定义
- 外观模式又叫门面模式,提供了一个统一的接口,用了访问子系统中的一群接口
- 外观模式定义了一个高层接口,让子系统更容易使用
类型
结构型
组成
- 外观角色:了解子系统所有的方法,它也有自己的方法,客户端通过调用外观角色的方法来调用子系统的功能
- 子系统:可以是一个也可以是多个,子系统按照不同的维度,完成不同的处理模块,并不是单独的类,子系统形成一个集合,为外观模式的外观了类,提供子系统的功能
优点
- 简化了调用过程,无需了解深入子系统,防止带来风险
- 减少系统依赖,松散耦合(客户端不和子系统直接交流,客户端和外观对象交流,让子系统内部的模块,更容易扩展和维护)
- 更好的划分访问层次(把需要对外暴露的功能,集中到外观类上,这样既方便客户端调用,也可以很好的隐藏细节)
- 符合迪米特法则,即最少知道原则,还有依赖倒转原则
缺点
- 增加子系统、扩展子系统行为容易引人风险
- 不符合开闭原则
相关设计模式
-
外观模式和中介者模式
外观模式关注,外部和子系统之间的交互。中介者模式关注的是子系统之间的交互 -
外观模式和单例模式
通常我们把外观模式的外观角色做成单例模式的 -
外观模式和抽象工厂模式
外观类可以通过抽象工厂获取子系统实例。这样子系统内部可以对外观类进行屏蔽
代码示例
模拟一个购买商品下单的过程。首先我们有三个子系统,分别是 库存子系统,支付子系统,物流子系统。还有我们外观类。已经客户端代码
- 创建子系统
库存子系统
/**
* 库存子系统
*/
public class InventoryService {
/**
* 校验商品库存是否充足
*/
public Boolean checkInventory(Goods goods) {
System.out.println("校验" + goods.getName() + "库存充足");
return Boolean.TRUE;
}
/**
* 减库存
*/
public void minusInventory(Goods goods) {
System.out.println(goods.getName() + "库存减一");
}
}
支付子系统
/**
* 支付子系统
*/
public class PayService {
/**
* 支付商品
*/
public Boolean payGoods(Goods goods) {
System.out.println(goods.getName() + "商品支付成功");
return Boolean.TRUE;
}
}
物流子系统
/**
* 物流子系统
*/
public class LogisticsService {
/**
* 商品发货
* return 物流单号
*/
public String deliverGoods(Goods goods) {
System.out.println(goods.getName() + "发货成功");
return "12345";
}
}
- 创建外观类
购买服务
/**
* 外观类-购物
*/
public class ShoppingService {
private InventoryService inventoryService = new InventoryService();
private PayService payService = new PayService();
private LogisticsService logisticsService = new LogisticsService();
/**
* 下单
*/
public void order(Goods goods) {
if (inventoryService.checkInventory(goods)) {
//库存校验通过
if (payService.payGoods(goods)) {
//支付成功,发物流
String odd = logisticsService.deliverGoods(goods);
//减库存
inventoryService.minusInventory(goods);
System.out.println("商品购买成功,物流单号:" + odd);
}
}
}
}
- 模拟客户端
public class Client {
public static void main(String[] args) {
Goods goods = new Goods("篮球");
ShoppingService shoppingService = new ShoppingService();
shoppingService.order(goods);
}
}
执行结果
校验篮球库存充足
篮球商品支付成功
篮球发货成功
篮球库存减一
商品购买成功,物流单号:12345
UML
使用场景
- 在设计初期阶段,应该有意识的将不同的两个层分离,层与层建立外观类
- 在开发阶段,子系统因为不断的重构演化,变得越来越复杂,增加外观类可以提供一个简单的接口,减少他们之间的依赖
- 在维护一个遗留的大型项目的时,可能这个系统已经难以维护和扩展了,我们可以为新系统开发一个外观类,来提供设计粗糙或高度复杂遗留代码的比较清新简单的接口,让新系统与外观对象交互,外观类与遗留代码交互所有复杂的工作