设计模式之外观模式

 外观模式介绍:外观模式(Facade),也叫"过程模式", 外观模式为子系统中的一组接口提供一个一致的界面,此模式定了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式通过定义一个一致的接口,用以屏蔽内部子雄他那个的细节,使得调用端只需要跟这个接口发生调用,而不需关心这个子系统的内部细节。

外观模式的原理类图如下:

 

 

 有一个外观类,里面聚合了各个子系统,然后Client客户端依赖使用这个外观类。

外观类(Facade):为调用端提供统一的调用接口,外观类知道哪些子系统负责处理请求。从而将调用端的请求代理给子系统对象。

调用者类(Client) :外观接口调用者

子系统的集合:指模块或者子系统,处理Facade对象指派的一个任务,他是功能的实际提供者。

 

创建一个家庭影院的项目,DVD播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求用java完成家庭影院的功能。

使用过程:

1、直接用遥控器,统筹各种设备开关

2、开爆米花机

3、放下屏幕

4、开投影仪

5、升音响

6、开DVD, 选dvd

7、去拿爆米花

8、调暗灯光

9、播放

10、观影结束关闭各种设备

 

如果用传统方式解决的话,大家容易想到的是,创建出一系列的遥控器类,每个遥控器类控制不同的功能,但是这样势必会造成遥控器类非常多。如下

 

那么以上解决方案的主要问题如下:

1、子系统对象非常多,操作步骤多,会造成调用过程混乱,没有清晰的过程。

2、不利于在ClientTest中去维护子系统的操作。如果各个子系统需要修改,造成ClientTest也需要跟着修改。

 

解决思路:

定义一个高层接口,给子系统的一组接口提供一个一致的界面(比如在高层接口提供ready,play,pause,end),用来访问子系统中的一群接口。也就是定义一个一致的接口(界面类),用以屏蔽子系统的细节,使得调用端只跟整个接口发生调用,而无需关心这个子系统的内部细节。=》引入外观模式。

 

代码实现:

TheaterLight.java

public class TheaterLight {
    private static TheaterLight theaterLight = new TheaterLight();
    public static TheaterLight getInstance(){
        return theaterLight;
    }
    public void on(){
        System.out.println("theaterLight on");
    }
    public void off(){
        System.out.println("theaterLight off");
    }
    public void dim(){
        System.out.println("theaterLight dim");
    }
    public void bright(){
        System.out.println("theaterLight bright");
    }
}

Stereo.java

public class Stereo {
    private static Stereo stereo = new Stereo();
    public static Stereo getInstance(){
        return stereo;
    }
    public void on(){
        System.out.println("Stereo on");
    }
    public void off(){
        System.out.println("Stereo off");
    }
    public void up(){
        System.out.println("Stereo up");
    }
    public void down(){
        System.out.println("Stereo down");
    }
}

Screen.java

public class Screen {
    private static Screen screen = new Screen();
    public static Screen getInstance(){
        return screen;
    }
    public void up(){
        System.out.println("Screen up");
    }
    public void down(){
        System.out.println("Screen down");
    }
}

Projector.java

public class Projector {
    private static Projector projector = new Projector();
    public static Projector getInstance(){
        return projector;
    }
    public void on(){
        System.out.println("Projector on");
    }
    public void off(){
        System.out.println("Projector off");
    }
    public void focus(){
        System.out.println("Projector is focusing");
    }
}

Popcorn.java

public class Popcorn {
    private static Popcorn popcorn = new Popcorn();
    public static Popcorn getInstance(){
        return popcorn;
    }
    public void on(){
        System.out.println("Popcorn on");
    }
    public void off(){
        System.out.println("Popcorn off");
    }
    public void pop(){
        System.out.println("Popcorn is poping");
    }
}

DVDPlayer.java

public class DVDPlayer {
    private static DVDPlayer instance = new DVDPlayer();
    public static DVDPlayer getInstance(){
        return instance;
    }
    public void on(){
        System.out.println("dvd on");
    }
    public void off(){
        System.out.println("dvd off");
    }
    public void play(){
        System.out.println("dvd is playing");
    }
    public void pause(){
        System.out.println("dvd is pausing");
    }
}

HomeTheaterFacade.java

public class HomeTheaterFacade {
    //定义各个子系统的对象
    private TheaterLight theaterLight;
    private Popcorn popcorn;
    private Stereo stereo;
    private Projector projector;
    private Screen screen;
    private DVDPlayer dvdPlayer;

    //构造器
    public HomeTheaterFacade() {
        super();
        this.theaterLight = TheaterLight.getInstance();
        this.popcorn = Popcorn.getInstance();
        this.stereo = Stereo.getInstance();
        this.projector = Projector.getInstance();
        this.screen = Screen.getInstance();
        this.dvdPlayer = DVDPlayer.getInstance();
    }

    //操作分为4个步骤
    public void ready(){
        //爆米花机打开
        popcorn.on();
        //爆米花机工作
        popcorn.pop();
        //屏幕放下
        screen.down();
        //投影仪打开
        projector.on();
        //立体声打开
        stereo.on();
        //dvd打开
        dvdPlayer.on();
        //灯光调暗
        theaterLight.dim();
    }

    //开始播放
    public void play(){
        dvdPlayer.play();
    }
    //停止
    public void pause(){
        dvdPlayer.pause();
    }
    //结束
    public void end(){
        //爆米花机关闭
        popcorn.off();
        //灯光打开
        theaterLight.bright();
        //屏幕升起来
        screen.up();
        //关闭投影仪
        projector.off();;
        //立体声关闭
        stereo.off();
        //关闭dvd
        dvdPlayer.off();
    }
}

Client.java

public class Client {
    public static void main(String[] args) {
        HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();
        homeTheaterFacade.ready();
        homeTheaterFacade.play();
        homeTheaterFacade.pause();
        homeTheaterFacade.end();
    }
}

 

外观模式的注意事项和细节

1)外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性。

2)外观模式对客户端与子系统的耦合关系进行解耦,使子系统内部的模块更易于维护和扩展。

3)通过外观模式,可以帮助我们更好的划分访问的层次。

4)当系统需要分层设计时可以考虑Facade模式。

5)在维护一个遗留的大系统时,可能这个系统已经十分的难以维护和拓展,此时可以考虑为新系统开发一个Facade类,来提供遗留系统的比较清晰简单的接口,让新系统与Facade类交互,提高复用性。

6)不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好,要以让系统有层次,利于维护为目的。

posted @ 2020-03-15 00:23  护花使者  Views(122)  Comments(0Edit  收藏  举报