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

本文主要是介绍《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(使用抽象操作)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1142331

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

C#使用Spire.Doc for .NET实现HTML转Word的高效方案

《C#使用Spire.Docfor.NET实现HTML转Word的高效方案》在Web开发中,HTML内容的生成与处理是高频需求,然而,当用户需要将HTML页面或动态生成的HTML字符串转换为Wor... 目录引言一、html转Word的典型场景与挑战二、用 Spire.Doc 实现 HTML 转 Word1

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Java实现在Word文档中添加文本水印和图片水印的操作指南

《Java实现在Word文档中添加文本水印和图片水印的操作指南》在当今数字时代,文档的自动化处理与安全防护变得尤为重要,无论是为了保护版权、推广品牌,还是为了在文档中加入特定的标识,为Word文档添加... 目录引言Spire.Doc for Java:高效Word文档处理的利器代码实战:使用Java为Wo

Java中的抽象类与abstract 关键字使用详解

《Java中的抽象类与abstract关键字使用详解》:本文主要介绍Java中的抽象类与abstract关键字使用详解,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、抽象类的概念二、使用 abstract2.1 修饰类 => 抽象类2.2 修饰方法 => 抽象方法,没有

MyBatis ParameterHandler的具体使用

《MyBatisParameterHandler的具体使用》本文主要介绍了MyBatisParameterHandler的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录一、概述二、源码1 关键属性2.setParameters3.TypeHandler1.TypeHa

Spring 中的切面与事务结合使用完整示例

《Spring中的切面与事务结合使用完整示例》本文给大家介绍Spring中的切面与事务结合使用完整示例,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录 一、前置知识:Spring AOP 与 事务的关系 事务本质上就是一个“切面”二、核心组件三、完

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同