《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

相关文章

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Java使用SLF4J记录不同级别日志的示例详解

《Java使用SLF4J记录不同级别日志的示例详解》SLF4J是一个简单的日志门面,它允许在运行时选择不同的日志实现,这篇文章主要为大家详细介绍了如何使用SLF4J记录不同级别日志,感兴趣的可以了解下... 目录一、SLF4J简介二、添加依赖三、配置Logback四、记录不同级别的日志五、总结一、SLF4J

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

如何使用Nginx配置将80端口重定向到443端口

《如何使用Nginx配置将80端口重定向到443端口》这篇文章主要为大家详细介绍了如何将Nginx配置为将HTTP(80端口)请求重定向到HTTPS(443端口),文中的示例代码讲解详细,有需要的小伙... 目录1. 创建或编辑Nginx配置文件2. 配置HTTP重定向到HTTPS3. 配置HTTPS服务器

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自