在这个有没有对象都要高呼“面向对象”的年代,掌握面向对象会给我们带来意想不到的方便。学编程的小伙伴从开始能写几行代码实现简单功能到后来懂得将一些重复的操作组合起来形成一个“函数”,再到后来将“函数”和属性组合起来形成一个“类”。一步步走来,我们在考虑着机器运行代码效率的提高的同时也在考虑减轻程序员的工作量。 那么我们今天讲到的适配器模型更着重考虑的是什么呢?是程序员工作量。

  什么时候会用到适配器模式?

  其实最简单的例子是当我们引用一个第三方类库。这个类库随着版本的改变,它提供的API也可能会改变。如果很不幸的是,你的应用里引用的某个API已经发生改变的时候,除了在心中默默地骂“wocao”之外,你还得去硬着头皮去改大量的代码。

  难道真的一定要如此吗?按照套路来说,我会回答“不是的”。我们有适配器模式啊~~

  当接口发生改变时,适配器模式就派上了用场。

举个栗子

  如果通过上面的简单描述,你都能懂,那在下只能佩服你的领悟能力超群了。一般人一定还是不知所云。为了方便理解,我引用一位博友的例子。原文地址

  一开始的和谐

  黑枣玩具公司专门生产玩具,生产的玩具不限于狗、猫、狮子,鱼等动物。每个玩具都可以进行“张嘴”与“闭嘴”操作,分别调用了openMouth与closeMouth方法。

  在这个时候,我们很容易想到可以第一定义一个抽象类Toy,甚至是接口Toy,这些问题不大,其他的类去继承父类,实现父类的方法。一片和谐,信心向荣。

  平衡的破坏

为了扩大业务,现在黑枣玩具公司与红枣遥控公司合作,红枣遥控公司可以使用遥控设备对动物进行嘴巴控制。不过红枣遥控公司的遥控设备是调用的动物的doMouthOpen及doMouthClose方法。黑枣玩具公司的程序员现在必须要做的是对Toy系列类进行升级改造,使Toy能调用doMouthOpendoMouthClose方法。

  考虑实现的方法时,我们很直接地想到,你需要的话我再在我的父类子类里给你添加这么两个方法就好啦。当你一次又一次在父类子类里面重复添加着这两个方法的时候,总会想着如此重复的工作,难道不能解决么?当有数百个子类的时候,程序员会改疯的。程序员往往比的是谁在不影响效率的时候更会“偷懒”。这样做下去程序员会觉得自己很傻。(其实我经常当这样的傻子)

abstract class Toy
{
public abstract function openMouth(); public abstract function closeMouth(); //为红枣遥控公司控制接口增加doMouthOpen方法
public abstract function doMouthOpen(); //为红枣遥控公司控制接口增加doMouthClose方法
public abstract function doMouthClose();
} class Dog extends Toy
{
public function openMouth()
{
echo "Dog open Mouth\n";
} public function closeMouth()
{
echo "Dog open Mouth\n";
} //增加的方法
public function doMouthOpen()
{
$this->doMouthOpen();
} //增加的方法
public function doMouthClose()
{
$this->closeMouth();
}
} class Cat extends Toy
{
public function openMouth()
{
echo "Cat open Mouth\n";
} public function closeMouth()
{
echo "Cat open Mouth\n";
} //增加的方法
public function doMouthOpen()
{
$this->doMouthOpen();
} //增加的方法
public function doMouthClose()
{
$this->closeMouth();
}
}

  更加烦躁

  程序员刚刚码完代码,喝了口水,突然间另一个消息传来。

  黑枣玩具公司也要与绿枣遥控公司合作,因为绿枣遥控公司遥控设备更便宜稳定。不过绿枣遥控公司的遥控设备是调用的动物的operMouth($type)方法来实现嘴巴控制。如果$type为0则“闭嘴”,反之张嘴。

这下好了,程序员又得对Toy及其子类进行升级,使Toy能调用operMouth()方法。搁谁都不淡定了。

abstract class Toy
{
public abstract function openMouth(); public abstract function closeMouth(); public abstract function doMouthOpen(); public abstract function doMouthClose(); //为绿枣遥控公司控制接口增加doMouthClose方法
public abstract function operateMouth($type = 0);
} class Dog extends Toy
{
public function openMouth()
{
echo "Dog open Mouth\n";
} public function closeMouth()
{
echo "Dog open Mouth\n";
} public function doMouthOpen()
{
$this->doMouthOpen();
} public function doMouthClose()
{
$this->closeMouth();
} public function operateMouth($type = 0)
{
if ($type == 0) {
$this->closeMouth();
} else {
$this->operateMouth();
}
}
} class Cat extends Toy
{
public function openMouth()
{
echo "Cat open Mouth\n";
} public function closeMouth()
{
echo "Cat open Mouth\n";
} public function doMouthOpen()
{
$this->doMouthOpen();
} public function doMouthClose()
{
$this->closeMouth();
} public function operateMouth($type = 0)
{
if ($type == 0) {
$this->closeMouth();
} else {
$this->operateMouth();
}
}
}

  在这个时候,程序员必须要动脑子想办法了,就算自己勤快,万一哪天紫枣青枣黄枣山枣这些遥控公司全来的时候,忽略自己不断增多的工作量不说,这个Toy类可是越来越大,总有一天程序员不崩溃,系统也会崩溃。

   问题在出在哪里呢?

  像上面那样编写代码,代码实现违反了“开-闭”原则,一个软件实体应当对扩展开放,对修改关闭。即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。也就是说每个尸体都是一个小王国,你让我参与你的事情这个可以,但你不能修改我的内部,除非我的内部代码确实可以优化。

  在这种想法下,我们懂得了如何去用继承,如何利用多态,甚至如何实现“高内聚,低耦合”。

  回到这个问题,我们现在面临这么一个问题,新的接口方法我要实现,旧的接口(Toy抽象类)也不能动,那么总得有个解决方法吧。那就是引入一个新的类--我们本文的主角--适配器。  适配器要完成的功能很明确,引用现有接口的方法实现新的接口的方法。更像它名字描述的那样,你的接口不改的话,我就利用现有接口和你对接一下吧。

  到此,解决方法已经呼之欲出了,下面贴上代码。

  

<?php
abstract class Toy
{
public abstract function openMouth(); public abstract function closeMouth();
} class Dog extends Toy
{
public function openMouth()
{
echo "Dog open Mouth\n";
} public function closeMouth()
{
echo "Dog close Mouth\n";
}
} class Cat extends Toy
{
public function openMouth()
{
echo "Cat open Mouth\n";
} public function closeMouth()
{
echo "Cat close Mouth\n";
}
} //目标角色:红枣遥控公司
interface RedTarget
{
public function doMouthOpen(); public function doMouthClose();
} //目标角色:绿枣遥控公司及
interface GreenTarget
{
public function operateMouth($type = 0);
} //类适配器角色:红枣遥控公司
class RedAdapter implements RedTarget
{
private $adaptee; function __construct(Toy $adaptee)
{
$this->adaptee = $adaptee;
} //委派调用Adaptee的sampleMethod1方法
public function doMouthOpen()
{
$this->adaptee->openMouth();
} public function doMouthClose()
{
$this->adaptee->closeMouth();
}
} //类适配器角色:绿枣遥控公司
class GreenAdapter implements GreenTarget
{
private $adaptee; function __construct(Toy $adaptee)
{
$this->adaptee = $adaptee;
} //委派调用Adaptee:GreenTarget的operateMouth方法
public function operateMouth($type = 0)
{
if ($type) {
$this->adaptee->openMouth();
} else {
$this->adaptee->closeMouth();
}
}
} class testDriver
{
public function run()
{
//实例化一只狗玩具
$adaptee_dog = new Dog();
echo "给狗套上红枣适配器\n";
$adapter_red = new RedAdapter($adaptee_dog);
//张嘴
$adapter_red->doMouthOpen();
//闭嘴
$adapter_red->doMouthClose();
echo "给狗套上绿枣适配器\n";
$adapter_green = new GreenAdapter($adaptee_dog);
//张嘴
$adapter_green->operateMouth(1);
//闭嘴
$adapter_green->operateMouth(0);
}
} $test = new testDriver();
$test->run();

  最后的结果就是,Toy类及其子类在不改变自身的情况下,通过适配器实现了不同的接口。

  最后总结

  将一个类的接口转换成客户希望的另外一个接口,使用原本不兼容的而不能在一起工作的那些类可以在一起工作.

  适配器模式核心思想:把对某些相似的类的操作转化为一个统一的“接口”(这里是比喻的说话)--适配器,或者比喻为一个“界面”,统一或屏蔽了那些类的细节。适配器模式还构造了一种“机制”,使“适配”的类可以很容易的增减,而不用修改与适配器交互的代码,符合“减少代码间耦合”的设计原则。

 以上

系列文章:

      php模式设计之 单例模式

    php模式设计之 工厂模式

   php模式设计之 注册树模式

    php模式设计之 适配器模式

          php模式设计之 观察者模式

php模式设计之 适配器模式的更多相关文章

  1. PHP模式设计之单例模式、工厂模式、注册树模式、适配器模式、观察者模式

    php模式设计之单例模式 什么是单例模式? 单例模式是指在整个应用中只有一个实例对象的设计模式 为什么要用单例模式? php经常要链接数据库,如果在一个项目中频繁建立连接数据库,会造成服务器资源的很大 ...

  2. php模式设计之 观察者模式

    这是我写的<php模式设计>的第五篇.前面的四篇在不断学习不断加深认识,到了今天再看观察者模式,觉得非常容易理解.这也许就是我们积少成多的结果吧.希望还是能够不断进步. 开篇还是从名字说起 ...

  3. php模式设计之 注册树模式

    在前两篇单例模式和工厂模式后,终于迎来了最后一个基础的设计模式--注册树模式. 什么是注册树模式? 注册树模式当然也叫注册模式,注册器模式.之所以我在这里矫情一下它的名称,是因为我感觉注册树这个名称更 ...

  4. php模式设计之 工厂模式

    承接上篇php模式设计之 单例模式,(虽然好像关系不大).今天讲述第二种基础的模式设计——工厂模式. 那么何为工厂模式? 从名字来看,似乎看不出什么端倪.工厂模式,和生产有关?还是和生产流程有关?难道 ...

  5. php模式设计之 单例模式

    模式设计是什么?初学者一开始会被这高大上的名称给唬住.而对于有丰富编程经验的老鸟来说,模式设计又是无处不在.很多接触的框架就是基于各种模式设计形成的. 简单说,在写代码的过程中一开始往往接触的是面向过 ...

  6. 分享基于Entity Framework的Repository模式设计(附源码)

    关于Repository模式,在这篇文章中有介绍,Entity Framework返回IEnumerable还是IQueryable? 这篇文章介绍的是使用Entity Framework实现的Rep ...

  7. JavaScript高级---门面模式设计

    门面模式 两个作用: 1.简化类的接口 2.消除类与使用它的客户代码之间的耦合 门面模式常常是开发人员最亲密的朋友.它几乎是所有javascript库的核心原则 门面模式的目的是为了让开发人员用更简单 ...

  8. JavaScript高级---组合模式设计

    一.设计模式 javascript里面给我们提供了很多种设计模式: 工厂.桥.组合.门面.适配器.装饰者.享元.代理.观察者.命令.责任链 在前面我们实现了工厂模式和桥模式 工厂模式 : 核心:为了生 ...

  9. JavaScript高级---桥模式设计

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/stri ...

随机推荐

  1. 学习随笔—Redis常用命令

    info 服务器基本信息 monitor 实时转储收到的请求 flushdb 清空当前数据库 flushall 清空所有数据库 quit 关闭连接 save 将数据同步保持到磁盘 bgsave     ...

  2. 一个SharePoint定时器 (SPJobDefinition)

    需要写一个自定义的sharepoint timer job, 目的是要定时到Site Collection Images这个List里检查图片的过期日期,如果即将过期的话,需要发送email到相关的人 ...

  3. 问题解决——WSAAsyncSelect模型 不触发 FD_CLOSE

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  4. cxf构建webservice的两种方式

    一.简介 对于基于soap传输协议的webservice有两种开发模式,代码优先和契约优先的模式.代码优先的模式是通过编写服务器端的代码,使用代码生成wsdl:契约优先模式首先编写wsdl,再通过ws ...

  5. jacob 实现Office Word文件格式转换

    关于jacob用法,百度一下就会发现几乎都是复制2004年一个代码,那段代码实现的是从一个目录读取所有doc文件,然后把它转html格式. 为了便习学习和使用,我把代码看懂后精简了一下,得出不少新结论 ...

  6. xml in hadoop ETL with pig summary

    项目中需要把source为xml的文件通过flume放置到hdfs,然后通过MR导入到vertica中去,我之前做过简单的 尝试,是通过pig的piggybank的xmlloader然后Regex_e ...

  7. js统计字符串中各种字符情况

    问题描述:在一个字符串中,统计出大写字母.小写字母.数字和其他字符各数.这个算法以前在学习java的时候,老师说过,而且说了四种算法.在孔乙己的世界里,茴香豆的"茴"字有四种写法嘛 ...

  8. 《至少有那天》——IU

    //<你的意义>中文版 那天冷的让人好想哭 可是我那一天看到了爱情 湖边的薄冰和老树 就在零下七度那一天 你和我牵手 慢慢聊着以前那些童话 可能它们都有些意义吧 是吗 一个吻 一滴眼泪 一 ...

  9. 并发用户数与TPS之间的关系

    1.  背景 在做性能测试的时候,很多人都用并发用户数来衡量系统的性能,觉得系统能支撑的并发用户数越多,系统的性能就越好:对TPS不是非常理解,也根本不知道它们之间的关系,因此非常有必要进行解释. 2 ...

  10. java 15 -3 集合的遍历的练习

    练习:用集合存储5个动物对象,并把动物对象进行遍历. 分析: A:创建动物类 a:无参构造方法 b:有参构造方法 c:get.set方法 B:创建集合对象 a:Collection animal = ...