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

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

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

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

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

举个栗子

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

  一开始的和谐

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

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

  平衡的破坏

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

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

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. 关于移动端的font和图片的问题

    一.font-family 使用无衬线字体 body { font-family: "Helvetica Neue", Helvetica, STHeiTi, sans-serif ...

  2. 烂泥:KVM中安装Windows Server 2008 R2系统

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 在前一篇文章中,我介绍了有关在KVM中的安装Centos系统.接下来,就来介绍如何在KVM中安装Windows系统. 注意:在此我安装的是windows ...

  3. HTML5客户端数据存储

    HTML5 使在不影响网站性能的情况下存储大量数据成为可能.之前,这些都是由 cookie 完成的,cookie不适合大量数据的存储,因为会影响速度. 举个例子: var obj = {x:1}; / ...

  4. td内元素居顶,td元素不随高度的撑开而变位置

    如下图,右边内容变高了,左边元素位置就下降到居中 设置居顶不变的方法 <table width="200" border="1"> <tr&g ...

  5. Intent详解

    ntent组件虽然不是四大组件,但却是连接四大组件的桥梁,学习好这个知识,也非常的重要. 一.什么是Intent 1.Intent的概念: Android中提供了Intent机制来协助应用间的交互与通 ...

  6. seq 显示00 01的格式

    for i in `seq -w 00 20` ; do echo $i ;done 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 ...

  7. solr性能调优

    Schema Design Considerations indexed fields indexed fields 的数量将会影响以下的一些性能: 索引时的时候的内存使用量 索引段的合并时间 优化时 ...

  8. C之五子棋

    #include <stdio.h> #include <stdlib.h> #define N 15 ][N + ] = { }; ; void initGame(void) ...

  9. ZBrush中的SubTool工具该怎样使用

    今天的ZBrush教程中将为大家引入一个新的工具SubTool,使用SubTool您可以添加PolyMesh至当前编辑的模型中,它的出现改变了过去ZBrush不能同时编辑多个模型的弊端. 查看详细的视 ...

  10. 如何实现ZBrush 4R7中按钮颜色的自定义

          本文详细讲解在ZBrush® 4R7中如何改变按钮颜色. Zbrush默认的开关按钮颜色为橙黄色,若您不喜欢当前颜色,可以通过“Icolors”功能按钮下的各命令来更改界面开关颜色及透明度 ...