zoukankan      html  css  js  c++  java
  • 浅析设计模式(七)——适配器模式

    适配器模式(Adapter,结构型模式)

    本文的结构

    一、适配器模式的定义

      定义:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

      简单点理解:转换接口,进行适配。

      从适配的方式来看,有2种可行的方式,即【类的适配器】和【对象的适配器】,换个说法就是【继承(接口实现)】和【组合】,两者的效果如下

    继承(接口实现,is-a):

    • 用一个具体的Adapter类对Adaptee和Target进行匹配,但无法匹配Adaptee的子类
    • 作为Adaptee的子类,Adapter可重新定义Adaptee的部分行为

    组合(has-a)

    • 允许一个Adapter与多个Adaptee(其本身或者所有子类)一起工作
    • 重新定义Adaptee的行为会比较困难,需要生成Adaptee的子类并且使得Adapter引用这个子类。

      Java是单继承(类),多实现(接口)。在使用时,需要根据实际情况进行考虑。比如说,Adaptee和Target都是类,无法多重继承,就只能使用对象的适配器;如果需要使用到一群子类,使用对象的适配器进行组合(子类的父接口)会更加合适;如果仅仅是适配一个第三方接口,可以使用类的适配器进行适配,也可以使用对象的适配器进行适配。

      举个不恰当的例子:spring工程中常见的service,也会调用到其他的service,可以看成是最简单粗暴的一种代理。。。

    二、适配器模式的参与者及其角色

    1. Target

    • 定义Client使用的与特定领域相关的接口,即目标接口

    2. Client

    • 与符合Target接口的对象协同。

    3. Adaptee

    • 定义一个已经存在的接口,这个接口需要适配

    4. Adapter

    • 对Adaptee的接口与Target接口进行适配

    三、适配器模式的类图

    类的适配器模式:

    对象的适配器模式:

    四、适配器模式的示例

       下面使用对象的适配器进行简单地说明。

      这里有鸭子类和火鸡类,可以通过适配器将鸭子适配(伪装)成火鸡进行调用,反过来也可以将火鸡适配(伪装)成鸭子进行调用。

    1. Target 和 3. Adaptee

      鸭子类和火鸡类是需要相互进行适配的类。

    鸭子及其实现类:

    // 鸭子接口
    public interface Duck {
        public void quack();
        public void fly();
    }
    
    // 鸭子实现类
    public class MallardDuck implements Duck {
        @Override
        public void quack() {
            System.out.println("Quack");
        }
    
        @Override
        public void fly() {
            System.out.println("I'm flying");
        }
    }

    火鸡及其实现类

     1 // 火鸡接口
     2 public interface Turkey {
     3     public void gobble();
     4     public void fly();
     5 }
     6 
     7 // 实现类
     8 public class WildTurkey implements Turkey {
     9     @Override
    10     public void gobble() {
    11         System.out.println("Gobble gobble");
    12     }
    13 
    14     @Override
    15     public void fly() {
    16         System.out.println("I'm flying a short distance");
    17     }
    18 }

     2. Client

      这里看成是正常的客户端调用,可以看到将火鸡Turkey进行适配包装后,可以和调用鸭子Duck一样调用适配后的火鸡。

    鸭子Duck

     1 public class DuckTestDrive {
     2     public static void main(String[] args) {
     3         Duck duck = new MallardDuck();
     4 
     5         Turkey turkey = new WildTurkey();
     6         Duck turkeyAdapter = new TurkeyAdapter(turkey);
     7 
     8         System.out.println("The Turkey says...");
     9         turkey.gobble();
    10         turkey.fly();
    11 
    12         System.out.println("
    The Duck says...");
    13         testDuck(duck);
    14 
    15         System.out.println("
    The TurkeyAdapter says...");
    16         testDuck(turkeyAdapter);
    17     }
    18 
    19     static void testDuck(Duck duck) {
    20         duck.quack();
    21         duck.fly();
    22     }
    23 }

    火鸡Turkey

    public class TurkeyTestDrive {
        public static void main(String[] args) {
            Duck duck = new MallardDuck();
            Turkey duckAdapter = new DuckAdapter(duck);
     
            for(int i=0;i<10;i++) {
                System.out.println("The DuckAdapter says...");
                duckAdapter.gobble();
                duckAdapter.fly();
            }
        }
    }

    4. Adapter

      火鸡适配成鸭子:

     1 public class TurkeyAdapter implements Duck {
     2     Turkey turkey;
     3 
     4     public TurkeyAdapter(Turkey turkey) {
     5         this.turkey = turkey;
     6     }
     7 
     8     public void setTurkey(Turkey turkey) {
     9         this.turkey = turkey;
    10     }
    11 
    12     @Override
    13     public void quack() {
    14         turkey.gobble();
    15     }
    16 
    17     @Override
    18     public void fly() {
    19         for (int i = 0; i < 5; i++) {
    20             turkey.fly();
    21         }
    22     }
    23 }

      鸭子适配成火鸡:

     1 public class DuckAdapter implements Turkey {
     2     Duck duck;
     3     Random rand;
     4 
     5     public DuckAdapter(Duck duck) {
     6         this.duck = duck;
     7         rand = new Random();
     8     }
     9 
    10     public void setDuck(Duck duck) {
    11         this.duck = duck;
    12     }
    13 
    14     @Override
    15     public void gobble() {
    16         duck.quack();
    17     }
    18 
    19     @Override
    20     public void fly() {
    21         if (rand.nextInt(5) == 0) {
    22             duck.fly();
    23         }
    24     }
    25 }

      由此可以看到接口的适配和转换。

    五、参考

    1、参考《Head First设计模式》和GoF《设计模式:可复用面向对象软件的基础》

    2、代码可参考【github传送门】、UML类图参考【github传送门

  • 相关阅读:
    测试的基本方法
    一些基本常用的正则表达式
    MySQL和Oracle的区别与不同
    Ubuntu中使用python3中的venv创建虚拟环境
    在Ubuntu中搭建Python3的虚拟环境并开始django项目
    Django中的图片加载不出来解决方式记录
    在django中进行后台管理时插入外键数据时不显示值的问题
    Django2.2连接mysql数据库出现django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None问题
    在Ubuntu中安装了MongoDB后无法启动mongod的问题
    PostgreSQL练习3
  • 原文地址:https://www.cnblogs.com/wpbxin/p/9827532.html
Copyright © 2011-2022 走看看