ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

适配器模式与外观模式

2019-03-28 19:48:55  阅读:235  来源: 互联网

标签:外观 void 接口 public 模式 amp new 适配器


适配器GitHub代码
外观GitHub代码

适配器模式

场景描述:想象一下我们维护了一套老系统,并于一个厂商通过接口进行交互。但是最近厂商更新它们的代码,并变更了接口格式,我们如何在不修改老系统代码的基础上,优雅的过渡呢?

提出方案:我们可以想象一下我们平时使用的转换头,这就是一种适配器。我们可以通过这种方式来优雅的“将方形放入圆形中”。

我们尝试举一个例子,假设现在有一个鸭子接口

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");
    }
}

接着我们有另一个火鸡接口

public interface Turkey {
    public void gobble();
    public void fly();
}

以及一个实现

public class WildTurkey implements Turkey {
    @Override
    public void gobble() {
        System.out.println("Gobble gobble");
    }

    @Override
    public void fly() {
        System.out.println("I'm flying a short distance");
    }
}

我们如何能够将火鸡作为鸭子呢?可以提供一个适配器来做接口的转换

public class TurkeyAdapter implements Duck {
    Turkey turkey;

    public TurkeyAdapter(Turkey turkey){
        this.turkey = turkey;
    }

    @Override
    public void quack() {
        turkey.gobble();
    }

    @Override
    public void fly() {
        for (int i = 0; i < 5; i++){
            turkey.fly();
        }
    }
}

然后我们测试一下

public class DuckTestDrive {
    public static void main(String[] args) {
        MallardDuck duck = new MallardDuck();
        WildTurkey turkey = new WildTurkey();

        Duck turkeyAdapter = new TurkeyAdapter(turkey);

        System.out.println("The Turkey says...");
        turkey.gobble();
        turkey.fly();

        System.out.println("\nThe Duck says...");
        testDuck(duck);

        System.out.println("\nThe TurkeyAdapter says...");
        testDuck(turkeyAdapter);
    }

    static void testDuck(Duck duck){
        duck.quack();
        duck.fly();
    }
}

可以通过结果看到我们现在将这个火鸡作为一只鸭子的实现了。
在这里插入图片描述

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

我们看一下它的类图
在这里插入图片描述
实现一个适配器所需要进行的工作,和目标接口的大小成正比。

由于Java不支持多继承,所以适配器又分为“对象”适配器(Java)和“类”适配器(支持多继承的其他语言)。

再看一下“类”适配器的类图
在这里插入图片描述

外观模式

场景描述:我们现在有一个家庭影院,其中包含了DVD,投影机,自动屏幕,立体环绕声等等,每当我们想要看电影的时候,都需要进行一系列操作;而看完电影时,又需要反向再操作一遍。

改进方案:我们尝试进行一种近似流水线的改造,通过将一系列操作变成一个更加高层的操作。

如下是我们的改进方案的代码

public class HomeTheaterFacade {
    Amplifier amp;
    Tuner tuner;
    DvdPlayer dvd;
    CdPlayer cd;
    Projector projector;
    TheaterLights lights;
    Screen screen;
    PopcornPopper popper;

    public HomeTheaterFacade(Amplifier amp, Tuner tuner, DvdPlayer dvd, CdPlayer cd, Projector projector, TheaterLights lights, Screen screen, PopcornPopper popper){
        this.amp = amp;
        this.tuner = tuner;
        this.dvd = dvd;
        this.cd = cd;
        this.projector = projector;
        this.lights = lights;
        this.screen = screen;
        this.popper = popper;
    }

    public void watchMovie(String movie){
        System.out.println("Get ready to watch a movie...");
        popper.on();
        popper.pop();
        lights.dim(10);
        screen.down();
        projector.on();
        projector.wideScreenMode();
        amp.on();
        amp.setDvd();
        amp.setSurroundSound();
        amp.setVolume(5);
        dvd.on();
        dvd.play(movie);
    }

    public void endMovie(){
        System.out.println("Shutting movie theater down...");
        popper.off();
        lights.on();
        screen.up();
        projector.off();
        amp.off();
        dvd.stop();
        dvd.eject();
        dvd.off();
    }

这样我们测试一下,只可以通过一步操作就完成之前的一系列操作

public class HomeTheaterTestDrive {
    public static void main(String[] args) {
        Amplifier amp = new Amplifier();
        Tuner tuner = new Tuner();
        DvdPlayer dvd = new DvdPlayer();
        CdPlayer cd = new CdPlayer();
        Projector projector = new Projector();
        Screen screen = new Screen();
        TheaterLights lights = new TheaterLights();
        PopcornPopper popper = new PopcornPopper();

        HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, tuner, dvd, cd, projector, lights, screen, popper);

        homeTheater.watchMovie("Raiders of the Lost Ark");
        System.out.println("\n-----------Watching Movies------------\n");
        homeTheater.endMovie();
    }
}

结果如下
在这里插入图片描述

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

外观模式有一个很好的特征:提供简化的接口的同时,依然将系统完整的功能暴露出来,以供需要的人使用。
以下是它的类图
在这里插入图片描述
适配器模式的意图是,“改变”接口符合客户的期望;而外观模式的意图是,提供子系统的一个简化接口。
我们将装饰者模式、适配器模式、外观模式一同比较,可以看出它们的意图分别为:

  • 装饰者模式,不改变接口,但加入职责
  • 适配器模式,将一个接口转成另一个接口
  • 外观模式,让接口更简单

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

当你正在设计一个系统,不管是任何对象,你都要注意它所交互的类有哪些,并注意它和这些类是如何交互的。
这个原则又名墨忒耳法则,它希望我们在设计中,不要让太多的类耦合在一起,免得修改系统中一部分,会影响到其他部分。

这个原则提供了一些方针:就任何对象而言,在该对象的方法内,我们只应该调用属于以下范围的方法:

  • 该对象本身
  • 被当作方法的参数而传递进来的对象
  • 此方法所创建或实例化的任何对象
  • 对象的任何组件

如果调用从另一个调用中返回的对象的方法,会有什么害处呢?如果我们这样做,相当于向另一个对象的子部分发请求(而增加我们直接认识的对象数目)。
在这里插入图片描述
这个原则的缺点是,采用这个原则会导致更多的“包装”类被制造出来,以处理和其他组件的沟通,这可能会导致复杂度和开发时间的增加,并降低运行时的性能。

总结如下:当我们需要从一个接口“转变”为另一个接口时,可以尝试使用适配器;而当我们想要将子系统的一系列操作简化时,可以使用外观模式。

标签:外观,void,接口,public,模式,amp,new,适配器
来源: https://blog.csdn.net/Ybt_c_index/article/details/88875488

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有