《GOF设计模式》—适配器(ADAPTER)—Delphi源码示例:可插入的Adapter(使用抽象操作)

示例:可插入的Adapter(使用抽象操作)

说明:

当其他的类(如A)使用一个类(如C)时,如果所需的假定条件越少,这个类(如C)就更具可复用性。如果将接口匹配构建为一个类(如B),就不需要假定对其他的类可见的是一个相同的接口(如C接口)。也就是说,接口匹配使得我们可以将自己的类(如C)加入到一些现有的系统中去,而这些系统对这个类(如C)的接口可能会有所不同。

A  = C

A  = B  = C

实现:

考虑TreeDisplay窗口组件,它可以图形化显示树状结构。如果这是一个具有特殊用途的窗口组件,仅在一个应用中使用,我们可能要求它所显示的对象有一个特殊的接口,即它们都是抽象类Tree的子类。如果我们希望使TreeDisplay有具有良好的复用性的话(比如说,我们希望将它作为可用窗口组件工具箱的一部分),那么这种要求将是不合理的。应用程序将自己定义树结构类,而不应一定要使用我们的抽象类Tree。不同的树结构会有不同的接口。

 

例如,在一个目录层次结构中,可以通过GetSubdirectories操作进行访问子目录,然而在一个继承式层次结构中,相应的操作可能被称为GetSubclasses。尽管这两种层次结构使用的接口不同,一个可复用的TreeDisplay窗口组件必须能显示所有这两种结构。也就是说,TreeDisplay应具有接口适配的功能。

 

有许多方法可以实现可插入的适配器。例如,TreeDisplay窗口组件可以自动的布置和显示层次式结构,对于它有三种实现方法:使用抽象操作、使用代理对象和参数化的适配器。

 

首先(这也是所有这三种实现都要做的)是为Adaptee找到一个“窄”接口,即可用于适配的最小操作集。因为包含较少操作的窄接口相对包含较多操作的宽接口比较容易进行匹配。对于TreeDisplay而言,被匹配的对象可以是任何一个层次式结构。因此最小接口集合仅包含两个操作:一个操作定义如何在层次结构中表示一个节点,另一个操作返回该节点的子节点。

 

a)、使用抽象操作

TreeDisplay类中定义窄Adaptee接口相应的抽象操作。这样就由子类来实现这些抽象操作并匹配具体的树结构的对象。例如,DirectoryTreeDisplay子类将通过访问目录结构实现这些操作,如下图所示。

DirectoryTreeDisplay对这个窄接口加以特化,使得它的DirectoryBrowser客户可以用它来显示目录结构。

 

代码:

 

unit uTreeDisplay;

 

interface

 

uses

    Classes;

 

type

    PNodes = ^TNodes;

 

    TNode = record

        Text: string;

        Child: PNodes;

    end;

    TNodes = array of TNode;

 

    TFileDirs = array of string;

 

    TFileSystemEntity = class;

 

    TTreeDisplay = class

    private

        FList: TStringList;

        procedure AddGraphiNode(const n: string);

    protected

        procedure GetChildren(var n: TNode); virtual; abstract;

        function CreateGraphiNode(n: TNode): string; virtual; abstract;

    public

        constructor Create;

        destructor Destroy; override;

        //---

        function Display: string;

        procedure BuildTree(n: TNode);

    end;

    TDirectoryTreeDisplay = class(TTreeDisplay)

    private

        FEntity: TFileSystemEntity;

    protected

        function CreateGraphiNode(n: TNode): string; override;

        procedure GetChildren(var n: TNode); override;

    public

        constructor Create(AEntity: TFileSystemEntity);

    end;

    TFileSystemEntity = class

        function GetSubclasses(const ADir: string): TFileDirs;

    end;

 

implementation

 

constructor TTreeDisplay.Create;

begin

    FList := TStringList.Create;

end;

 

destructor TTreeDisplay.Destroy;

begin

    FList.Free;

    //---

    inherited;

end;

 

procedure TTreeDisplay.BuildTree(n: TNode);

var

    i: integer;

begin

    self.GetChildren(n);

    if n.Child <> nil then

    begin

        for i := low(n.Child^) to high(n.Child^) do

        begin

            AddGraphiNode(CreateGraphiNode(n.Child^[i]));

            BuildTree(n.Child^[i]);

        end;

        //---

        Dispose(n.Child);

        n.Child := nil;

    end;

end;

 

procedure TTreeDisplay.AddGraphiNode(const n: string);

begin

    FList.Add(n);

end;

 

function TTreeDisplay.Display: string;

begin

    result := FList.Text;

end;

 

constructor TDirectoryTreeDisplay.Create(AEntity: TFileSystemEntity);

begin

    inherited Create;

    //---

    FEntity := AEntity;

end;

 

function TDirectoryTreeDisplay.CreateGraphiNode(n: TNode): string;

begin

    Result := n.Text;

end;

 

procedure TDirectoryTreeDisplay.GetChildren(var n: TNode);

var

    ADirs: TFileDirs;

    i: integer;

begin

    if n.Child <> nil then

    begin

        Dispose(n.Child);

        n.Child := nil;

    end;

    //---

    ADirs := FEntity.GetSubclasses(n.Text);

    if length(ADirs) > 0 then

    begin

        new(n.Child);

        //---

        setlength(n.Child^,length(ADirs));

        for i := low(n.Child^) to high(n.Child^) do

            n.Child^[i].Text := ADirs[i];

    end;

end;

 

function TFileSystemEntity.GetSubclasses(const ADir: string): TFileDirs;

begin

    if ADir = 'a' then

    begin

        SetLength(Result,2);

        //---

        Result[0] := '123';

        Result[1] := '456';

    end

    else

        SetLength(Result,0);

end;

 

end.

 

procedure TForm1.Button1Click(Sender: TObject);

var

    AEntity: TFileSystemEntity;

    ATree:TTreeDisplay;

    n: TNode;

begin

    AEntity:= TFileSystemEntity.Create;

    ATree := TDirectoryTreeDisplay.Create(AEntity);

    try

        n.Text := 'a';

        n.Child := nil;

        //---

        ATree.BuildTree(n);

        self.Memo1.Text := ATree.Display;

    finally

        ATree.Free;

        AEntity.Free;

    end;

end;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值