影院管理项目
组件一个家庭影院:DVD播放器、投影仪、自动屏幕、环绕立体声、爆米花机,要求完成使用家庭影院的功能,器过程为:
- 直接用遥控器,统筹各设备开关。
- 开爆米花机
- 放下屏幕
- 开投影仪
- 开音响
- 开DVD,旋转DVD
- 去拿爆米花
- 调暗灯光
- 播放电影
- 观影结束后,关闭各种设备
传统方式解决影院管理问题
该方式存在的问题
- 在Client的main方法中,创建各个子系统的对象,并直接调用子系统的相关方法,会造成调用过程混乱,没有清晰的过程。
- 不利于在Client中维护对各子系统的相关操作。
解决思路:
- 定义一个高层接口,给系统中的一组接口提供一个一致的界面(比如在高层接口中提供四个方法ready、play、pause、end),用来访问子系统中的一群接口。
- 通过定义一个一致的接口(界面类),用以屏蔽内部子系统的细节,使得调用端只需要跟这个接口发生调用,而无须关心这个子系统的内部细节 — 外观模式。
外观模式
基本介绍
- 外观模式(Facade)也叫过程模式。外观模式为系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
- 外观模式通过定义一个一致的接口,用以屏蔽内部子系统的细节,使得调用端只需跟这个接口发生调用,而无需关心这个子系统的内部细节。
外观模式解决家庭影院问题
- UML类图
- 代码实现:
DVDPlayer 类:
Popcorn 类: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 play"); } public void pause() { System.out.println("dvd pause"); } }
Projector 类:public class Popcorn { // 使用单例模式,使用饿汉式 private static Popcorn instance = new Popcorn(); public static Popcorn getInstance() { return instance; } public void on() { System.out.println("popcorn on"); } public void off() { System.out.println("popcorn off"); } public void pop() { System.out.println("popcorn is popping"); } }
Screen 类:public class Projector { // 使用单例模式,使用饿汉式 private static Projector instance = new Projector(); public static Projector getInstance() { return instance; } public void on() { System.out.println("Projector on"); } public void off() { System.out.println("Projector off"); } public void focus() { System.out.println("Projector is focus"); } }
Stereo 类:public class Screen { // 使用单例模式,使用饿汉式 private static Screen instance = new Screen(); public static Screen getInstance() { return instance; } public void up() { System.out.println("screen up"); } public void down() { System.out.println("screen down"); } }
TheaterLight 类:public class Stereo { // 使用单例模式,使用饿汉式 private static Stereo instance = new Stereo(); public static Stereo getInstance() { return instance; } public void on() { System.out.println("Stereo on"); } public void off() { System.out.println("Stereo off"); } public void trunUp() { System.out.println("Stereo turns up"); } }
HomeTheaterFacade 类:public class TheaterLight { // 使用单例模式,使用饿汉式 private static TheaterLight instance = new TheaterLight(); public static TheaterLight getInstance() { return instance; } 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 birght"); } }
public class HomeTheaterFacade { // 定义各个子系统的对象 private TheaterLight theaterLight; private Popcorn popcorn; private Projector projector; private Screen screen; private Stereo stereo; private DVDPlayer dvdPlayer; public HomeTheaterFacade() { this.theaterLight = TheaterLight.getInstance(); this.popcorn = Popcorn.getInstance(); this.projector = Projector.getInstance(); this.screen = Screen.getInstance(); this.stereo = Stereo.getInstance(); this.dvdPlayer = DVDPlayer.getInstance(); } public void ready() { theaterLight.on(); 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() { theaterLight.bright(); dvdPlayer.off(); projector.off(); screen.up(); stereo.off(); theaterLight.off(); } }
外观模式在 MyBatis 框架中应用
org.apache.ibatis.session.Configuration 类:
public class Configuration {
...
protected ReflectorFactory reflectorFactory;
protected ObjectFactory objectFactory;
protected ObjectWrapperFactory objectWrapperFactory;
...
public Configuration(Environment environment) {
this();
this.environment = environment;
}
public Configuration() {
...
this.reflectorFactory = new DefaultReflectorFactory();
this.objectFactory = new DefaultObjectFactory();
this.objectWrapperFactory = new DefaultObjectWrapperFactory();
...
}
...
public MetaObject newMetaObject(Object object) {
return MetaObject.forObject(object, this.objectFactory, this.objectWrapperFactory, this.reflectorFactory);
}
...
}
org.apache.ibatis.reflection.MetaObject 类:
public class MetaObject {
private final Object originalObject;
private final ObjectWrapper objectWrapper;
private final ObjectFactory objectFactory;
private final ObjectWrapperFactory objectWrapperFactory;
private final ReflectorFactory reflectorFactory;
private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
this.originalObject = object;
this.objectFactory = objectFactory;
this.objectWrapperFactory = objectWrapperFactory;
this.reflectorFactory = reflectorFactory;
if (object instanceof ObjectWrapper) {
this.objectWrapper = (ObjectWrapper)object;
} else if (objectWrapperFactory.hasWrapperFor(object)) {
this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
} else if (object instanceof Map) {
this.objectWrapper = new MapWrapper(this, (Map)object);
} else if (object instanceof Collection) {
this.objectWrapper = new CollectionWrapper(this, (Collection)object);
} else {
this.objectWrapper = new BeanWrapper(this, object);
}
}
public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory, ReflectorFactory reflectorFactory) {
return object == null ? SystemMetaObject.NULL_META_OBJECT : new MetaObject(object, objectFactory, objectWrapperFactory, reflectorFactory);
}
}
Configuration类的实现,就用到了外观设计模式,而ReflectorFactory、ObjectWrapperFactory、ObjectFactory分别构成子系统。UML类图:
外观模式的注意事项和细节
- 外观模式对外屏蔽了系统的细节,因此外观模式降低了客户端对子系统使用的复杂性。
- 外观模式对客户端与子系统的耦合关系,让子系统内部的模块更易维护和扩展。
- 通过合理的使用外观模式,可以帮我们更好的划分访问的层次。
- 当系统需要进行分层设计时,可以考虑使用Facade模式。
- 当维护一个大型遗留系统时,可能这个系统已经变得非常难以维护和扩展。此时,可以考虑为新系统开发一个Facade类,来提供遗留系统的比较清晰的接口,让系统与Facade类交互,提高复用性。