示例:设备
说明:
计算机和立体声组合音响这样的设备经常被组装成“部分-整体层次结构”或者是“容器层次结构”。例如,机柜包括底盘、总线,底盘可包含驱动装置和平面板,总线含有多个插件等。这种结构可以很自然地用Composite模式进行模拟。
Equipment类为在“部分-整体层次结构”中的所有设备定义了一个接口。
Equipment声明一些操作返回一个设备的属性,例如它的能量消耗和价格。子类为指定的设备实现这些操作,Equipment还声明了一个CreateIterator操作,该操作为访问它的零件返回一个Iterator。这个操作的缺省实现返回一个NullIterator,它在空集上叠代。
Equipment的子类包括表示磁盘驱动器、集成电路和开关的Leaf类。CompositeEquipment是包含其他设备的基类,它也是Equipment的子类。
CompositeEquipment为访问和管理子设备定义了一些操作。操作Add和Remove从存储在FEquipments成员变量中的设备列表中插入并删除设备。操作CreateIterator返回一个迭代器(ListIterator的一个实例)遍历这个列表。NetPrice的缺省实现使用CreateIterator来累加子设备的实际价格。
现在我们将计算机的底盘表示为CompositeEquipment的子类Chassis。Chassis从CompositeEquipment继承了与子类有关的那些操作。
我们可用相似的方式定义其他设备容器,如Cabinet和Bus。这样我们就得到了组装一台(非常简单)个人计算机所需的所有设备。
代码:
unit uIterator;
interface
uses classes;
type
{迭代器}
TIterator = class
public
procedure First; virtual; abstract;
procedure Next; virtual; abstract;
function IsDone: Boolean; virtual; abstract;
function CurrentItem(): TObject; virtual; abstract;
end;
TListIterator = class(TIterator)
private
FList: TList;
FIndex: Integer;
public
constructor Create(const AList: TList);
//---
procedure First; override;
procedure Next; override;
function IsDone: Boolean; override;
function CurrentItem(): TObject; override;
end;
implementation
constructor TListIterator.Create(const AList: TList);
begin
inherited Create;
//---
FList := AList;
FIndex := 0;
end;
procedure TListIterator.First();
begin
FIndex := 0;
end;
procedure TListIterator.Next();
begin
FIndex := FIndex + 1;
end;
function TListIterator.IsDone: Boolean;
begin
Result := FIndex >= FList.Count;
end;
function TListIterator.CurrentItem(): TObject;
begin
Result := FList[FIndex];
end;
end.
unit uEquipment;
interface
uses
SysUtils,Dialogs,Contnrs,uIterator;
type
{设备接口}
TEquipment = class
private
FName: String;
public
constructor Create(const AName: string);
//---
{用电量}
function Power(): Integer; virtual; abstract;
{设备价格}
function NetPrice(): Currency; virtual; abstract;
{设备折扣价}
function DiscountPrice(): Currency; virtual; abstract;
//---
procedure Add(const AEquipment: TEquipment); virtual;
procedure Remove(const AEquipment: TEquipment); virtual;
function CreateIterator(): TIterator; virtual;
//---
property Name: String read FName write FName;
end;
{组合设备}
TCompositeEquipment = class(TEquipment)
private
FEquipments: TObjectList;
public
constructor Create(const AName: string);
destructor Destroy; override;
//---
function Power(): Integer; override;
function NetPrice(): Currency; override;
function DiscountPrice(): Currency; override;
//---
procedure Add(const AEquipment: TEquipment);override;
procedure Remove(const AEquipment: TEquipment);override;
function CreateIterator: TIterator;override;
end;
{机柜}
TCabinet = class(TCompositeEquipment)
public
function Power(): Integer; override;
function NetPrice(): Currency; override;
function DiscountPrice(): Currency; override;
end;
{底盘}
TChassis = class(TCompositeEquipment)
public
function Power(): Integer; override;
function NetPrice(): Currency; override;
function DiscountPrice(): Currency; override;
end;
{总线}
TBus = class(TCompositeEquipment)
public
function Power(): Integer; override;
function NetPrice(): Currency; override;
function DiscountPrice(): Currency; override;
end;
{软驱}
TFloppyDisk = class(TEquipment)
public
function Power(): Integer; override;
function NetPrice(): Currency; override;
function DiscountPrice(): Currency; override;
end;
{插件}
TCard = class(TEquipment)
public
function Power(): Integer; override;
function NetPrice(): Currency; override;
function DiscountPrice(): Currency; override;
end;
implementation
constructor TEquipment.Create(const AName: string);
begin
FName := AName;
end;
procedure TEquipment.Add(const AEquipment: TEquipment);
begin
raise Exception.Create('不支持该方法');
end;
procedure TEquipment.Remove(const AEquipment: TEquipment);
begin
raise Exception.Create('不支持该方法');
end;
function TEquipment.CreateIterator(): TIterator;
begin
Result := nil;
end;
function TFloppyDisk.Power(): Integer;
begin
Result := 1;
end;
function TFloppyDisk.NetPrice(): Currency;
begin
Result := 1;
end;
function TFloppyDisk.DiscountPrice(): Currency;
begin
Result := 1;
end;
constructor TCompositeEquipment.Create(const AName: string);
begin
inherited;
//---
FEquipments := TObjectList.Create;
end;
destructor TCompositeEquipment.Destroy;
begin
FEquipments.Free;
//---
inherited;
end;
function TCompositeEquipment.Power(): Integer;
var
AIterator: TIterator;
begin
AIterator := self.CreateIterator;
try
result := 0;
with AIterator do
begin
First;
while not IsDone do
begin
result := result + TEquipment(CurrentItem).Power;
Next;
end;
end;
finally
AIterator.free;
end;
end;
function TCompositeEquipment.NetPrice(): Currency;
var
AIterator: TIterator;
begin
AIterator := self.CreateIterator;
try
result := 0;
with AIterator do
begin
First;
while not IsDone do
begin
result := result + TEquipment(CurrentItem).NetPrice;
Next;
end;
end;
finally
AIterator.free;
end;
end;
function TCompositeEquipment.DiscountPrice(): Currency;
var
AIterator: TIterator;
begin
AIterator := self.CreateIterator;
try
result := 0;
with AIterator do
begin
First;
while not IsDone do
begin
result := result + TEquipment(CurrentItem).DiscountPrice;
Next;
end;
end;
finally
AIterator.free;
end;
end;
procedure TCompositeEquipment.Add(const AEquipment: TEquipment);
begin
FEquipments.Add(AEquipment);
end;
procedure TCompositeEquipment.Remove(const AEquipment: TEquipment);
begin
FEquipments.Remove(AEquipment);
end;
function TCompositeEquipment.CreateIterator:TIterator;
begin
result := TListIterator.Create(FEquipments);
end;
function TChassis.Power(): Integer; //Watt
begin
Result := inherited Power + 1;
end;
function TChassis.NetPrice(): Currency;
begin
Result := inherited NetPrice + 1;
end;
function TChassis.DiscountPrice(): Currency;
begin
Result := inherited DiscountPrice + 1;
end;
function TCabinet.Power(): Integer;
begin
Result := inherited Power + 1;
end;
function TCabinet.NetPrice(): Currency;
begin
Result := inherited NetPrice + 1;
end;
function TCabinet.DiscountPrice(): Currency;
begin
Result := inherited DiscountPrice + 1;
end;
function TBus.Power(): Integer;
begin
Result := inherited Power + 1;
end;
function TBus.NetPrice(): Currency;
begin
Result := inherited NetPrice + 1;
end;
function TBus.DiscountPrice(): Currency;
begin
Result := inherited DiscountPrice + 1;
end;
function TCard.Power(): Integer;
begin
Result := 1;
end;
function TCard.NetPrice(): Currency;
begin
Result := 1;
end;
function TCard.DiscountPrice(): Currency;
begin
Result := 1;
end;
end.
procedure TForm1.Button1Click(Sender: TObject);
var
Cabinet: TCabinet;
Chassis: TChassis;
Bus: TBus;
begin
Cabinet := TCabinet.Create('PC Cabinet');
try
Chassis := TChassis.Create('PC Chassis');
Cabinet.Add(Chassis);
//---
Bus := TBus.Create('MCA Bus');
Bus.Add(TCard.Create('16Mbs Token Ring'));
Chassis.Add(Bus);
//---
Chassis.Add(TFloppyDisk.Create('3.5in Floppy'));
//---
ShowMessage(CurrToStr(Cabinet.NetPrice));
finally
Cabinet.Free;
end;
end;