`

第九课 适配器模式

阅读更多

第九课 适配器模式

       今天我们来看一看适配器模式。这是一个常用的模式,作用也很简单,举例说明一下。现在我们有一个团队,在做一个大型项目。A同志负责写一些基类。它定义了一个读写操作类,由一个方法readbyte(),正如名字说说的,将文本读取,返回byte[]的方法。现在呢,B定义了一个接口,里面包含了2个方法,readByte(),和readString()。并且设计者基于这个接口做了很多应用。现在C同志犯愁了。A只给了他一个readByte(),而根据设计,他需要用B的接口。可是现在没有一个readString()的方法呀。那么怎么办呢。他就需要实现一个适配器。将A的类适配到B的接口上去。简单的说就是利用一下A的readbyte()方法,来实现一下readString()方法,这样不就满足了B的接口了吗,也能满足设计者的需求。这就是适配器模式了。就像美国的电源是110v,中国是220v。美国电器来到中国用,必须要通过一个 变压器(适配器) 来把电流改成110v才能正常使用。中间的适配器,就想C写的实现一样。

       转一段原话:在 GoF 的经典著作《设计模式》中指出: Adapter 模式的目的就是将类的接口转换成客户对象需要的接口, Adapter 模式使原本不相容的接口变的相容。也就是说我们有一个可以满足我们需要的对象,但是她的接口却不是象我们所期望的那样,而我们现在所需要的就是创建一个新的接口,让原本的接口能够满足我们的需要。

       这在拿过别人的类来做应用的时候很常用的。毕竟不能期待别人给你的接口完全符合你的需要,相信经常给不同设备写应用的同志很有感触吧。

 

       在实际应用中适配器基本有两种实现方法。

1.       基于类的实现

2.       基于对象的实现

 

下面分别来看1个例子

 

基于类的适配器模式实现:

首先看要适配到的接口(或基类,也就是上文例子B的接口)

1.        package com.javapatterns.adapter.classAdapter;
2.        

3.        public interface Target {
4.            byte[] readByte();
5.        

6.            string readString();
7.        }
8.        

9.        

Target接口期待这两个方法,readByte()和readString()。

 

接着看A实现的类对象:

1.        package com.javapatterns.adapter.classAdapter;
2.        

3.        public class Adaptee {
4.            public byte[] readByte(){...}
5.        }
6.        

Adaptee类只提供了readByte()一个方法,无法满足Target接口的期望。

 

再看C的处理方法:

1.        package com.javapatterns.adapter.classAdapter;
2.        

3.        public class Adapter extends Adaptee implements Target {
4.            public string readString(){
5.                byte[] bytes = readByte();
6.                return byte2String(bytes);
7.            }
8.        

9.            private string byte2String(byte[] bytes){...}
10.     }
11.     

 

他继承了Adaptee类,同时实现Target 接口。这样他自然就拥有了readByte()方法的实现。只需要实现Target接口期望的另一个方法readString()即可。这里用了集成Adaptee的方式,所以说他是基于类的实现。

      

       基于对象的适配器实现:

接口Target与Adaptee类不变,这里不再描述了。来关注下C的实现。

1.        package com.javapatterns.adapter.objectAdapter;
2.        

3.        public class Adapter implements Target {
4.        public Adapter(Adaptee adaptee){
5.                super();
6.                this.adaptee = adaptee;
7.            }
8.        

9.            public byte[] readByte(){
10.             return adaptee.readByte();
11.         }
12.     

13.         public string readString(){
14.             return byte2String(adaptee.readByte());
15.         }
16.     

17.         private Adaptee adaptee;
18.         private string byte2String(byte[] bytes){...}
19.     }
20.     

 

注意看这里C巧妙的利用了一个似有属性 adaptee 来实现Target 所期望的两个方法。这种方式就是基于对象的实现。

 

在实际应用中,很多情况下A提供的方法并不能直接作为B期望的方法的实现,所以基于对象的实现是颇为常用的手段。

 

先说个大家都知道的例子。Java的jdbc驱动。其实不同的数据库操作,都有这自己的接口。Jdbc就相当于一个适配器。将Oracle,sqlserver.mysql等操作接口适配成统一的jdbc的数据操作接口。进而方便客户调用。

 

再说一个我实际的例子。我在做发卡程序的时候,需要用到读写射频卡(可以理解为IC卡)的发卡器。不同厂家的发卡起都提供自己的接口。但是我要兼容多家厂商的发卡器啊,所以这里我采取了适配器模式。定义了一个统一的接口,里面包含基本方法(基本就是 init read write 这些基本操作。对于不同品牌发卡器来说,只是接口不同,基本用法都是相同的)然后通过适配器类来将不同品牌的接口适配到我统一的接口上。在通过一个反射工厂来获得具体的适配器类的接口引用。这样我用那个厂家的发卡器,只需要做下配置即可。如果采取了新厂家的发卡器,只需要新增一个适配器实现。很方便吧。

 

最后追加一个C#的例子,是大话设计模式的例子。我想例子多了终归是好的。、

1.        using System;
2.        using System.Collections.Generic;
3.        using System.Text;
4.        

5.        namespace 适配器模式
6.        {
7.            class Program
8.            {
9.                static void Main(string[] args)
10.             {
11.                 Player b = new Forwards("巴蒂尔");
12.                 b.Attack();
13.     

14.                 Player m = new Guards("麦克格雷迪");
15.                 m.Attack();
16.     

17.                 //Player ym = new Center("姚明");
18.                 Player ym = new Translator("姚明");
19.                 ym.Attack();
20.                 ym.Defense();
21.     

22.                 Console.Read();
23.             }
24.         }
25.     

26.         //篮球运动员
27.         abstract class Player
28.         {
29.             protected string name;
30.             public Player(string name)
31.             {
32.                 this.name = name;
33.             }
34.     

35.             public abstract void Attack();
36.             public abstract void Defense();
37.         }
38.     

39.         //前锋
40.         class Forwards : Player
41.         {
42.             public Forwards(string name)
43.                 : base(name)
44.             {
45.             }
46.     

47.             public override void Attack()
48.             {
49.                 Console.WriteLine("前锋 {0} 进攻", name);
50.             }
51.     

52.             public override void Defense()
53.             {
54.                 Console.WriteLine("前锋 {0} 防守", name);
55.             }
56.         }
57.     

58.         //中锋
59.         class Center : Player
60.         {
61.             public Center(string name)
62.                 : base(name)
63.             {
64.             }
65.     

66.             public override void Attack()
67.             {
68.                 Console.WriteLine("中锋 {0} 进攻", name);
69.             }
70.     

71.             public override void Defense()
72.             {
73.                 Console.WriteLine("中锋 {0} 防守", name);
74.             }
75.         }
76.     

77.         //后卫
78.         class Guards : Player
79.         {
80.             public Guards(string name)
81.                 : base(name)
82.             {
83.             }
84.     

85.             public override void Attack()
86.             {
87.                 Console.WriteLine("后卫 {0} 进攻", name);
88.             }
89.     

90.             public override void Defense()
91.             {
92.                 Console.WriteLine("后卫 {0} 防守", name);
93.             }
94.         }
95.     

96.         //外籍中锋
97.         class ForeignCenter
98.         {
99.             private string name;
100.          public string Name
101.          {
102.              get { return name; }
103.              set { name = value; }
104.          }
105.  

106.          public void 进攻()
107.          {
108.              Console.WriteLine("外籍中锋 {0} 进攻", name);
109.          }
110.  

111.          public void 防守()
112.          {
113.              Console.WriteLine("外籍中锋 {0} 防守", name);
114.          }
115.      }
116.  

117.      //翻译者
118.      class Translator : Player
119.      {
120.          private ForeignCenter wjzf = new ForeignCenter();
121.  

122.          public Translator(string name)
123.              : base(name)
124.          {
125.              wjzf.Name = name;
126.          }
127.  

128.          public override void Attack()
129.          {
130.              wjzf.进攻();
131.          }
132.  

133.          public override void Defense()
134.          {
135.              wjzf.防守();
136.          }
137.      }
138.  }
139.  

 

这里有一个基类Player,包含进攻和防守。不同位置都有不同的实现。但是最终大家都适配到了Player上。

 

       其实现在讲到这里了,大家应该对“开发模式”这个东西有一定了解了。这里重在思想,不重实现。(有点像依赖倒转原则哦)实际应用中很多情况下都是各种模式组合应用。而这个例子打眼一看好像根本都不算适配器模式。但他的思想是把各个位置的人员都适配到Player上面,体现了适配器的思想。所以他可以叫做适配器模式。

 

       其实到这里我实际用过的设计模式就讲得差不多了。再之后的我也是要先学习了。好了,不废话了,学习~

 

       作者:王文斌

       转载请注明出处


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lanwilliam/archive/2008/10/29/3173433.aspx

分享到:
评论

相关推荐

    C#23种设计模式_示例源代码及PDF

    适配器模式: 从而使原本因接口原因不 适配器模式 把一个类的接口变换成客户端所期待的另一种接口, 匹配而无法一起工作的两个类能够一起工作。 适配类可以根据参数返还一个合适的实例给客 户端。 7、BRIDGE —...

    VMware虚拟机教程

    2. **VMware第9课:虚拟机的网络功能(基本功能).rar** - 这一课会介绍VMware虚拟机的网络配置,包括桥接模式、NAT模式和仅主机模式,以及如何设置网络适配器,确保虚拟机能够正确连接到物理网络或互联网。...

    易安卓零基础第十八课 - 接口函数调用.zip

    "易安卓零基础第十八课 - 接口函数调用"这个教程可能是针对初学者设计的,旨在帮助他们理解并掌握如何在Android应用中有效地使用接口。在本课程中,我们可以期待学习到以下几个核心知识点: 1. **接口的概念**:在...

    winxp系统结构5课(注册表)->1认识注册表

    ### WinXP系统结构5课(注册表)->1 认识注册表 #### 课程概述 本课程由网蝉老师授课,旨在帮助学员深入了解WinXP系统中的注册表机制及其作用。通过本课程的学习,学生将能够掌握注册表的基本概念、工作原理以及...

    scala从入门到精通技术教学视频

    第九章 包_样例类_样例对象 00,导学 01.包的简介和格式 02.包的作用域 03.包对象 04.包的可见性 05.包的引入 06.样例类入门案例 07.样例类的默认方法 08.样例对象 09.案例_计算器 第十章 常用容器(数组, ...

Global site tag (gtag.js) - Google Analytics