设计模式循序渐进(3)合成模式 Composite
模式解说:
合成模式把多个对象合成为树状结构用以表现“个别-整体”的层次结构。合成模式让客户端能够用统一的方法处理单个对象和合成对象。
模式结构:
TComponent:抽象部件;声明合成对象的接口;实现所有类通用接口的缺省行为;
TLeaf:叶部件;表示合成中的叶节点对象;叶对象无字节点;
TComposite:合成部件;表示合成中的枝节点对象;拥有子部件(子节点);
TClient:客户;通过TComponent接口操作合成部件的对象。
UML结构图:

Delphi代码实现:模式实现
// Added by zhangsk 2008-6-4 18:29:56 结构型模式编程-合成模式
unit uCompsite;
interface
uses
SysUtils, Contnrs;
type
TClient = class(TObject)
end;
TComponent = class(TObject)
public
constructor Create; virtual; abstract;
procedure Add(Component: TComponent); virtual; abstract;
function GetChild(index: Integer): TComponent; virtual; abstract;
procedure Operation; virtual; abstract; //某个操作抽象接口
procedure Remove(Component: TComponent); virtual; abstract;
end;
TComposite = class(TComponent)
private
children: TObjectList; //子部件对象列表
public
constructor Create; override;
procedure Add(Component: TComponent); override;
function GetChild(index: Integer): TComponent; override;
procedure Operation; override; //枝节点的具体操作
procedure Remove(Component: TComponent); override;
end;
TLeaf = class(TComponent)
public
procedure Add(Component: TComponent); override;
function GetChild(index: Integer): TComponent; override;
procedure Operation; override; //叶节点的具体操作
procedure Remove(Component: TComponent); override;
end;
implementation
{ TComposite }
procedure TComposite.Add(Component: TComponent);
begin
// inherited;
//管理子部件对象:新增
children.Add(Component);
end;
constructor TComposite.Create;
begin
// inherited;
//创建子部件对象列表
children := TObjectList.Create;
end;
function TComposite.GetChild(index: Integer): TComponent;
begin
//管理子部件对象:检索
Result := TComponent(children.Items[index]);
end;
procedure TComposite.Operation;
begin
// inherited;
//枝节点的具体操作实现
end;
procedure TComposite.Remove(Component: TComponent);
begin
// inherited;
//管理子部件对象:删除
children.Remove(Component);
end;
{ TLeaf }
procedure TLeaf.Add(Component: TComponent);
begin
// inherited;
raise Exception.CreateFmt('%s 类实例是叶节点对象,无法为其增加字节点对象!',
[ClassName]);
end;
function TLeaf.GetChild(index: Integer): TComponent;
begin
Result := nil;
end;
procedure TLeaf.Operation;
begin
// inherited;
//叶节点的具体操作实现
end;
procedure TLeaf.Remove(Component: TComponent);
begin
// inherited;
raise Exception.CreateFmt('%s 类实例是叶节点对象,无法为其删除字节点对象!',
[ClassName]);
end;
end.
通过合成模式处理部门员工工资问题:
uCompsiteOrg.pas
unit uCompsiteOrg;

interface
uses
SysUtils, Classes, Contnrs;
type
TComponentMan = class(TObject)
public
constructor Create(name: string; salary: Integer); virtual; abstract;
procedure Add(Component: TComponentMan); virtual; abstract;
function GetChild(index: Integer): TComponentMan; virtual; abstract;
procedure Operation; virtual; abstract; //某个操作抽象接口
procedure Remove(Component: TComponentMan); virtual; abstract;
function GetSalary: Integer; virtual; abstract;
procedure FreeChildren; virtual; abstract;
function GetName: string; virtual; abstract;
function GetSalaries: Integer; virtual; abstract;
procedure SetItems(items: TStrings; level: Integer); virtual; abstract;
end;
TCompositeManage = class(TComponentMan)
private
children: TObjectList; //子部件对象列表
FName: string;
Fsalary: Integer;
function GetSalary: Integer; override;
public
constructor Create(name: string; salary: Integer); override;
procedure Add(Component: TComponentMan); override;
function GetChild(index: Integer): TComponentMan; override;
procedure Operation; override; //枝节点的具体操作
procedure Remove(Component: TComponentMan); override;
procedure FreeChildren; override;
function GetName: string; override;
function GetSalaries: Integer; override;
procedure SetItems(items: TStrings; level: Integer); override;
end;
TLeafEmployee = class(TComponentMan)
private
FName: string;
Fsalary: Integer;
function GetSalary: Integer; override;
public
constructor Create(name: string; salary: Integer);
procedure Add(Component: TComponentMan); override;
function GetChild(index: Integer): TComponentMan; override;
procedure Operation; override; //叶节点的具体操作
procedure Remove(Component: TComponentMan); override;
procedure FreeChildren; override;
function GetName: string; override;
function GetSalaries: Integer; override;
procedure SetItems(items: TStrings; level: Integer); override;
end;
implementation
uses
Forms;
const
const_line = '---';
{ TComposite }
procedure TCompositeManage.Add(Component: TComponentMan);
begin
// inherited;
//管理子部件对象:新增
children.Add(Component);
end;
constructor TCompositeManage.Create(name: string; salary: Integer);
begin
// inherited;
//创建子部件对象列表
children := TObjectList.Create;
FName := name;
Fsalary := salary;
end;
procedure TCompositeManage.FreeChildren;
var
i: Integer;
s: string;
obj: TComponentMan;
begin
if Self <> nil then
begin
for i := children.Count - 1 downto 0 do
begin
obj := TComponentMan(children.Items[i]);
obj.FreeChildren;
end;
// Added by zhangsk 2008-6-4 19:19:18 演示销毁对象
s := '销毁对象 TComposite ' + GetName;
Application.MessageBox(PChar(s), '提示', 0);
FreeAndNil(Self);
end;
end;
function TCompositeManage.GetChild(index: Integer): TComponentMan;
begin
//管理子部件对象:检索
Result := TComponentMan(children.Items[index]);
end;
function TCompositeManage.GetName: string;
begin
Result := FName;
end;
function TCompositeManage.GetSalaries: Integer;
var
i, sum, n: Integer;
nam: string;
begin
sum := GetSalary;
for i := 0 to children.Count - 1 do
begin
//调试中观察nam的值就可以了解合成模式是如何递归遍历对象的
nam := TComponentMan(children.Items[i]).GetName;
n := TComponentMan(children.Items[i]).GetSalaries;
sum := sum + n;
end;
Result := sum;
end;
function TCompositeManage.GetSalary: Integer;
begin
Result := Fsalary;
end;
procedure TCompositeManage.Operation;
begin
// inherited;
//枝节点的具体操作实现
end;
procedure TCompositeManage.Remove(Component: TComponentMan);
begin
// inherited;
//管理子部件对象:删除
children.Remove(Component);
end;
{ TLeaf }
procedure TLeafEmployee.Add(Component: TComponentMan);
begin
// inherited;
raise Exception.CreateFmt('%s 类实例是叶节点对象,无法为其增加字节点对象!',
[ClassName]);
end;
constructor TLeafEmployee.Create(name: string; salary: Integer);
begin
FName := name;
Fsalary := salary;
end;
procedure TLeafEmployee.FreeChildren;
var
s: String;
begin
if Self <> nil then
begin
// Added by zhangsk 2008-6-4 19:04:34 演示销毁对象
s := '销毁对象 ' + GetName;
Application.MessageBox(PChar(s), '提示', 0);
FreeAndNil(Self);
end; 
end;
function TLeafEmployee.GetChild(index: Integer): TComponentMan;
begin
Result := nil;
end;
function TLeafEmployee.GetName: string;
begin
Result := FName;
end;
function TLeafEmployee.GetSalaries: Integer;
begin
Result := Fsalary;
end;
function TLeafEmployee.GetSalary: Integer;
begin
Result := Fsalary;
end;
procedure TLeafEmployee.Operation;
begin
// inherited;
//叶节点的具体操作实现
end;
procedure TLeafEmployee.Remove(Component: TComponentMan);
begin
// inherited;
raise Exception.CreateFmt('%s 类实例是叶节点对象,无法为其删除字节点对象!',
[ClassName]);
end;
procedure TLeafEmployee.SetItems(items: TStrings; level: Integer);
var
s: string;
i: Integer;
begin
for i := 1 to level do s := s + const_line;
s := s + FName;
items.AddObject(s, Self);
end;
procedure TCompositeManage.SetItems(items: TStrings; level: Integer);
var
s: string;
i: Integer;
curItem: TStringList;
begin
for i := 1 to level do s := s + const_line;
s := s + FName;
items.AddObject(s, Self);
for i := 0 to children.Count - 1 do
begin
TComponentMan(children.Items[i]).SetItems(items, level + 1);
end;
end;
end.
Unit1.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,
uCompsiteOrg;
type
TForm1 = class(TForm)
mmo1: TMemo;
btn1: TButton;
ListBox1: TListBox;
procedure btn1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure ListBox1Click(Sender: TObject);
procedure mmo1Click(Sender: TObject);
private
{ Private declarations }
Root: TComponentMan;
procedure DataIni;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TForm1 }
procedure TForm1.DataIni;
var
M_MKT,
M_PRD,
D_MKT1,
D_MKT2: TCompositeManage;
DisplayItems: TStrings;
Employee: TLeafEmployee;
begin
Root := TCompositeManage.Create('总经理', 10000);
Root.Add(TLeafEmployee.Create('总经理秘书', 2000));
M_MKT := TCompositeManage.Create('市场部经理', 5000);
D_MKT1 := TCompositeManage.Create('销售主管', 3000);
D_MKT1.Add(TLeafEmployee.Create('高级推销员', 2000));
D_MKT1.Add(TLeafEmployee.Create('见习推销员', 1000));
D_MKT2 := TCompositeManage.Create('市场主管', 3000);
D_MKT2.Add(TLeafEmployee.Create('市场调研员', 2000));
M_PRD := TCompositeManage.Create('制造部经理', 5000);
M_PRD.Add(TLeafEmployee.Create('制造部雇员A', 2000));
M_PRD.Add(TLeafEmployee.Create('制造部雇员B', 2000));
Root.Add(M_MKT);
M_MKT.Add(D_MKT1);
M_MKT.Add(D_MKT2);
Root.Add(M_PRD);
//叶节点不能加入子对象,下面语句用于测试异常。
// Employee := TLeafEmployee.Create('雇员', 800);
// Employee.Add(TLeafEmployee.Create('其它雇员', 600));
DisplayItems := TStringList.Create;
Root.SetItems(DisplayItems, 0);
ListBox1.Items := DisplayItems;
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
Close;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
DataIni;
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Root.FreeChildren;
end;
procedure TForm1.ListBox1Click(Sender: TObject);
var
s: string;
person: TComponentMan;
begin
person := TComponentMan(ListBox1.Items.Objects[ListBox1.ItemIndex]);
s := person.GetName;
mmo1.Lines.Add(s);
s := IntToStr(person.GetSalaries);
if person.GetChild(0) <> nil then
mmo1.Lines.Add(Format('部门工资:%s', [s]));
s := IntToStr(person.GetSalary);
mmo1.Lines.Add(Format('个人工资:%s', [s]));
mmo1.Lines.Add('===============================');
end;
procedure TForm1.mmo1Click(Sender: TObject);
begin
mmo1.Clear;
end;
end.




浙公网安备 33010602011771号