一、外观模式
外观模式(fasade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
类型:结构型
使用场景:
1.子系统越来越复杂,增加外观模式提供简单高层调用接口
2.构建多层系统结构,利用外观对象作为每层的入口,简化层间调用
优点:
1.简化调用过程,无需深入了解子系统,防止带来风险
2.减少系统依赖,松散耦合
3.更好的划分访问层次
4.符合迪米特法则,即最少知道原则
5.结合抽象工厂,可以做到开闭原则,更好的扩展
缺点:
1.增加子系统,扩展子系统行为容易引起风险。
2.不符合开闭原则—结合抽象工厂可避免
假设场景:
以电商订单结算为例子,结算订单需要调用多个模块:
1.查询账户余额是否够
2.余额满足支付的情况下金额完成支付
3.清除购物车记录,修改订单状态完成支付
4.进入物流模块,显示物流信息
场景分析:
这些每一个都与订单结算相关联,我们需要一一调用来完成结算功能。这样非常麻烦,就可以在这些操作的基础上增加一个高层接口,我们只需传入用户信息,在这个高层接口里面完成一系列的检验支付功能,由这个高层接口来判断是否满足订单结算功能,而不用与这一组接口产生耦合。只需调用这个高层接口,高层接口反馈支付成功还是不成功的信息,针对反馈结果进行处理。
开闭原则实现:
上述场景来看,目前需要这四个步骤来完成订单结算,假设产品现在需要额外扩展一个积分功能,就需要对这个高层接口修改,或者某一个天积分功能不需要了,又要来注释掉积分模块的调用,这样不符合开闭原则。
可以再这个高层接口上再定义一层抽象接口,当需要增加积分功能时,重新额外扩展一个实现来完成积分功能的新增,只需在调用位置修改一下实现类,当不需要积分功能时将实现类替换回去即可。完全符合开闭原则。
二、代码实现
//账户类判断是否满足支付金额
public class Account {
private Long balance;
public Account(Long balance) {
this.balance = balance;
}
public Account() {
}
public Long getBalance() {
return balance;
}
public void setBalance(Long balance) {
this.balance = balance;
}
}
//是否可以支付
public class AccountService {
public boolean isSettle(Account account, int purchaseMoney){
if(account.getBalance()>=purchaseMoney){
account.setBalance(account.getBalance()-purchaseMoney);
System.out.println("支付完成,账户减少金额:"+purchaseMoney);
return true;
}else{
return false;
}
}
}
//清除购物车记录
public class CartService {
public void deleteRecore(){
System.out.println("结算完成,清除购物车记录");
}
}
//物流仓储模块,还缺少一个减少库存的函数
public class LogisticsService {
public String logistics(){
System.out.println("进入物流系统");
return UUID.randomUUID().toString();
}
}
//结算完成-修改订单状态
public class OrderService {
public void settleAccounts(){
System.out.println("完成结算,修改订单状态");
}
}
//高层接口调用---外观模式接口
public class OrderExchangeService {
//假设spring 自动注入
AccountService accountService = new AccountService();
LogisticsService logisticsService = new LogisticsService();
OrderService orderService = new OrderService();
public String payment(Account account){
String num = null;
//假设订单价格是98
int orderMoney = 98;
boolean settle = accountService.isSettle(account, orderMoney);
if(settle){
orderService.settleAccounts();
num = logisticsService.logistics();
}
return num;
}
}
结合抽象工厂,完成积分功能扩展就不列举了,大概思路就是增加抽象高层接口,添加积分服务,实现抽象接口在里面添加积分服务的调用,main测试方法修改实现类即可。
大概就是这个道理,我没有做过电商系统其中很多细节可能不到位,这里目的是为了体验外观设计模式。
来源于:慕课网geely老师视频,其中大话设计模式一书中也有一个例子,其过程类似就不列举了。