Head First设计模式之适配器模式与外观模式

前言:

之前讲过装饰者模式,将对象包装起来并赋予新的职责,这一章我们也会将对象进行包装,只不过是让它们看起来不像自己而像是别的东西。这样就可以在设计中将类的接口转化为想要的接口,以实现同的接口,此外还将讲述另一个模式,将对象包装起来以简化接口。

1.   适配器简介

1.1 面向对象的适配器

真实世界的适配器比如位于美式插头和欧式插座之间的交流电适配器。面向对象的适配器是什么呢?

面向对象的适配器是将一个接口转化成另一个接口,以符合客户的期望。

例如已有的一个软件系统,希望它能和一个新的厂商类库搭配使用,但是这个厂商设计出来的接口不同于旧的接口,而你又不想改变现有的代码,所以这个时候就需要一个适配器来完成现有系统和新的厂商类库的对接。

1.2 使用中的适配器

我们在策略模式里举例讲的鸭子。看一个简化版的示例。

1.2.1 鸭子接口
publicinterface Duck
{
void Quack();//鸭子叫
void Fly();//鸭子飞
}
1.2.2 鸭子子类(绿头鸭)实现
publicclass MallardDuck:Duck
{
public void Quack()
{
Console.WriteLine(" Quack");
}
public void Fly()
{
Console.WriteLine(" Fly");
}
}
1.2.3 新的禽类接口以及具体实现
publicinterface Turkey
{
void Gobble();//咯咯叫
void Fly();//飞
}
publicclass WildTurkey : Turkey
{
public void Gobble()
{
Console.WriteLine(" GobbleGobble");
}
public void Fly()
{
Console.WriteLine(" I'm flyinga short distance ");
}
}
1.2.4 适配器
publicclass TurkeyAdapter:Duck//实现想转换成的类型接口
{
Turkey turkey;
public TurkeyAdapter(Turkey turkey)//取得适配器的对象引用,并利用构造得到这个引用
{
this.turkey = turkey;
} public void Quack()//实现接口中的所有方法
{
turkey.Gobble();
} public void Fly()
{
for(var i=0;i<5;i++)
turkey.Fly();
}
}
1.2.5 测试
MallardDuckduck = new MallardDuck();
WildTurkey turkey = newWildTurkey();
Duck turkeyAdapter = newTurkeyAdapter(turkey); Console.WriteLine(" The turkeysyas ...");
turkey.Gobble();
turkey.Fly(); Console.WriteLine(" The Ducksays ...");
turkeyAdapter.Quack();
turkeyAdapter.Fly(); Console.Read();

结果如下:

1.3 适配器模式解析

客户使用适配器的过程如下:

l  客户通过目标接口调用适配器的方法对适配器发出请求。

l  适配器使用被适配者接口把请求转化成被适配者的一个或多个调用接口。

l  客户接收到调用的结果。

2.   定义适配器模式

适配器模式:将一个类的接口,转化成客户期望的另一个接口。适配器可以让原本接口不兼容的类可以合作无间。

该模式可以通过创建适配器进行接口转换,让不兼容的接口变得兼容,让客户从实现的接口解耦。其类图如下:

该适配器充满了OO设计的原则:使用对象组合,以修改的接口包装被适配者。被是陪者的任何子类都可以搭配着适配器使用。该模式是把客户和接口绑定起来的,而非和实现绑定。

实际上有两种适配器:对象适配器和类适配器。类适配器通过多重继承来实现,而对象适配器利用组合的方式将请求传递给被适配者。

类适配器图:

3.   定义外观模式

外观模式:提供了一个统一的接口,用来访问子系统的一群接口。外观定义了一个高层接口,让子系统更容易使用。

外观模式允许我们让客户和子系统之间避免紧耦合。类图如下:

4.   最少知识原则

最少知识原则:只和你的密友谈话。

最少知识原则告诉我们要减少对象之间的交互。该原则希望在设计时,不要让太多的类耦合在一起,免得修改系统中的一部分,会影响到其他部分。

怎样避免让太多的类耦合在一起呢?主要有以下的方针:

就对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

l  该对象本身

l  被当做方法的参数而传递进来的对象

l  此方法所创建或实例化的任何对象

l  对象的任何组件

如下示例:

(不要采用这个原则)从气象站取得了温度计对象,然后再从温度计对象取得问题

Publicfloat GetTemp()
{
Thermometerthermometer=station.GetThermometer();
return thermometer.GetTemperature();
}

(采用这个原则)我们在气象站中加进一个方法,用来向温度计请求温度。可以减少我们所依赖的类的数据。

Publicfloat GetTemp()
{
Return station.GetTemperature();
}

5.   总结

l  当需要使用一个现有的类而其接口并不符合你的需要时,就需要使用适配器。

l  当需要简化并统一一个很大的接口或者一群负责的接口时,使用外观。

l  适配器改变接口以符合客户的期望。

l  外观将客户从一个复杂的子系统中解耦。

l  实现一个适配器的难易视目标接口的大小与复杂而定。

l  实现一个外观,需要将子系统组合进外观中,然后将工作委托给子系统执行。

l  适配器分为对象适配器和类适配器,类适配器需要多重继承。

l  可以为一个子系统实现一个以上的外观。

l  适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;而外观将一群对象“包装”起来以简化其接口。

Head First 设计模式之适配器模式与外观模式的更多相关文章

  1. 适配器模式和外观模式(head first设计模式——6)

    为什么要把适配器模式和外观模式放在同一篇文章中,主要是其相对前面的几个模式来讲会简单些并且具有相似之处.下面就分别通过例子来看理解一下两种模式,然后再进行对其进行比较. 一.适配器模式 1.1适配器模 ...

  2. 设计模式(九)外观模式Facade(结构型)

    设计模式(九)外观模式Facade(结构型) 1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性. ...

  3. Java设计模式(11)外观模式(Facade模式)

    外观模式(Facade)的定义:为子系统中的一组接口提供一个一致的界面. Facade一个典型应用就是数据库JDBC的应用,如下例对数据库的操作: public class DBCompare { C ...

  4. 设计模式(二)-- 外观模式(Facade)

    设计模式(二) 外观模式(Facade) 为了解决子系统外部的客户端在使用子系统的时候,既能简单地使用这些子系统内部的模块功能,而又不用客户端去与子系统内部的多个模块交互的问题. 为子系统中的一组接口 ...

  5. headfirst设计模式(8)—适配器模式与外观模式

    前言 这一章主要讲2个模式,一个是,适配器模式(负责将一个类的接口适配成用户所期待的),另外一个是外观模式(为子系统提供一个共同的对外接口),看完的第一反应是,为什么要把它们两放在同一章,难道它们有什 ...

  6. 【HeadFirst设计模式】7.适配器模式与外观模式

    今晚学习完第七章,顺便做一下知识备忘. 适配器模模式: 定义:将一个类的接口,转换成客户期望的另一个接口.适配器让原本接口不兼容的类可以合作无间. 对象适配器: 类适配器: 外观模式: 提供了一个统一 ...

  7. 《Head First 设计模式》之适配器模式与外观模式

    适配器模式(Adapter) 适配器(adapter-pattern):将一个类的接口,转换成客户期望的另一个接口.适配器让原来接口不兼容的类可以合作无间.两种形式: 对象适配器(组合) 类适配器(多 ...

  8. 设计模式(十一)外观模式(Facade Pattern)

    一.引言 在软件开发过程中,客户端程序经常会与复杂系统的内部子系统进行耦合,从而导致客户端程序随着子系统的变化而变化,然而为了将复杂系统的内部子系统与客户端之间的依赖解耦,从而就有了外观模式,也称作 ...

  9. 【转】设计模式(九)外观模式Facade(结构型)

    设计模式--外观模式Facade(结构型): 1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性. ...

随机推荐

  1. ios framework 简单制作

    在制作过程中遇到的一些问题跟大家分享下,直接上步骤 制作库有分模拟器框架和真机矿机  如果报错x86_64什么的字眼就是库里面没有包含模拟器框架 模拟器:iPhone4s~5 : i386 iPhon ...

  2. Python学习路程CMDB

    本节内容 浅谈ITIL CMDB介绍 Django自定义用户认证 Restful 规范 资产管理功能开发 浅谈ITIL TIL即IT基础架构库(Information Technology Infra ...

  3. C++关于Condition Variable

    #include <condition_variable> #include <mutex> #include <future> #include <iost ...

  4. Unable to run app in Simulator

    xcode6 beta出现 “Unable to run app in Simulator” 错误提示,之前一直用着好好的,重启xcode就可以了. xcode6 beta出现 “Unable to ...

  5. 13个JavaScript图表(JS图表)图形绘制插件【转】

    现在网络上又有越来越多的免费的(JS 图表)JavaScript图表图形绘制插件.我之前给一家网站做过复杂的图形,我们用的是 highchart.在那段时间,没有很多可供选择的插件.但现在不同了,很容 ...

  6. Android锁屏或灭屏状态下,快速按两次音量下键实现抓拍功能(1.2Framework层使用startService形式实现)

        如前一篇博文所分析,我们可以使用广播的形式在快速按下两次音量下键的时候发出广播,以方便客户端进行捕捉.既然有两种方式可以实现该Issue那么哪种方式是首选呢?     我个人推荐使用启动服务的 ...

  7. Android下使用Properties文件保存程序设置

    原文:http://jerrysun.blog.51cto.com/745955/804789 废话不说,直接上代码.    读取.properties文件中的配置: String strValue ...

  8. Linux 路线 推荐

    1.<Linux程序设计>- 靠它来入门,然后装一个linux体系,练习shell(party)和linuxC,把基础打牢: 2. <深入理解Linux内核>和<Linu ...

  9. strip_tags() 函数

    定义和用法 strip_tags() 函数剥去 HTML.XML 以及 PHP 的标签. 语法 strip_tags(string,allow) 参数 描述 string 必需.规定要检查的字符串. ...

  10. Discuz 7.0版块横排显示版块图标和版块简介的方法

    Discuz 7.0版块横排显示版块图标和版块简介的方法 最近很多朋友咨询Discuz论坛设置论坛版块横排后,如何设置显示版块图标和简介的问题. 一.显示板块图标 找到templates\defaul ...