《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中Arrays类和Collections类常用方法示例详解

《Java中Arrays类和Collections类常用方法示例详解》本文总结了Java中Arrays和Collections类的常用方法,涵盖数组填充、排序、搜索、复制、列表转换等操作,帮助开发者高... 目录Arrays.fill()相关用法Arrays.toString()Arrays.sort()A

如何使用Lombok进行spring 注入

《如何使用Lombok进行spring注入》本文介绍如何用Lombok简化Spring注入,推荐优先使用setter注入,通过注解自动生成getter/setter及构造器,减少冗余代码,提升开发效... Lombok为了开发环境简化代码,好处不用多说。spring 注入方式为2种,构造器注入和setter

MySQL中比较运算符的具体使用

《MySQL中比较运算符的具体使用》本文介绍了SQL中常用的符号类型和非符号类型运算符,符号类型运算符包括等于(=)、安全等于(=)、不等于(/!=)、大小比较(,=,,=)等,感兴趣的可以了解一下... 目录符号类型运算符1. 等于运算符=2. 安全等于运算符<=>3. 不等于运算符<>或!=4. 小于运

使用zip4j实现Java中的ZIP文件加密压缩的操作方法

《使用zip4j实现Java中的ZIP文件加密压缩的操作方法》本文介绍如何通过Maven集成zip4j1.3.2库创建带密码保护的ZIP文件,涵盖依赖配置、代码示例及加密原理,确保数据安全性,感兴趣的... 目录1. zip4j库介绍和版本1.1 zip4j库概述1.2 zip4j的版本演变1.3 zip4

Python 字典 (Dictionary)使用详解

《Python字典(Dictionary)使用详解》字典是python中最重要,最常用的数据结构之一,它提供了高效的键值对存储和查找能力,:本文主要介绍Python字典(Dictionary)... 目录字典1.基本特性2.创建字典3.访问元素4.修改字典5.删除元素6.字典遍历7.字典的高级特性默认字典

MySQL进行数据库审计的详细步骤和示例代码

《MySQL进行数据库审计的详细步骤和示例代码》数据库审计通过触发器、内置功能及第三方工具记录和监控数据库活动,确保安全、完整与合规,Java代码实现自动化日志记录,整合分析系统提升监控效率,本文给大... 目录一、数据库审计的基本概念二、使用触发器进行数据库审计1. 创建审计表2. 创建触发器三、Java

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

MySQL 主从复制部署及验证(示例详解)

《MySQL主从复制部署及验证(示例详解)》本文介绍MySQL主从复制部署步骤及学校管理数据库创建脚本,包含表结构设计、示例数据插入和查询语句,用于验证主从同步功能,感兴趣的朋友一起看看吧... 目录mysql 主从复制部署指南部署步骤1.环境准备2. 主服务器配置3. 创建复制用户4. 获取主服务器状态5

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

Ubuntu 24.04启用root图形登录的操作流程

《Ubuntu24.04启用root图形登录的操作流程》Ubuntu默认禁用root账户的图形与SSH登录,这是为了安全,但在某些场景你可能需要直接用root登录GNOME桌面,本文以Ubuntu2... 目录一、前言二、准备工作三、设置 root 密码四、启用图形界面 root 登录1. 修改 GDM 配