之前我们已经介绍完了创建型模式,它们分别为Factory Method,Abstract Factory,Singleton,Builder,Prototype。创建型模式是创建对象而不是直接实例化对象,这会使程序在判断给定情况下创建哪个对象时更为灵活。在C#中为new,在Pascal中为Create。
       接下来我们要介绍结构型模式,这类模式可以将一组对象组合成更大的结构。对于结构型模式(Structural Pattern)来说主要分为两种组合方式,分别为类模式和对象模式,其主要区别为类模式描述的是如何使用继承提供更有用的程序接口,而对象模式描述的是通过使用对象组合或将对象包含在其他对象里,将对象组合成更大的结构。
       下面我们来看看结构型的第一种模式适配器模式(Adapter Pattern)。
       适配器模式可以将类的接口转变成客户需要的其他接口。这样做的好处就是能很好的复用已有的代码,比如很多公司都生产数据库,如Oracle,IBM,Microsoft,它们的产品各有各的特点,原生的开发方法也有很大的区别,比如Oracle提供OCI接口,Sql Server提供自己专用的API。如果都使用数据库厂商的原生开发方法,那么在Sql Server开发的软件就很难移植到其他的数据库平台上去,这无疑会限制产品的应用范围。为此很多厂商就提供了各种标准的开发接口,比如最早的ODBC,BDE,到现在的ADO.NET等等,有了这种标准的数据库开发接口,我们在一个平台上开发的产品就很容易移植到其他平台上去。
    那么如何让数据库适应不同的标准API而无需大的改动呢,这就是通过适配器模式来实现了,微软最早的ODBC Driver和现在的ADO.NET就相当于一个适配器,可以让数据库适应不同的标准开发接口。这样原有的产品无需针对标准的API做任何改变,只要针对不同的开发API实现一个Dirver就可以了。
       适配器模式的实现原理很简单,就是通过实现了客户指定接口的类来响应客户的请求,然后在适配器内部将请求转发给原有的API接口对应的具有类似功能的方法,然后将处理的结果整理后返回给客户。
        适配器模式有类的适配器模式和对象的适配器模式两种。我们将分别讨论这两种Adapter模式。

类的Adapter模式的结构:

由图中可以看出,AdapteeXML类没有CreateFile方法,而客户期待这个方法。为了使客户能够使用AdapteeXML类,提供一个中间环节,即类Adapter类,Adapter类实现了ISerTarget接口,此接口中定义了CreateFile方法,并继承自AdapteeXML,Adapter类的CreateFile方法重新封装了AdapteeXMl的CreateXMLFile方法,实现了适配的目的。<?xml:namespace prefix = o />

因为Adapter与AdapteeXML是继承的关系,所以这决定了这个适配器模式是类的。

该适配器模式所涉及的角色包括:

目标(Target)角色:这是客户所期待的接口。因为C#不支持多继承,所以Target必须是接口,不可以是类,这里为ISerTarget。
源(Adaptee)角色:需要适配的类,这里为AdapteeXML。
适配器(Adapter)角色:把源接口转换成目标接口。这一角色必须是类。
以上例子主要是一个XML串行化实例(C#):

 1 using  System;
 2 using  System.IO;
 3 using  System.Xml.Serialization;
 4 using  System.Xml;
 5 namespace  AdapterClass
 6 {
 7    /**//// <summary>
 8    ///============== Program Description==============
 9    ///Name:AdapterClass.cs
10    ///Objective:AdapterClass 
11    ///Date:2006-05-04 
12    ///Written By coffee.liu
13    ///================================================
14    /// </summary>
15    class Class1
16    {
17        /**//// <summary>
18        /// 应用程序的主入口点。
19        /// </summary>
20        [STAThread]
21        static void Main(string[] args)
22        {
23            ISerTarget target=new Adapter();
24            target.CreateFile();
25            Console.WriteLine("xml file created");
26        }
27    }
28    [Serializable]
29    public class Person
30    {
31        public string Name;
32        public string Sex;
33        public DateTime Brith;
34        private int PersonID;
35        public Person()
36        {}
37        public void SetID(int ID)
38        {PersonID=ID;}
39    }
40
41    interface ISerTarget
42    {
43        void CreateFile();
44    }
45    class Adapter:AdapteeXML,ISerTarget
46    {
47        public Adapter():base()
48        {
49        }
50
51        public  void CreateFile()
52        {
53            this.FillData();
54            this.CreateXMLFile();
55      
56        }
57    
58    }
59    class AdapteeXML
60    {
61        FileStream aFile;
62        Person aPerson;
63        XmlSerializer aXML;
64        public AdapteeXML()
65        {
66            aXML=new XmlSerializer(typeof(Person));
67            aPerson=new Person();
68        }
69        public void FillData()
70        {
71            aPerson.Name="XML";
72            aPerson.Sex="男";
73            aPerson.Brith=DateTime.Now;
74            aPerson.SetID(1);
75        }
76        public void CreateXMLFile()
77        {
78            try
79            {
80                aFile=new FileStream("Person.xml",FileMode.Create);
81            }
82            catch(IOException e)
83            {
84                Console.WriteLine("some error happened!");
85                Console.WriteLine(e.ToString());
86                return;
87            }
88            aXML.Serialize(aFile,aPerson);
89            aFile.Close();
90        }
91    }
92}
93

当然用Pascal也可以实现同样的功能,我们看看如何将上面的XML文件读取出来,这里只给出功能性代码,具体扩展希望读者自己思考。
代码(Pascal):

 1 program AdapterClass;
 2    //==============  Program Description ==============
 3      // Name:AdapterClass.dpr
 4      // Objective:AdapterClass
 5      // Date: 2006 - 05 - 04
 6      // Written  By  coffee.liu
 7      //================================================
 8 {$APPTYPE CONSOLE}
 9
10 uses
11   SysUtils,msxmldom,XMLDoc, oxmldom, xmldom, XMLIntf,windows;
12   type ISerTarget = interface
13      function  ReadFile():string;
14      end ;
15   type AdapteeXML = class
16       xmlDocument1 :IXMLDocument;
17       node:IXMLNode;
18        count : Integer ;
19       constructor  Create ;
20        function  ReadFromXml(Node:IXMLNode; Count : integer ):string;
21      end ;
22   type Adapter =  class(AdapteeXML,ISerTarget)
23     private
24      FRefCount :  Integer ;
25       public  
26      function  QueryInterface(const IID:TGUID;out Obj):HRESULT;stdcall;
27      function  _AddRef: Integer ;stdcall;
28      function  _Release: Integer ;stdcall; // 这里让接口引用计数器来控制对象生存周期了,这里我为了少写代码没有人为的去控制对象的生存周期,当然读者也可以通过继承TInterfacedObject对象来完成IInterface。     function  ReadFile():string;
29     constructor  Create ;
30     end ;
31
32
33 { AdapteeXML }
34
35 constructor AdapteeXML. Create ;
36 begin
37     xmlDocument1 : = TXMLDocument. Create (nil);
38     xmlDocument1.LoadFromFile( ' D:\coffee.liu\Delphi7\Projects\Person.xml ' ); // 上面C#例子创建出的XML文件
39     XMLDocument1.Active: = true;
40      count : = xmlDocument1.ChildNodes. Count ;
41     node: =  xmlDocument1.DocumentElement;
42 end ;
43
44 function  AdapteeXML.ReadFromXml(Node:IXMLNode; Count : integer ):string;
45 var
46 i: integer ;
47 begin
48              for  i : =   1   to   Count - 1  do  begin
49                  if (node <> nil)  then
50                  result: = Node.ChildNodes [ 'Name' ] . Text + ' ; ' + Node.ChildNodes [ 'Sex' ] . Text + ' ; ' + Node.ChildNodes [ 'Brith' ] . Text ; 
51
52              end ;
53             xmlDocument1.Active: = false;
54 end ;
55 { Adapter }
56
57 function  Adapter._AddRef:  Integer ;
58 begin
59    Result : =  InterlockedIncrement(FRefCount);
60 end ;
61
62 function  Adapter._Release:  Integer ;
63 begin
64    Result : =  InterlockedDecrement(FRefCount);
65      if  Result  =   0   then
66    Destroy;
67 end ;
68
69 function  Adapter.QueryInterface(const IID: TGUID; out Obj): HRESULT;
70 begin
71     if  GetInterface(IID, Obj)  then
72     Result : =   0
73    else
74     Result : =  E_NOINTERFACE;
75 end ;
76 function  Adapter.ReadFile():string;
77 begin
78    self.ReadFromXml(self.node,self. count );
79 end ;
80 constructor Adapter. Create ;
81 begin
82 inherited;
83 end ;
84 var
85 aAdapter:Adapter;
86 begin
87   aAdapter: = Adapter. Create ;
88   Writeln(aAdapter.ReadFile);
89 end .
90

对象的Adapter模式的结构:

从图中可以看出:客户端需要调用CreateFile方法,而AdapteeXML,AdapteeSoap,AdapteeBin没有该方法,为了使客户端能够使用AdapteeXXX类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装AdapteeXXX的实例,从而将客户端与AdapteeXXX衔接起来。
由于Adapter与AdapteeXXX是委派关系,这决定了这个适配器模式是对象的。

该适配器模式所涉及的角色包括:

目标(Target)角色:这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口,这里为ISerTarget接口。
源(Adaptee)角色:需要适配的类,这里为AdapteeXML,AdapteeSoap,AdapteeBin类。
适配器(Adapter)角色:通过在内部包装(Wrap)Adaptee对象,把源接口转换成目标接口。

以上的例子主要为将Person类串行化为不同的形式的例子,这里分别保存为xml,soap,binary形式。由于我们使用了Adapter进行了统一封装,这样用户可以不必知道具体的封装细节,运用统一的CreateFile方法即可将Person类串行化为不同的形式。
具体代码(C#):

  1 using  System;
  2 using  System.IO;
  3 using  System.Xml.Serialization;
  4 using  System.Xml;
  5 using  System.Runtime.Serialization.Formatters.Binary;
  6 /**/ /////运行时要将System.Runtime.Serialization.Formatters.Soap.dll的引用添加到项目中
  7 using  System.Runtime.Serialization.Formatters.Soap;
  8
  9 namespace  AdapterObject
 10 {
 11    /**//// <summary>
 12    ///============== Program Description==============
 13    ///Name:AdapterObject.cs
 14    ///Objective:AdapterObject 
 15    ///Date:2006-05-04 
 16    ///Written By coffee.liu
 17    ///================================================
 18    /// </summary>
 19    class Class1
 20    {
 21        [STAThread]
 22        static void Main(string[] args)
 23        {
 24            ISerTarget target=new Adapter("XML");
 25            target.CreateFile();
 26            Console.WriteLine("XML file created");
 27
 28            target=new Adapter("Soap");
 29            target.CreateFile();
 30            Console.WriteLine("Soap file created");
 31
 32            target=new Adapter("Bin");
 33            target.CreateFile();
 34            Console.WriteLine("Bin file created");
 35        }
 36    }
 37    [Serializable]
 38    public class Person{
 39        public string Name;
 40        public string Sex;
 41        public DateTime Brith;
 42        private int PersonID;
 43        public Person()
 44        {}
 45        public void SetID(int ID)
 46        {PersonID=ID;}
 47    }
 48
 49    interface ISerTarget{
 50        void CreateFile();
 51    }
 52    class Adapter:ISerTarget{
 53       private AdapteeXML aXML;
 54       private AdapteeSoap aSoap;
 55       private AdapteeBin aBin;
 56       private string S;
 57        public Adapter(string s){
 58            S=s;
 59            if (s=="XML")
 60            {
 61                aXML=new AdapteeXML();
 62                aXML.FillData();
 63            }
 64            else
 65                if (s=="Soap")
 66            {
 67                aSoap=new AdapteeSoap();
 68                aSoap.FillData();
 69            }
 70            else if (s=="Bin")
 71            {
 72                aBin=new AdapteeBin();
 73                aBin.FillData();
 74            }
 75            else
 76            {
 77                aXML=new AdapteeXML();
 78                aXML.FillData();
 79            }
 80        }
 81
 82      public  void CreateFile(){
 83          if (S=="XML")
 84          {
 85              aXML.CreateXMLFile();
 86          }
 87          else
 88              if (S=="Soap")
 89          {
 90              aSoap.CreateSoapFile();
 91          }
 92          else if (S=="Bin")
 93          {
 94              aBin.CreateBinFile();
 95          }
 96          else
 97          {
 98              aXML.CreateXMLFile();
 99          } 
100      
101      }
102    
103    }
104    class AdapteeSoap{
105      FileStream aFileSoap;
106        Person aPerson;
107        SoapFormatter aSoapFormatter;
108        public AdapteeSoap(){
109          aSoapFormatter=new SoapFormatter();
110            aPerson=new Person();
111        }
112        public void FillData()
113        {
114            aPerson.Name="Soap";
115            aPerson.Sex="男";
116            aPerson.Brith=DateTime.Now;
117            aPerson.SetID(2);
118        }
119        public void CreateSoapFile(){
120            try
121            {
122                aFileSoap=new FileStream("SoapPerson.xml",FileMode.OpenOrCreate);
123                aSoapFormatter.Serialize(aFileSoap,aPerson);
124                aFileSoap.Close();
125            }
126            catch(IOException e){
127              Console.WriteLine("some error happened");
128                Console.WriteLine(e.ToString());
129                return;
130            }
131
132        }
133    }
134    class AdapteeBin
135    {
136        FileStream aFileBin;
137        Person aPerson;
138        BinaryFormatter aBinaryFormatter;
139        public AdapteeBin()
140        {
141            aBinaryFormatter=new BinaryFormatter();
142            aPerson=new Person();
143        }
144        public void FillData()
145        {
146            aPerson.Name="Bin";
147            aPerson.Sex="男";
148            aPerson.Brith=DateTime.Now;
149            aPerson.SetID(3);
150        }
151        public void CreateBinFile()
152        {
153            try
154            {
155                aFileBin=new FileStream("BinPerson.data",FileMode.OpenOrCreate);
156                aBinaryFormatter.Serialize(aFileBin,aPerson);
157                aFileBin.Close();
158            }
159            catch(IOException e)
160            {
161                Console.WriteLine("some error happened");
162                Console.WriteLine(e.ToString());
163                return;
164            }
165
166        }
167    }
168    class AdapteeXML{
169        FileStream aFile;
170        Person aPerson;
171        XmlSerializer aXML;
172        public AdapteeXML(){
173         aXML=new XmlSerializer(typeof(Person));
174            aPerson=new Person();
175    }
176        public void FillData(){
177        aPerson.Name="XML";
178            aPerson.Sex="男";
179            aPerson.Brith=DateTime.Now;
180            aPerson.SetID(1);
181        }
182        public void CreateXMLFile(){
183            try
184            {
185                aFile=new FileStream("Person.xml",FileMode.Create);
186            }
187            catch(IOException e)
188            {
189             Console.WriteLine("some error happened!");
190                Console.WriteLine(e.ToString());
191                return;
192            }
193            aXML.Serialize(aFile,aPerson);
194            aFile.Close();
195        }
196    }
197}
198

类适配器和对象适配器之间的差别:
   1.当我们想匹配一个类和它所有子类时,类适配器将不能胜任,因为在创建子类时就已定义了派生它的基类。如上第二例,要想改为类适配器模式就必须使用三个Adapter来分别封装三个Adaptee,这样做不太实际。
   2.类适配器允许适配器更改某些被匹配的类的方法,同时还允许使用其他未修改的方法。
   3. 对象适配器通过将子类传递给构造函数而允许匹配所有子类,如上面的第二例。
   4.对象适配器要求读者将希望使用的,被匹配对象的方法提到表面上来。

转载于:https://www.cnblogs.com/coffeeliu/archive/2006/05/04/391410.html

模式设计(七)Adapter相关推荐

  1. 从壹开始微服务 [ DDD ] 之一 ║ D3模式设计初探 与 我的计划书

    缘起 哈喽大家周四好!又是开心的一天,时间过的真快,我们的 <从壹开始 .net core 2.1 + vue 2.5 >前后端分离系列共 34 篇已经完结了,当然以后肯定还会有更新和修改 ...

  2. UML+模式设计概述

    转自于:http://blog.csdn.net/rexuefengye/article/details/13020225 工程学:工程庞大到一定程度必须是用工程学方法,好比直接用水泥沙子建设实用的摩 ...

  3. 模式设计趣解——追MM篇

    创建型模式? 1.FACTORY一追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说"来四个鸡翅" ...

  4. visual设计的界面发布到iis上显示不一样_Material Design暗夜模式设计指南

    本文较长,大概需要12分钟阅读.不久前谷歌I/O大会召开,带来了对设计师来说最为重要的的暗夜模式.由于Android面对的用户相当广泛,相当严谨具体的暗夜模式设计规范已经悄然在Google Desig ...

  5. BLM业务模式设计之战略控制

    说明:本文源自樊老师的线上课程<业务模式制胜,BLM战略规划七步法>第25集. 业务模式的"客户选择"和"价值主张"是从满足客户需求的角度所做的设计 ...

  6. [渝粤教育] 中北大学 商业模式设计与创新 参考 资料

    教育 -商业模式设计与创新-章节资料考试资料-中北大学[] 单元测验一 1.[单选题]以下企业中,年营收从0达到1000亿,用时最短的企业是( ) A.小米 B.华为 C.苹果 D.阿里巴巴 参考资料 ...

  7. 众利币开发与模式设计

    一.设计模式 1.什么是设计模式 设计模式是一套被反复使用.多数人知晓.代码设计经验的总结. 2.目的 设计模式的目的是为了让软件具有更好的代码重用性.可读性.可扩展性.可靠性,同时使程序间出现高内聚 ...

  8. 创业商业模式设计与实务

    目录 一.课程内容介绍 二.课程内容思维导图 三.文字内容 一.课程内容介绍 "创业商业模式设计与实务"是在MBA课程中非常重要的一部分.创业指希望创造创新和价值,并为此投入时间. ...

  9. jsp的MVC模式设计用户登陆注册

    jsp的MVC模式设计用户登陆注册 用户登陆功能 1.实验内容 2.实验步骤 3.实验结果 4.实验分析 用户登陆功能 通过设计用户的登陆和注册,来学习jsp的MVC模式,熟练掌握MVC模式各部分的内 ...

  10. 模式设计概述:代理者模式

    分布式系统模式 分布式相关的模式设计有大概三种模式,分布式系统与集中式系统相比需要完全不同的软件.管道和过滤器模式,微核和代理者模式. 代理者模式 代理者模式体系结构的强制条件是 组件应该能够访问其他 ...

最新文章

  1. Ubuntu换回Gnome界面
  2. 实战:从深度学习探究计算机视觉
  3. linux 查看主板sn_如何使用您的工业边缘计算单元:第三章:使用你的JayBox 主板...
  4. 黑马vue---8-10、v-cloak、v-text、v-html、v-bind、v-on的基本使用
  5. 自然语言处理期末复习(2)中文分词
  6. DevExpress第三方控件汉化的全部代码和使用方法
  7. Android之记住密码与自动登陆实现
  8. 【渝粤教育】国家开放大学2018年秋季 1131t卫生经济学 参考试题
  9. eclipse添加约束文件
  10. java web 课程设计_javaweb期末课程设计
  11. mysql amd.dll 后门_DLL型后门原理及完全清除秘诀
  12. AcrelEMS-IDC综合能效管理系统在某大型数据中心的应用方案
  13. RNA 14. SCI 文章中差异表达基因之 蛋白互作网络 (PPI)
  14. ERROR: Cannot uninstall ‘xxx‘. It is a distutils installed project and thus we cannot accurately
  15. MediaWiki搭建指导
  16. 微信小程序:关注公众号组件自定义样式
  17. jq 隔行变色(横、纵)
  18. 百度年龄计算机在线使用,百度精准年龄计算器在线计算app
  19. 新年寄语+从业感受+祝大家新年快乐~
  20. FITURE 、百度、咕咚“围猎”智能健身镜

热门文章

  1. 9.28巨人网络笔试
  2. 【接口测试简介】关于接口测试的介绍,包含分类、测试的重点、模型等等
  3. 速卖通跨境电商还好做吗,速卖通运营如反指纹浏览器防关联
  4. 测试过程中的可追溯性要求
  5. 教你从零写vue穿梭框
  6. JavaScript - 唤醒 app store 跳转到苹果商店内下载指定应用页面
  7. Redis07:redis的主从复制(原理与哨兵模式)、集群(搭建与它的优缺点)
  8. 3.6 shellcode编码技术
  9. 影像呈现再度进阶,OPPO Find X5系列与哈苏强强联合
  10. 相机手动对焦(带动画效果)