1.门面模式的定义
为子系统的一系列接口提供一个一致的界面,Facade模式定义了高层次的接口,该接口使得子系统更加容易使用。
2.门面模式的使用场景
现在考虑这样的场景,有一个顾客需要到饭店用餐,这就需要定义一个Customer类,并为该类定义一个haveDinner()方法。考虑该饭店有三个部门:收银部、厨师部和服务生部,用户就餐需要这三个部门协调才能完成。
Customer需要依次调用三个部门的方法才可实现haveDinner()方法——这就会增加haveDinner()方法的实现难度。为了解决这个问题,可以为三个部门提供一个门面(Facade),使用该Facade来包装这些类,对外提供一个简单的访问方法。
3.门面模式的UML类图
4.门面模式的实现
public interface Payment {
public String pay();
}
public class PaymentImpl implements Payment{
//实现模拟顾客支付费用的方法
@Override
public String pay() {
// TODO Auto-generated method stub
String food = "快餐";
System.out.println("你已向收银员支付了费用,您购买的食物是:"+food);
return food;
}
}
public interface Cook {
public String cook(String food);
}
public class CookImpl implements Cook{
//实现模拟烹调食物的方法
@Override
public String cook(String food) {
// TODO Auto-generated method stub
System.out.println("厨师正在烹调"+food);
return food;
}
}
public interface Waiter {
public void serve(String food);
}
public class WaiterImpl implements Waiter{
//模拟服务生上菜的方法
@Override
public void serve(String food) {
// TODO Auto-generated method stub
System.out.println("服务生已将"+food+"端上来了,请慢用...");
}
}
public class Facade {
//定义被Facede封装的三个部门
Payment pay;
Cook cook;
Waiter waiter;
//构造器
public Facade() {
this.pay = new PaymentImpl();
this.cook = new CookImpl();
this.waiter = new WaiterImpl();
}
public void serveFood() {
//依次调用三个部门的方法,封装成一个serveFood()方法
String food = pay.pay();
food = cook.cook(food);
waiter.serve(food);
}
}
public class Customer {
public void haveDinner() {
Facade f = new Facade();
f.serveFood();
}
}
5.总结
外观模式时一个高频率使用的设计模式,它的精髓就在于封装二字。通过一个高层次结构为用户提供统一的API入口,使得用户通过一个类型就基本能够操作整个系统,这样减少了用户的使用成本,也能够提升系统的灵活性。
优点
- 对客户程序隐藏了系统细节,因而减少了客户对于子系统的耦合,能够拥抱变化。
- 外观类对子系统的接口封装,使得系统更易于使用。
缺点
- 外观类接口膨胀。由于子系统的接口都有外观类统一对外暴露,使得外观类的API接口较多,在一定程度上增加了用户使用成本。
- 外观类没有遵循开闭原则,当业务出现变更时,可能需要直接修改外观类。
备注:读《Android源码设计模式解析与实践》笔记。