zoukankan      html  css  js  c++  java
  • 设计模式之Adapter(适配器模式)

    1、出现原因:

    在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象不满足的。(所以可以在他们之间建立一个适配器的中间类

    2、意图:

    将一个类的接口转换成客户希望的另一个接口。Adapter模式使得原本由接口不兼容而不能一起工作的那些类可以一起工作。(就是在新环境的 接口 和 原来的 类之间 建立一个适配器,将他们联系起来

    3、两种实现适配器模式的方式

    1》对象适配器

    推荐使用,因为相对于下面的类继承的方式耦合度更低 

    结构图:

    1对象适配器采用对象组合,通过引用一个类(原来的类)与另一个类接口(实现新的环境接口) 在对象适配器中通过组合获得Adaptee对象

     

    2、通过调用Adaptee对象的方法,转换后返回Target结果

    2》类的多继承方式

    不推荐使用,因为使用继承实现的,对象之间的耦合度 过高

     结构图:

    1、类适配器通过多继承对一个接口与另一个接口进行匹配。

     

    2Target定义了Client使用的与特定领域相关的接口,Client通过调用Target实现某一个特定的操作。Adaptee是一个已经存在的类,需要与Target协同工作,这个接口需要适配。Adapter适配器适配AdapteeTarget接口。在类适配器中,通过继承获得Adaptee中的方法。

     

    3、.NET不支持多重继承,因此当Target是一个类,而不是一个接口时无法实现类适配器,这时需要使用对象适配器。(如果,Target是抽象类的话,就不行了,因为 适配器在 c#里面是不支持多继承的),所以Target要是 接口,因为旧的系统已经继承了

    4、代码演示

    实现需求如下图:

    实现代码:

      1     //新的环境(.Net不支持多继承,所以要使用接口),一个新的环境一个接口(然后 适配器 实现多个接口)
      2     public interface FootballPlayer
      3     {
      4         void Attact();
      5         void Defende();
      6     }
      7 
      8     public class FQianFeng : FootballPlayer
      9     {
     10         public void Attact()
     11         {
     12             Console.WriteLine("我是足球前锋,我要进攻了");
     13         }
     14 
     15         public void Defende()
     16         {
     17             Console.WriteLine("我是足球前锋,我要防守了");
     18         }
     19     }
     20 
     21 
     22     public class FZhongFeng : FootballPlayer
     23     {
     24         public void Attact()
     25         {
     26             Console.WriteLine("我是足球中锋,我要进攻了");
     27         }
     28 
     29         public void Defende()
     30         {
     31             Console.WriteLine("我是足球中锋,我要防守了");
     32         }
     33     }
     34 
     35     public class FHouWei : FootballPlayer
     36     {
     37         public void Attact()
     38         {
     39             Console.WriteLine("我是足球后卫,我要进攻了");
     40         }
     41 
     42         public void Defende()
     43         {
     44             Console.WriteLine("我是足球后卫,我要防守了");
     45         }
     46     }
     47 
     48 
     49     //另一个新的环境 接口
     50     public interface BasketBallPlayer
     51     {
     52         void JinGong();
     53         void FangShou();
     54     }
     55 
     56     public class BQianFeng : BasketBallPlayer
     57     {
     58         public void JinGong()
     59         {
     60             Console.WriteLine("我是篮球前锋,我要进攻了");
     61         }
     62 
     63         public void FangShou()
     64         {
     65             Console.WriteLine("我是篮球前锋,我要防守了");
     66         }
     67     }
     68 
     69 
     70 
     71     //要被适配的 类(Adaptee)
     72     //中国运动员:既会 打篮球,又会  踢足球
     73     public class ChinesePlayer
     74     {
     75         public void 足球进攻()
     76         {
     77             Console.WriteLine("我是中国运动员,我要进行足球进攻了");
     78         }
     79         public void 足球防守()
     80         {
     81             Console.WriteLine("我是中国运动员,我要进行足球防守了");
     82         }
     83         public void 篮球进攻()
     84         {
     85             Console.WriteLine("我是中国的运动员,我要进行篮球进攻了");
     86         }
     87         public void 篮球防守()
     88         {
     89             Console.WriteLine("我是中国的运动员,我要进行篮球防守了");
     90         }
     91     }
     92 
     93 
     94 
     95     //下面是一个 Adapter适配器的类
     96     public class Adapter : FootballPlayer, BasketBallPlayer  
     97     {
     98         //其实这里举的例子不适当,因为 是  先有  旧的系统(Adaptee被适配对象),才有新的环境。而且是 新的环境要使用旧的系统,才不得已使用适配器模式,,而且两个 新的环境 使用的 同一 旧的系统(也就是使用的同一 对象)
     99 
    100         ChinesePlayer player = new ChinesePlayer();//这里使用的是  对象组合的方式  实现的 适配器模式
    101         public void Attact()
    102         {
    103             player.足球进攻();
    104         }
    105 
    106         public void Defende()
    107         {
    108             player.足球防守();
    109         }
    110 
    111         public void JinGong()
    112         {
    113             player.篮球进攻();
    114         }
    115 
    116         public void FangShou()
    117         {
    118             player.篮球防守();
    119         }
    120     }
    Adapter模式

    客户端代码:

     1             //第一个环境  使用旧的对象
     2             FootballPlayer footPlayer = new FQianFeng();
     3             FootballPlayer footChinesePlayer = new Adapter();
     4             footPlayer.Attact();
     5             footPlayer.Defende();
     6             footChinesePlayer.Attact();
     7             footChinesePlayer.Defende();
     8 
     9             //第二个环境 使用旧的对象
    10             BasketBallPlayer basQianFeng = new BQianFeng();
    11             BasketBallPlayer basChinesePlayer = new Adapter();
    12             basQianFeng.JinGong();
    13             basQianFeng.FangShou();
    14             basChinesePlayer.JinGong();
    15             basChinesePlayer.FangShou();
    客户端调用代码

    其实适配器 起的 作用就是承上启下的作用。承上实现新的环境的接口,然后在新的接口对应方法的地方调用旧的对象的方法实现想要的 旧对象的 功能。

    启下:通过旧对象的引用(对象组合的方式)调用对应的功能方法,或者 通过 继承 旧对象(类的多继承),然后调用 旧对象 的功能方法

    5、.Net中的适配器模式

    1、DataAdapter:数据适配器

     

    2、DataAdpter使应用程序的数据(sql里面的)操作统一到DataSet上,而与具体的数据库类型无关(sql 是早就存在的,要将sql里面的 统一到 Dataset上面,所以就通过 DataAdapter这个中间适配器

    6、实现要点

    1适配器模式重在转换接口,它能够使原本不能在一起工作的两个类一起工作,所以经常用在类库复用,代码迁移等方面,有一种亡羊补牢的味道(但是,不要硬要套这种模式如果在设计一个类库的时候,就已经想到以后会进行扩展,那么就应该提前做好准备。因为这种模式毕竟是一种 弥补措施

     

    2类适配器和对象适配器可以根据具体实际情况来选用,但一般情况建议使用对象适配器模式(耦合度较低)

    7、效果

    通过类的继承(类适配器)或者对象的组合(对象适配器)转换已有的接口为目标接口

    8、适用性

    1需要使用一个已经存在的类,但接口与设计要求不符

     

    2、希望创建一个可以复用的类,该类可以与其他不相关的类或者是将来不可预见的类协同工作

    9、总结

    1Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用环境要求不一致的情况” ,在遗留代码复用、类库迁移等方面非常有用。

     

    2GoF 23 定义了两种Adapter模式的实现结构:对象适配器和类适配器。但类适配器采用“多继承”的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神

     

    3Adapter模式可以实现的非常灵活不必拘泥于Gof23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象”作为新的接口方法参数(接口里定义一个重载方法:例如:上面那个例子:可以增加一个重载方法void AttackChineseRearguard rearguard),然后在适配器里面进行实现,执行 现存类要执行的事务),来达到适配的目的

    Adapter模式本身要求我们尽可能地使用“面向接口的编程”风格(切记千万不能面向实现编程),这样才能在后期很方便地适配。

  • 相关阅读:
    版本控制之GitHub亲手实验总结
    Java的HashMap是如何实现的?
    Junit
    由swap引发的关于按值传递和引用传递的思考与总结
    C++了解free和delete
    GitHub使用教程
    Oracle下SQL学习笔记
    Flappy Bird
    尾递归与Continuation(转载)
    十步完全理解SQL(转载)
  • 原文地址:https://www.cnblogs.com/xiaoxiaogogo/p/3585072.html
Copyright © 2011-2022 走看看