本文主要是介绍《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;
这篇关于《GOF设计模式》—适配器(ADAPTER)—Delphi源码示例:可插入的Adapter(使用抽象操作)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!