GOF是这样说明它的意图:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
简而言之,就是将各对象间错综复杂的交互行为,变成多对一的交互。这很很容易让人想起现实生活中的中介服务单位(房产中介、劳务中介等)。
GOF书的第一章是很值得在学习模式前阅读的,里面对设计模式有总结,有比较,告诉你何时使用,如何使用等等。每个模式的“意图”(讲解模式的作用),“适用性”(讲解在什幺情况下使用模式),“效果”(缺点和优点)是应该关注的重点。没必要将它们全都记录下来,几次思考和运用下来就深有体会了!
我对这个模式的应用,写了个小例子,類似GOF书的中一个简单的GUI,如下图:
有一些交互行为:在文本输入框输入字符时,会在列表框中自动匹配相应的字符串。根据选择列表框中的内容,会确定单选按钮的状态。
没采用mediator的Delphi代码如下:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
ListBox1: TListBox;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
Button1: TButton;
Button2: TButton;
procedure Edit1Change(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses comm;
{$R *.dfm}
procedure TForm1.Edit1Change(Sender: TObject);
Var
i: integer;
begin
for i:=0 to ListBox1.Items.Count-1 do
if pos(Edit1.Text,ListBox1.Items.Strings[i])<>0 then
begin
ListBox1.Selected[i]:=true;
abort;
end;
end;
procedure TForm1.ListBox1Click(Sender: TObject);
var
i: integer;
begin
for i:=0 to ListBox1.Items.Count-1 do
if listbox1.Selected[i] then
begin
edit1.Text:= Listbox1.Items.Strings[i];
RadioButton2.Enabled:= iif(pos('r',Listbox1.Items.Strings[i])<>0,true,false);
end;
end;
end.
采用mediator的Delphi代码如下:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TMediator = class
public
procedure doEditChanged();
procedure doListBoxChanged();
end;
TForm2 = class(TForm)
Edit1: TEdit;
ListBox1: TListBox;
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
Button1: TButton;
Button2: TButton;
procedure ListBox1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure Edit1Change(Sender: TObject);
private
{ Private declarations }
mediator : TMediator;
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
uses comm;
{$R *.dfm}
{ TForm2 }
procedure TForm2.FormCreate(Sender: TObject);
begin
mediator:= TMediator.Create();
end;
procedure TForm2.FormDestroy(Sender: TObject);
begin
FreeAndNil(mediator);
end;
procedure TForm2.Edit1Change(Sender: TObject);
begin
mediator.doEditChanged;
end;
procedure TForm2.ListBox1Click(Sender: TObject);
begin
mediator.doListBoxChanged;
end;
{ TMediator }
procedure TMediator.doEditChanged;
Var
i: integer;
begin
with form2 do
begin
for i:=0 to ListBox1.Items.Count-1 do
if pos(Edit1.Text,ListBox1.Items.Strings[i])<>0 then
begin
ListBox1.Selected[i]:=true;
abort;
end;
end;
end;
procedure TMediator.doListBoxChanged;
var
i: integer;
begin
with form2 do
begin
for i:=0 to ListBox1.Items.Count-1 do
if listbox1.Selected[i] then
begin
edit1.Text:= Listbox1.Items.Strings[i];
RadioButton2.Enabled:= iif(pos('r',Listbox1.Items.Strings[i])<>0,true,false);
end;
end;
end;
end.
你会发现这是一个很简单的例子,在原有的基础上加入了一个中介者mediator对象,将对象Edit1,ListBox1,RadioButton1, RadioButton2之间的交互全部封装了!一个对象与其它个对象的交互行为全交由它间接的执行。
这有什幺好处呢? 不错,form2及各对象更容易重用,Edit1等这些对象的行为变化,只需要生成mediator的子类即可。要是有众多对象的交互会让mediator变得很复杂,重用性会越来越小。这说明:Colleague对象(就是Edit1等)的重用是以牺牲mediator的重用为代价的!
作为系统学习的第二个模式是有原因的,因为它和facade模式有一些相似之处。这们都提供简化对象间交互的接口。但它们也是有区别的:Facade的协议是单向的,即Facade对象对子系统类提出请求,但反之则不行。相反,Mediator的协议是多向的。
刘艺在《Delphi模式编程》中举了个聊天室的例子,很不错!看懂一个模式是简单的,如何用好它要下点功夫。