zoukankan      html  css  js  c++  java
  • 七、适配器模式

    1. 定义

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

    2. UML类图

    说明:

    1、客户看到的是目标接口。
    2、适配器与被适配者组合。
    3、适配器实现目标接口。
    4、所有的请求都委托给配适配者。

    装饰者和适配器模式对比

    • 适配器
    • 装饰者

    说明:

    1、适配器的好处是,允许客户使用行的库和子集合,无须“改变”代码,由适配器负责装换(装饰者同样也可以让“新行为”加入类中,无须修改现有代码)。
    2、适配器“一定会”进行接口转换(装饰者的工作是扩展包装对象的行为或责任)。

    外观模式

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

    • 例子:
      HomeTheaterFacade 类(高层接口)

    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, 
                     Screen screen,
                     TheaterLights lights,
                     PopcornPopper popper) {
    
            this.amp = amp;
            this.tuner = tuner;
            this.dvd = dvd;
            this.cd = cd;
            this.projector = projector;
            this.screen = screen;
            this.lights = lights;
            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(dvd);
            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 void listenToCd(String cdTitle) {
            System.out.println("Get ready for an audiopile experence...");
            lights.on();
            amp.on();
            amp.setVolume(5);
            amp.setCd(cd);
            amp.setStereoSound();
            cd.on();
            cd.play(cdTitle);
        }
    
        public void endCd() {
            System.out.println("Shutting down CD...");
            amp.off();
            amp.setCd(cd);
            cd.eject();
            cd.off();
        }
    
        public void listenToRadio(double frequency) {
            System.out.println("Tuning in the airwaves...");
            tuner.on();
            tuner.setFrequency(frequency);
            amp.on();
            amp.setVolume(5);
            amp.setTuner(tuner);
        }
    
        public void endRadio() {
            System.out.println("Shutting down the tuner...");
            tuner.off();
            amp.off();
        }
    }

    Amplifier类(高层接口需要包装的众多子类之一)

    public class Amplifier {
        String description;
        Tuner tuner;
        DvdPlayer dvd;
        CdPlayer cd;
    
        public Amplifier(String description) {
            this.description = description;
        }
    
        public void on() {
            System.out.println(description + " on");
        }
    
        public void off() {
            System.out.println(description + " off");
        }
    
        public void setStereoSound() {
            System.out.println(description + " stereo mode on");
        }
    
        public void setSurroundSound() {
            System.out.println(description + " surround sound on (5 speakers, 1 subwoofer)");
        }
    
        public void setVolume(int level) {
            System.out.println(description + " setting volume to " + level);
        }
    
        public void setTuner(Tuner tuner) {
            System.out.println(description + " setting tuner to " + dvd);
            this.tuner = tuner;
        }
    
        public void setDvd(DvdPlayer dvd) {
            System.out.println(description + " setting DVD player to " + dvd);
            this.dvd = dvd;
        }
    
        public void setCd(CdPlayer cd) {
            System.out.println(description + " setting CD player to " + cd);
            this.cd = cd;
        }
    
        public String toString() {
            return description;
        }
    }

    测试类

    public class HomeTheaterTestDrive {
        public static void main(String[] args) {
            Amplifier amp = new Amplifier("Top-O-Line Amplifier");
            Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp);
            DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp);
            CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp);
            Projector projector = new Projector("Top-O-Line Projector", dvd);
            TheaterLights lights = new TheaterLights("Theater Ceiling Lights");
            Screen screen = new Screen("Theater Screen");
            PopcornPopper popper = new PopcornPopper("Popcorn Popper");
    
            HomeTheaterFacade homeTheater = new HomeTheaterFacade(amp, tuner, dvd, cd, 
                    projector, screen, lights, popper);
    
            homeTheater.watchMovie("Raiders of the Lost Ark");
            homeTheater.endMovie();
        }
    }

    外观不只是简化了接口,也将客户从组件的子系统中解耦。

    外观和适配器可以包装很多类,但是外观的意图是简化接口,而适配器的意图是将接口转换成不同的接口。

    • 要点
      1、当需要使用一个现有的类而其它接口并不符合你的需要时,就使用适配器。
      2、当需要简化并统一一个很大的接口或者一群复杂的接口的时候,使用外观模式。
      3、适配器改变接口以符合客户的期望。
      4、外观将客户从一个复杂的子系统中解耦。
      5、实现一个适配器可能需要一番功夫,也可能不费功夫,视目标接口的大小与复杂程度而定。
      6、实现一个外观,需要将子系统组合进外观中,而将工作委托给子系统执行。
      7、Java中只存在对象适配器。
      8、可以为一个子系统实现一个以上的外观。
      9、适配器将一个对象包装起来以改变其接口;装饰者将一个对象包装起来以增加新的行为和责任;而外观将一群对象“包装”起来以简化其接口。

    说明:以上智慧参考于HeadFirst书籍,如有必要,请参考原书籍。

  • 相关阅读:
    【原创】大叔问题定位分享(21)spark执行insert overwrite非常慢,比hive还要慢
    【原创】大叔经验分享(14)spark on yarn提交任务到集群后spark-submit进程一直等待
    【原创】大叔问题定位分享(20)hdfs文件create写入正常,append写入报错
    【原创】大叔问题定位分享(19)spark task在executors上分布不均
    【原创】大数据基础之Spark(4)RDD原理及代码解析
    【原创】大叔问题定位分享(18)beeline连接spark thrift有时会卡住
    【原创】大叔问题定位分享(17)spark查orc格式数据偶尔报错NullPointerException
    【原创】大叔经验分享(13)spark运行报错WARN Utils: Service 'sparkDriver' could not bind on port 0. Attempting port 1.
    linux定时任务
    source导入错码解决办法
  • 原文地址:https://www.cnblogs.com/huacesun/p/6622493.html
Copyright © 2011-2022 走看看