第九课 适配器模式
今天我们来看一看适配器模式。这是一个常用的模式,作用也很简单,举例说明一下。现在我们有一个团队,在做一个大型项目。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
分享到:
相关推荐
适配器模式: 从而使原本因接口原因不 适配器模式 把一个类的接口变换成客户端所期待的另一种接口, 匹配而无法一起工作的两个类能够一起工作。 适配类可以根据参数返还一个合适的实例给客 户端。 7、BRIDGE —...
2. **VMware第9课:虚拟机的网络功能(基本功能).rar** - 这一课会介绍VMware虚拟机的网络配置,包括桥接模式、NAT模式和仅主机模式,以及如何设置网络适配器,确保虚拟机能够正确连接到物理网络或互联网。...
"易安卓零基础第十八课 - 接口函数调用"这个教程可能是针对初学者设计的,旨在帮助他们理解并掌握如何在Android应用中有效地使用接口。在本课程中,我们可以期待学习到以下几个核心知识点: 1. **接口的概念**:在...
### WinXP系统结构5课(注册表)->1 认识注册表 #### 课程概述 本课程由网蝉老师授课,旨在帮助学员深入了解WinXP系统中的注册表机制及其作用。通过本课程的学习,学生将能够掌握注册表的基本概念、工作原理以及...
第九章 包_样例类_样例对象 00,导学 01.包的简介和格式 02.包的作用域 03.包对象 04.包的可见性 05.包的引入 06.样例类入门案例 07.样例类的默认方法 08.样例对象 09.案例_计算器 第十章 常用容器(数组, ...