设计模式循序渐进(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; 
virtualabstract;
    procedure Add(Component: TComponent); 
virtualabstract;
    function GetChild(index: Integer): TComponent; 
virtualabstract;
    procedure Operation; 
virtualabstract//某个操作抽象接口
    procedure Remove(Component: TComponent); virtualabstract;
  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); virtualabstract;
    procedure Add(Component: TComponentMan); 
virtualabstract;
    function GetChild(index: Integer): TComponentMan; 
virtualabstract;
    procedure Operation; 
virtualabstract//某个操作抽象接口
    procedure Remove(Component: TComponentMan); virtualabstract;
    function GetSalary: Integer; 
virtualabstract;
    procedure FreeChildren; 
virtualabstract;
    function GetName: 
stringvirtualabstract;
    function GetSalaries: Integer; 
virtualabstract;
    procedure SetItems(items: TStrings; level: Integer); 
virtualabstract;
  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: 
stringoverride;
    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: 
stringoverride;
    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.



 

posted @ 2008-06-06 13:36  treemon  阅读(559)  评论(0)    收藏  举报