浅谈适配器设计模式与观察者设计模式

浅谈适配器设计模式与观察者设计模式

直接复制doc 可能没有图

写在前面:

阅读该文档基本要求:了解面对对象编程,理解面对对象的基本概念。

 

一.           适配器设计模式

1.1经典概念诠释

在计算机编程中,适配器模式(有时候也称包装样式或者包装)将一个的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。(来自维基百科)

适配器模式将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。(来自head first 设计模式)

1.2 适配器设计模式的分类

1.>适配器设计模式委托实现形式(对象适配器模式)。

2.>适配器设计模式继承实现形式(类适配器模式)

1.3实际生活中物理意义的适配器例子

电脑上用的PS/2接口转USB接口的适配器就是一种典型的实际生活中物理意义的适配器,如下图:

1PS/2USB适配器

适配器设计模式其实顾名思义,它使得两个相互交互的模块能够很好整合成为一个整体,这和我们平常生活中物理意义的适配器的思想是一样的,唯一的不同他只是在软件开发中应用。

1.3适配器模式简单实例讲解(设计模式的故事:猫和狗的故事)

故事的开头总是这样:很久很久以前有一只猫,他很想和狗交流,并想用自己的猫食换取阿狗的骨头。但是由于它们语言很不通交流很困难,双方比划了半天,谁也没有听懂对方在说什么。因为能和狗狗交流的只有狗语者。

%#我要骨头#@$

 

whatI can’t understand

1.3.1委托形式实现适配器模式(有时也叫包装 wrapper pattern

猫清楚的知道,要想能和狗狗进行交流,就必须要有说狗语能力(即成为狗语者),但是它不会狗语,而且也不想成为狗语者,不过幸运的是,这只猫虽然不会狗语,但是它是一名软件工程师,而且学过适配器设计模式,它清楚要和狗狗们对话必须要找个会狗语的委托人(即一个狗语者),这个想法使得他很快想起了适配设计模式的委托形式实现,为了分析这个计划的可行性,于是他用UML起草了这份计划书(类图)。

2

其中DogCommunicate函数只接受类型为DogSpeaker的参数

对于该类图的阐述:

Translator类实现了一个DogSpeaker的接口,他成为狗语者。所以translator通过狗语者的身份能够和狗进行交流,因为Dog类中的communicate函数只接受DogSpeaker类型的参数。从而如果老猫同志要和狗狗进行交流,他可以委托一位Translator作为发言人 和狗狗交流。那么具体Translator是怎样做的呢,我看看Translator中具有一个Cat实例,这个Cat的实例就是使得Translator通过自己DogSpeaker身份(狗语者)和狗狗进行交流时,能够真正的调用Cat类中的talk()函数即利用身份帮助猫表达观点,所以Translator其实只是担任了一个发言者的作用或是包装者的作用,而真正表达还是老猫的言论即Cat类中的talk。这样便实现了猫和狗的交流。(看后面简单的代码就能够明白)

 

Java实现对象适配器模式源码:

Cat类代码:

/**

*

* @author Administrator

* 说明:猫不会说狗语的传统老猫

*/

public class Cat {

public void talk(){

System.out.println("我要你的骨头");

}

}

 

DogSpeaker接口:

/**

 *

 * @author Administrator

 * 说明:狗语者

 */

public interface DogSpeaker {

public void speakDogLanguage();

}

 

Translator类:

/**

 *

 * @author Administrator

 * 说明:实现了狗语者的优良品质,能够胜任狗语翻译员

 */

public class Translator implements DogSpeaker {

private Cat cat;//老猫同志躲在这里

 

public Translator(){

cat=new Cat();

}

 

public void speakDogLanguage() {

// TODO Auto-generated method stub

cat.talk();//看似狗语者在讲话。其实是老猫的表达

}

}

 

Dog类:

public class Dog {

public void communicate(DogSpeaker speaker){

speaker.speakDogLanguage();

System.out.println("ok no problem");

}

}

//狗狗只和狗语者沟通

 

测试用的主类

public class Main {

public static void main(String[] args){

DogSpeaker speaker=new Translator();

System.out.println("***************");

//超级猫在说狗语

Dog dog=new Dog();

dog.communicate(speaker);

}

}

 

运行结果:

***************

我要你的骨头

ok no problem

 

Cat成功进入DogCommunicate函数内部,并发表自己的言论。

 

1.3.2 继承形式实现适配器模式

对于猫来讲,每次和狗狗交流都得付给翻译员Translator高额的费用,这让他很不爽,况且这段时间一直流行软件外包,似乎懂狗语的软件工程师很吃香,于是老猫通知考虑是不是应该学习狗语了……面对这自己空空的钱袋,他终于下定决心,它辞退了translator,然后大步迈向狗语者训练营”……(PS:老猫同志终于觉悟了,毕竟继承模式实现比委托模式更简单)

老猫的学习蓝图(即继承形式实现的类图):

3

对类图的说明(故事的延续):

Cat还是那只catDog也还是那只DogDogSpeaker的接口代码也没变,SuperCat实现了DogSpeaker 变成了一只用狗语武装了自己的SuperCat

经过漫长而又艰苦的岁月,老猫同志终于学会狗语,它很好的继承了狗语者这个接口(DogSpeaker),并且通过狗语专业八级考试,拿到高级狗语者资格证于是他能够和狗狗交流。

Java实现源码:Cat Dog DogSpeaker接口的源码都前面一样。

SuperCat源码:

/**

 *

 * @author Administrator

 * 说明:超级猫类,身为狗语者的猫

 */

public class SuperCat extends Cat implements DogSpeaker{

public void speakDogLanguage(){

super.talk();//直接调用父类的函数

}

}

 

测试用的main类:

public class Main {

public static void main(String[] args){

DogSpeaker speaker=new SuperCat();

System.out.println("***************");

//超级猫在说狗语

Dog dog=new Dog();

dog.communicate(speaker);

}

}

 

结果最终和前面一样。

关于继承形式的实现的思考:

在这个例子中幸好能够狗交流的条件很低只要是狗语者,如果它要求变成了只能是狗,那么用继承的方法是否合理,让猫继承狗这样的举动是否合理?

继承方式很简单,但是有时候也会与一些纯粹的面对对象编程相互冲突。

 

故事总是有相同的结局而且一样的无聊:老猫懂得了狗语,使得他和狗狗们快乐的生活着。

 

二.           观察者设计模式

2.1对于观察者模式的经典言论

“a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.” 在对象之间定义一对多依赖,当一个对象改变状态,依赖它的对象都会收到通知,并自动更新。(来自四人组《设计模式》)

观察者模式是JDK使用最多的模式之一,非常有用。(来自《head first 设计模式》)

2.2观察者模式的组成

不可缺少的部分:主题(被观察的类或组件),具体Observer(观察者),观察者被通知时所被调用的函数,主题通知观察者的函数。

典型的观察者所具有的函数(功能):addObserver()增加观察者,deleteObserver()删除观察者,notifyObservers()通知所有观察者,以及一个放观察者的链表或容器。

当然一半观察者都有自己的特有属性,即被通知,所以通常(便于主题的通知),都会把观察者的这个属性提炼出来作为一个接口,这样的话,每个观察者被通知就可以利用接口对实现类实例对象引用通知所有观察者都有的被通知函数来实现主题通知所有观察者这一功能(这里利用的面对对象中的多态)。我们在以后图中就把这种观察者需要实现的被通知函数称为update()。

观察者模式用uml表示:

4

图的解释:

Subject及是被观察者的观察主题,他是一个基类,具有主题应该有的特性,增加删除通知观察者这一特性,而且还应该具有vector来放置观察者(因为Observer的数量是不固定的)XXXSubjectSubject的子类,是主题类的具体实现,Observer接口拥有观察者的一般属性,XXXObserver具体观察者。

addObserver()和deleteObserver()这个几个函数功能也是增加观察者和删除观察者,其实这只是观察者模式一种最普遍的是现实形式,如果不用vector直接把Observer当成主题一个成员变量写入Subject(主题)这个类中也不是不可以,但是如果你想增加或减少观察者这样修改起来很方便所以一般都用上述的方法解决。

notifyObserver()这个函数是通知所有在主题类中注册了Observer对象,它的实质是和Observer接口珠联璧合,通过Observer接口调用Update达到通知观察者的目的。

观察者设计模式的触发流程:

在主题类的实例

中注册观察者

主题内容

发生更改

调用主题

notifyObservers()

函数来通知各个观察者

notifyObserver()

实现调用Observer接口

Update()函数

具体Observer都实现了接口

通过OO中的多态性

notifyObserver其实

调用了他们的Upate()

对他们进行了更新

2.3 设计模式在实际项目中的应用

项目简介:

项目名称:coffeechess 实现语言:java 所属类型:局域网游戏 概述:coffeechess是一款用java编写的局域网国际象棋对弈游戏,所以者牵涉到数据网络传输,和接受到对方数据后通知己方显示模块工作的问题,在这里就需要利用观察者设计模式。

coffeechess中应用的观察者模式:

5

类图的解释:

BindComponet为一个接口,他是监听网络消息线程ClientThread的实现的一个接口,它主要是包装了被监听主题的一些特性,BindComponet()函数就是它的一个函数作用和AddObserver一样注册观察者的,而insertStr2Componet()与NotifyObservers()函数类似是通知所有观察者的函数,ComponentBeUpdate是一个接口,它主要是包装Observer的一些特性,Componet类一个具体的观察者,当消息通知到各个观察者时,这些观察者都是被主题通过InsertStr2Component通过接口ComponentBeUpate调用insert2Component函数的。

 

具体代码实现:

BingComponent接口部分源码:clientThread实现的一个接口这里两个函数一个主要是用来注册观察者,一个是用来通知观察者们的函数

interface BindComponent {

public void bindingComponent(ComponentBeUpate component);

 

public void insertStr2Component(String str);

}

 

ClientThread的部分代码

public class ClientThread implements Runnable , BindComponent {

……..

protected Vector<ComponentBeUpate> componentlist;

…….

public void insertStr2Component(String str) {// 通知控件

for(int i=0;i<this.componentlist.size();i++){

componentlist.get(i).insert2Component(str);

}

}

 

public void bindingComponent(ComponentBeUpate component) {//注册控件 类似addObserver

this.componentlist.add(component);

}

}

 

它主要用于通知观察者后,观察者的更新

ComponentBeUpdate接口的代码:

package LinkDepartment;

public interface ComponentBeUpate {

public  void insert2Component(String str);

}

 

观察者的实现部分部分(举了一个具体的实现片段)

public void insert2Component(String str){

 if(component!=null){ ((JTextArea)component).append("对方 "+str+"/n");

 }else{

 }

}

 

最后的效果图:

6

2.3观察者模式和适配器模式的关系

其实虽然观察者模式和适配器模式是两个不同的设计模式,但是它们之间还是有很微妙的关系,观察者模式一般都会利用到适配器模式,即存在观察者模式的地方必存在适配器模式。因为一般实现了观察者接口的类都是属于被观察者所包装,即被适配器模式的继承形式,当然也有委托形式,看看图6上方的观察者部分实现代码((JTextArea)component这个就是被委托的。

2.4关于Observer Pattern的部分感想

Observer这个名词的原意是观察者,但实际上Observer的参与者并不是主动的观察,而是被动等待subject(主题)参与者的通知Observer pattern又称为publish-subscrible patternPublish(发行)和subscrible(订阅)的表达可能更贴切一点。

 

三.           关于设计模式的部分感想

设计模式的本身很简单,思想也很容易弄懂,它的难度主要是如何应用它,如何实现它使得它能够提高代码的可维护性,可重用性,可扩展性。以及怎样富有创造性利用它们,组合它们,甚至自己创建一种新的设计模式。这也许才是设计模式所应该给予我们的,而不仅仅是简单思想本省。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值