示例:最大化Component接口
说明:
Composite模式的目的之一是使得用户不知道他们正在使用的具体的Leaf和Composite类。为了达到这一目的,Composite类应为Leaf和Composite类尽可能多定义一些公共操作。Composite类通常为这些操作提供缺省的实现,而Leaf和Composite子类可以对它们进行重定义。
然而,这个目标有时可能会与类层次结构设计原则相冲突,该原则规定:一个类只能定义那些对它的子类有意义的操作。有许多Component所支持的操作对Leaf类似乎没有什么意义,那么Component怎样为它们提供一个缺省的操作呢?
有时一点创造性可以使得一个看起来仅对Composite才有意义的操作,将它移入Component类中,就会对所有的Component都适用。例如,访问子节点的接口是Composite类的一个基本组成部分,但对Leaf类来说并不必要。但是如果我们把一个Leaf看成一个没有子节点的Component,就可以为在Component类中定义一个缺省的操作,用于对子节点进行访问,这个缺省的操作不返回任何一个子节点。Leaf类可以使用缺省的实现,而Composite类则会重新实现这个操作以返回它们的子类。
代码:
unit uComposite2;
interface
uses
Dialogs;
type
TComponent = class
protected
function GetCount: integer; virtual;
function GetChilds(Index: integer): TComponent; virtual;
public
procedure Operation; virtual; abstract;
procedure Add(AComponent: TComponent); virtual;
procedure Remove(AComponent: TComponent); virtual;
//---
property Count: integer read GetCount;
property Childs[Index: integer]: TComponent read GetChilds;
end;
TLeaf = class(TComponent)
public
procedure Operation; override;
end;
TComposite = class(TComponent)
private
FChilds: array of TComponent;
protected
function GetChilds(Index: integer): TComponent; override;
function GetCount: integer; override;
public
constructor Create;
destructor Destroy; override;
//---
procedure Operation; override;
procedure Add(AComponent: TComponent); override;
procedure Remove(AComponent: TComponent); override;
end;
implementation
procedure TComponent.Add(AComponent: TComponent);
begin
end;
procedure TComponent.Remove(AComponent: TComponent);
begin
end;
procedure TLeaf.Operation;
begin
ShowMessage('Leaf');
end;
constructor TComposite.Create;
begin
SetLength(FChilds,0);
end;
destructor TComposite.Destroy;
//---
procedure _Clear;
var
i: integer;
begin
for i := low(FChilds) to high(FChilds) do
FChilds[i].Free;
SetLength(FChilds,0);
end;
begin
_Clear;
//---
inherited;
end;
procedure TComposite.Add(AComponent: TComponent);
var
ACount: integer;
begin
ACount := Length(FChilds);
SetLength(FChilds,ACount + 1);
FChilds[ACount] := AComponent;
end;
procedure TComposite.Remove(AComponent: TComponent);
//---
function _IndexOf: integer;
var
i: integer;
begin
for i := low(FChilds) to high(FChilds) do
begin
if FChilds[i] = AComponent then
begin
Result := i;
exit;
end;
end;
//---
Result := -1;
end;
//---
procedure _Delete(AIndex: integer);
var
ACount: integer;
begin
ACount := Length(FChilds);
if AIndex < ACount - 1 then
Move(FChilds[AIndex + 1],FChilds[AIndex],(ACount - AIndex - 1) * 4);
SetLength(FChilds,ACount - 1);
end;
var
AIndex: integer;
begin
AIndex := _IndexOf;
if AIndex >= 0 then
_Delete(AIndex);
end;
function TComposite.GetChilds(Index: integer): TComponent;
begin
Result := FChilds[Index];
end;
function TComposite.GetCount: integer;
begin
Result := Length(FChilds);
end;
procedure TComposite.Operation;
begin
ShowMessage('Composite');
end;
function TComponent.GetChilds(Index: integer): TComponent;
begin
Result := nil;
end;
function TComponent.GetCount: integer;
begin
Result := 0;
end;
end.
procedure TForm1.Button1Click(Sender: TObject);
//---
function _GetComposite: TComponent;
begin
Result := TComposite.Create;
with Result do
begin
Add(TLeaf.Create);
Add(TLeaf.Create);
Add(TComposite.Create);
end;
end;
//---
function _GetComposite1: TComponent;
begin
Result := TLeaf.Create;
end;
//---
procedure _ShowComposite(AComponent: TComponent);
var
i: integer;
begin
AComponent.Operation;
for i := 0 to AComponent.Count - 1 do
AComponent.Childs[i].Operation;
end;
var
AComposite: TComponent;
begin
AComposite := _GetComposite;
try
_ShowComposite(AComposite);
finally
AComposite.Free;
end;
end;