这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战
外观模式
前言
- 通过一个影院管理项目来了解外观模式
- 传统方式解决方法为:
- 传统方式的问题:在 ClientTest 的 main 方法中,创建各个子系统的对象,并直接去调用子系统 对象相关方法,会造成调用过程混乱,没有清晰的过程,不利于在 ClientTest 中,去维护对子系统的操作
- 解决办法:定义一个高层接口,给子系统中的一组接口提供一个一致的界面比如在高层接口提供四个方法 ready, play, pause, end,用来访问子系统中的一群接口也就是说就是通过定义一个一致的接口界面类用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节 => 外观模式
基本介绍
- 外观模式也叫过程模式 :外观模式为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
- 外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节
- 外观模式就是解决多个复杂接口带来的使用困难,起到简化用户操作的作用
- 原理图
具体实现
- 类图:
- 代码实现:
//子系统
public class DVDPlayer {
//使用单例模式, 使用饿汉式
private static DVDPlayer instance = new DVDPlayer();
//提取DVDPlayer
public static DVDPlayer getInstanc() {
return instance;
}
//开启
public void on() {
System.out.println("DVD开始运行");
}
//关闭
public void off() {
System.out.println("DVD关闭");
}
//运行
public void play() {
System.out.println("DVD正在运行");
}
//DVD放完了
public void pause() {
System.out.println("DVD放完了");
}
}
//爆米花机
public class Popcorn {
//创建爆米花机
private static Popcorn instance = new Popcorn();
public static Popcorn getInstance() {
return instance;
}
//爆米花机开机
public void on() {
System.out.println("爆米花机开机");
}
//爆米花机关机
public void off() {
System.out.println("爆米花机关机");
}
//爆米花机正在制作爆米花
public void pop() {
System.out.println("爆米花机正在制作爆米花");
}
}
//投影机
public class Projector {
//创建投影机
private static Projector instance = new Projector();
public static Projector getInstance() {
return instance;
}
//投影机开机
public void on() {
System.out.println("投影机开机");
}
//投影机关机
public void off() {
System.out.println("投影机关机");
}
//投影机正在运行
public void focus() {
System.out.println("投影机正在运行");
}
//...
}
//荧幕
public class Screen {
//创建荧幕
private static Screen instance = new Screen();
public static Screen getInstance() {
return instance;
}
//上升荧幕
public void up() {
System.out.println("上升荧幕");
}
//下降荧幕
public void down() {
System.out.println("下降荧幕");
}
}
//立体声机
public class Stereo {
//创建立体声机
private static Stereo instance = new Stereo();
public static Stereo getInstance() {
return instance;
}
//立体声机开机
public void on() {
System.out.println("立体声机开机");
}
//立体声机关机
public void off() {
System.out.println("立体声机关机");
}
//立体声机正在运行
public void up() {
System.out.println("立体声机正在运行");
}
//...
}
//灯光
public class TheaterLight {
//创建灯光
private static TheaterLight instance = new TheaterLight();
public static TheaterLight getInstance() {
return instance;
}
//灯光开启
public void on() {
System.out.println("灯光开启");
}
//灯光关闭
public void off() {
System.out.println("灯光关闭");
}
//灯光调暗
public void dim() {
System.out.println("灯光调暗");
}
//灯光调亮
public void bright() {
System.out.println("灯光调亮");
}
}
//外观类
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.getInstanc();
}
//操作分成 4 步
//电影院准备
public void ready() {
popcorn.on();
popcorn.pop();
screen.down();
projector.on();
stereo.on();
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();
dVDPlayer.off();
}
}
//客户端调用
//客户端
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
//这里直接调用。。 很麻烦
HomeTheaterFacade homeTheaterFacade = new HomeTheaterFacade();
//电影院准备
homeTheaterFacade.ready();
//电影院开始
homeTheaterFacade.play();
//电影院结束
homeTheaterFacade.end();
}
}
- 结果展示:
总结
- 外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
- 外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展
- 通过合理的使用外观模式,可以帮我们更好的划分访问的层次
- 当系统需要进行分层设计时可以考虑使用外观模 式
- 在维护一个遗留的大型系统时,可能这个系统已经变得非常难以维护和扩展,此时可以考虑为新系统开发一个外观类,来提供遗留系统的比较清晰简单的接口,让新系统与外观类交互, 提高复用性
- 不能过多的或者不合理的使用外观模式,使用外观模式好,还是直接调用模块好,要以让系统有层次,利于维护为目的 。