10.java设计模式之外观模式
基本需求
- 组建一个家庭影院:DVD 播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能,
- 其过程为:直接用遥控器:统筹各设备开关
- 开爆米花机、放下屏幕、开投影仪、开音响、开 DVD,选 dvd、去拿爆米花、调暗灯光、播放、观影结束后,关闭各种设备
传统方案
- 客户端直接依赖各种设备,直接调用各种设备的方法
- UML类图
- 在Client中,创建各个子系统的对象,并直接去调用子系统(对象)相关方法,会造成调用过程混乱,没有清晰的过程,不利于维护
- 定义一个高层接口,给子系统中的一组接口提供一个一致的界面(比如在高层接口提供四个方法ready, play, pause, end),用来访问子系统中的一群接口,就是通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节 -> 外观模式
基本介绍
-
外观模式(Facade)隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这种类型的设计模式属于结构型模式,它向现有的系统添加一个接口,来隐藏系统的复杂性。这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用
-
为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
-
主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口
-
UMl类图(原理)
- Facade类为外观类,聚合了其他多个子系统(实际功能的提供者),让client统一调用
-
UML类图(案例)
-
代码实现
-
public class DVDPlayer { // DVD播放器 使用饿汉 public static final DVDPlayer DVD_PLAYER = new DVDPlayer(); private DVDPlayer() { } public static DVDPlayer getInstance() { return DVD_PLAYER; } public void on() { System.out.println("dvd on"); } public void off() { System.out.println("dvd off"); } public void play() { System.out.println("dvd play"); } public void pause() { System.out.println("dvd pause"); } }
-
public class Screen { // 屏幕 使用饿汉 public static final Screen SCREEN = new Screen(); private Screen() { } public static Screen getInstance() { return SCREEN; } public void up() { System.out.println("screen up"); } public void dowm() { System.out.println("screen down"); } }
-
public class Popcorn { // 爆米花机 使用饿汉 public static final Popcorn POPCORN = new Popcorn(); private 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 pop"); } }
-
public class Projector { // 投影仪 使用饿汉 public static final Projector PROJECTOR = new Projector(); private 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 focus"); } }
-
public class TheaterLight { // 影院灯光 使用饿汉 public static final TheaterLight THEATER_LIGHT = new TheaterLight(); private TheaterLight() { } public static TheaterLight getInstance() { return THEATER_LIGHT; } public void on() { System.out.println("theater_light on"); } public void off() { System.out.println("theater_light off"); } public void dim() { System.out.println("theater_light dim"); } public void bright() { System.out.println("theater_light bright"); } }
-
public class Stereo { // 立体声 使用饿汉 public static final Stereo STEREO = new Stereo(); private 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 class HomeTheaterFacade { // 影院外观类,聚合其他子系统 ,提供统一的方法供Client调用 private DVDPlayer dvdPlayer = DVDPlayer.getInstance(); private Screen screen = Screen.getInstance(); private Popcorn popcorn = Popcorn.getInstance(); private Projector projector = Projector.getInstance(); private TheaterLight theaterLight = TheaterLight.getInstance(); private Stereo stereo = Stereo.getInstance(); public HomeTheaterFacade() { } // 给Client提供的方法相当于子系统方法的集合 public void ready() { popcorn.on(); popcorn.pop(); screen.dowm(); projector.on(); projector.focus(); theaterLight.on(); stereo.on(); dvdPlayer.on(); } public void play() { theaterLight.dim(); stereo.up(); dvdPlayer.play(); } public void pause() { dvdPlayer.pause(); } public void end() { popcorn.off(); screen.up(); projector.off(); theaterLight.off(); stereo.off(); dvdPlayer.off(); } }
-
public class Client { public static void main(String[] args) { HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade(); System.out.println("-----------ready-----------"); homeTheaterFacade.ready(); System.out.println("-----------play-----------"); homeTheaterFacade.play(); System.out.println("-----------pause-----------"); homeTheaterFacade.pause(); System.out.println("-----------end-----------"); homeTheaterFacade.end(); } }
-
mybatis源码
- 在mybatis的configuration类中的newMetaObject方法中创建MetaObject时使用的构造方法中就用到的外观模式
- UML类图
- configuration类就相当于facade类
注意事项
- 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
- 外观模式对客户端与子系统的耦合关系 - 解耦,让子系统内部的模块更易维护和扩展
- 通过合理的使用外观模式,可以帮我们更好的划分访问的
- 当系统需要进行分层设计时,可以考虑使用Facade模式(三层架构)
- 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个Facade类,来提供遗留系统的比较清晰简单的接口,让新系统与Facade类交互,提高复用性
- 不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好。要以让系统有层次,利于维护为目的