参考链接:http://www.cnblogs.com/zhili/p/AdapterPattern.html
一、定义:
将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。
适配器模式有类的适配器模式和对象的适配器模式两种形式。

二、类的适配器模式实现(不推荐,违反了类的单一职责原则)

using System;

/// 这里以插座和插头的例子来诠释适配器模式
/// 现在我们买的电器插头是2个孔,但是我们买的插座只有3个孔的
/// 这是我们想把电器插在插座上的话就需要一个电适配器
namespace 设计模式之适配器模式
{
/// <summary>
/// 客户端,客户想要把2个孔的插头 转变成三个孔的插头,这个转变交给适配器就好
/// 既然适配器需要完成这个功能,所以它必须同时具体2个孔插头和三个孔插头的特征
/// </summary>
class Client
{
static void Main(string[] args)
{
// 现在客户端可以通过电适配要使用2个孔的插头了
IThreeHole threehole = new PowerAdapter();
threehole.Request();
Console.ReadLine();
}
} /// <summary>
/// 三个孔的插头,也就是适配器模式中的目标角色
/// </summary>
public interface IThreeHole
{
void Request();
} /// <summary>
/// 两个孔的插头,源角色——需要适配的类
/// </summary>
public abstract class TwoHole
{
public void SpecificRequest()
{
Console.WriteLine("我是两个孔的插头");
}
} /// <summary>
/// 适配器类,接口要放在类的后面
/// 适配器类提供了三个孔插头的行为,但其本质是调用两个孔插头的方法
/// </summary>
public class PowerAdapter:TwoHole,IThreeHole
{
/// <summary>
/// 实现三个孔插头接口方法
/// </summary>
public void Request()
{
// 调用两个孔插头方法
this.SpecificRequest();
}
}
}

从上面代码中可以看出,客户端希望调用Request方法(即三个孔插头),但是我们现有的类(即2个孔的插头)并没有Request方法,它只有SpecificRequest方法(即两个孔插头本身的方法),然而适配器类(适配器必须实现三个孔插头接口和继承两个孔插头类)可以提供这种转换,它提供了Request方法的实现(其内部调用的是两个孔插头,因为适配器只是一个外壳罢了,包装着两个孔插头(因为只有这样,电器才能使用),并向外界提供三个孔插头的外观,)以供客户端使用。

PowerAdapter类同时继承TwoHole和IThreeHole,既可以使用TwoHole里的方法,也可以使用IThreeHole接口里的方法,这样就感觉有点不伦不类的,违反了类的单一职责原则,它既有TwoHole的职责,也有IThreeHole职责,因此这种类适配器不是很常用,也不推荐使用。
三、对象的适配器模式实现

namespace 对象的适配器模式
{
class Client
{
static void Main(string[] args)
{
// 现在客户端可以通过电适配要使用2个孔的插头了
ThreeHole threehole = new PowerAdapter();
threehole.Request();
Console.ReadLine();
}
} /// <summary>
/// 三个孔的插头,也就是适配器模式中的目标(Target)角色
/// </summary>
public class ThreeHole
{
// 客户端需要的方法
public virtual void Request()
{
// 可以把一般实现放在这里
}
} /// <summary>
/// 两个孔的插头,源角色——需要适配的类
/// </summary>
public class TwoHole
{
public void SpecificRequest()
{
Console.WriteLine("我是两个孔的插头");
}
} /// <summary>
/// 适配器类,这里适配器类没有TwoHole类,
/// 而是引用了TwoHole对象,所以是对象的适配器模式的实现
/// </summary>
public class PowerAdapter : ThreeHole
{
// 引用两个孔插头的实例,从而将客户端与TwoHole联系起来
public TwoHole twoholeAdaptee = new TwoHole(); /// <summary>
/// 实现三个孔插头接口方法
/// </summary>
public override void Request()
{
twoholeAdaptee.SpecificRequest();
}
}
}

如果一个方法有可能要委托到两个或两个以上的对象,或者两个或两个以上的类需要委托,对于对象适配器,只需要增加几个内部的属性就可以实现适配器模式了。而对于类适配器模式,因为C#中类只能是单一继承,它不能继承自两个或两个以上的类,所有类适配器无法使用。
四、适配器模式的优缺点
类的适配器模式:
优点:
可以在不修改原有代码的基础上来复用现有类,很好的符合“开闭原则”
可以重新定义Adapter的部分行为,因为在类适配器模式中,Adapter是引用Adapter的子类
仅仅引入一个对象,并不需要额外的字段来引用Adapter实例(这个即是优点也是缺点)。
缺点:
用一个具体的Adapter类对Adapter和Target进行匹配,当如果想要匹配一个类以及所有它的子类时,类的适配器模式就不能胜任了。因为类的适配器模式中没有引入Adapter的实例,光调用this.SpecificRequest方法并不能去调用它对应子类的SpecificRequest方法。
采用了 “多继承”的实现方式,带来了不良的高耦合。

对象的适配器模式
优点:
可以在不修改原有代码的基础上来复用现有类,很好地符合 “开闭原则”(这点是两种实现方式都具有的)
采用 “对象组合”的方式,更符合松耦合。
缺点:
使得重定义Adapter的行为较困难,这就需要生成Adapter的子类并且使得Adapter引用这个子类而不是引用Adapter本身。

五、使用场景
在以下情况下可以考虑使用适配器模式:
系统需要复用现有类,而该类的接口不符合系统的需求
想要建立一个可重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
对于对象适配器模式,在设计里需要改变多个已有子类的接口,如果使用类的适配器模式,就要针对每一个子类做一个适配器,而这不太实际。

六、.NET框架中的Adapter应用
1.在.NET中复用COM对象:
-COM对象不符合.NET对象的接口,使用tlbimp.exe来创建一个Runtime Callable Wrapper(RCW)以使其符合.NET对象的接口
2..NET数据访问类(Adapter变体):
-各种数据库并没有提供DataSet接口,使用DbDataAdapter可以将任何个数据库访问/存取适配到一个DataSet对象上
DbDataAdapter dataAdapter = new SqlDataAdapter();
DataSet dataSet = new DataSet();
dataAdapter.Fill(dataSet);
微软把适配器和被适配的对象分离了,这和上面的模式有点不同,但是原理都是一样的,如果是写成下面的样子,就比较好理解了。
class DataSet
{
DataAdapter dataAdapter;
public DataSet(DbDataAdapter dataAdapter)
{
this.DataTable = dataAdapter.Fill();
}
}
DataSet就是一个适配器
DataSet dataSet = new DataSet(new SqlDataAdapter());
把适配对象直接作为参数传递一样是一种很好的做法。

设计模式学习之适配器模式(Adapter,结构型模式)(14)的更多相关文章

  1. 设计模式06: Adapter 适配器模式(结构型模式)

    Adapter 适配器模式(结构型模式) 适配(转换)的概念无处不在:电源转接头.电源适配器.水管转接头... 动机(Motivation)在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象 ...

  2. .NET设计模式(15):结构型模式专题总结(转)

    摘要:结构型模式,顾名思义讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能(对象结构型模式).这些结构型模式,它们在某些方面具有很大的相似 ...

  3. Java设计模式06:常用设计模式之适配器模式(结构型模式)

    1. Java之适配器模式(Adapter Pattern) (1)概述:    将一个类的接口转换成客户希望的另外一个接口.Adapter模式使得原本由于接口不兼容而不能一起工作的那些类,可以在一起 ...

  4. 适配器模式 adapter 结构型 设计模式(九)

    现实世界中的适配器模型   先来看下来几个图片,截图自淘宝 上图为港版的插头与港版的插座   上图为插座适配器卖家的描述图   上图为适配后的结果 现实世界中适配器模式 角色分类 这就是适配器模式在电 ...

  5. C#设计模式--适配器模式(结构型模式)

    一.适配器模式介绍: 适配器模式:将一个类的接口,转换成客户希望的另外一个接口.adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作 例子分析(充电器充电): 模式中的角色: 安 ...

  6. Java设计模式——结构型模式

    Java设计模式中共有7种结构型模式:适配器模式.装饰模式.代理模式.外观模式.桥接模式.组合模式.享元模式.其中对象的适配器模式是各种模式的起源,其关系如下面的图:1.适配器模式 适配器模式将某个类 ...

  7. Java设计模式学习记录-适配器模式

    前言 之前已经将五个创建型设计模式介绍完了,从这一篇开始介绍结构型设计模式,适配器模式就是结构型模式的一种,适配器要实现的效果是把“源”过渡到“目标”. 适配器模式 在开发过程中,使用一个已经存在的类 ...

  8. NET设计模式 第三部分 结构型模式(7):适配器模式(Adapter Pattern)

    适配器模式(Adapter Pattern) ——.NET设计模式系列之八 Terrylee,2006年2月 概述 在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但 ...

  9. 初探Java设计模式2:结构型模式(代理模式,适配器模式等)

    行为型模式 行为型模式关注的是各个类之间的相互作用,将职责划分清楚,使得我们的代码更加地清晰. 策略模式 策略模式太常用了,所以把它放到最前面进行介绍.它比较简单,我就不废话,直接用代码说事吧. 下面 ...

  10. 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)

    结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题.   结构 ...

随机推荐

  1. php中0," ",null和false的区别

    php中很多还不懂php中0,"",null和false之间的区别,这些区别有时会影响到数据判断的正确性和安全性,给程序的测试运行造成很多麻烦.先看一个例子: <? $str ...

  2. C#高级编程笔记 Day 1, 2016年8月 30日 名词定义

    1.C# 中的命名空间 namespace,我觉得和Java中的package 差不多,相当于一个"包" 一样. 2.修饰符 static 修饰方法表示方法不能在类的实例化上执行, ...

  3. HTML页面关键词随机分布布局

    结合underscore-min.js,和D3.js 绘制HTML关键词随机分布 <!DOCTYPE html> <html> <head> <meta ch ...

  4. bootstrap 响应式布局

    先上点媒体查询css(某个著名的”段子“),跟bootstrap无关: <html> <head> <style> body { background-color: ...

  5. Tomcat部署Web应用的两种方式

    WEB工程目录结构 部署方式一:此种方式部署,jsp页面修改后,不能动态更新,需要重新部署才能看到效果.不过可以配置动态更新实现. 部署方式二:此种方式部署,jsp修改后,直接在页面可以看到效果.(因 ...

  6. js的工作原理

    JavaScript就是所谓的客户端脚本语言,是一种在互联网浏览器(浏览器也称为Web客户端,因为它连接到Web服务器上,以下载页面)内部运行的计算机编程语言. 也就是说,如果一个网页里有js代码,那 ...

  7. How to keep Environment Variables when Using SUDO

    The trick is to add environment variables to sudoers file via sudo visudo command and add these line ...

  8. Git的维护(git gc和git fsck)

    原文: http://gitbook.liuhui998.com/4_10.html 一.保证git良好的性能 在大的仓库中, git靠压缩历史信息来节约磁盘和内存空间. 压缩操作并不是自动进行的, ...

  9. win7桌面背景地址

    C:\Users\你的用户名\AppData\Local\Microsoft\Windows\Themes\Alaskan L\DesktopBackground

  10. 22. javacript高级程序设计-高级技巧

    1. 高级技巧 1.1 函数 l 可以使用惰性载入函数,将任何分支推迟到第一个调用函数的时候 l 函数绑定可以让你创建始终在指定环境中运行的函数,同时函数柯里化可以让你创建已经填写了某些参数的函数 l ...