开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,点击查看活动详情
在家里吃饭,需要买菜、烧菜、洗碗等等一系列过程,甚为繁琐。但是去饭店吃饭,只需要跟服务员点好菜就可以了,剩下的一系列工作都由饭店的工作人员来完成,非常简单省事。
在业务系统开发中也是这样,通常一个较复杂的功能都是需要和若干个业务类进行交互,在一些场景中,这些交互总是批量出现的,这就会导致使用时较为复杂,出现较多重复的代码。这时,如果有一个类似服务员的角色,由它来负责和复杂的类或者业务进行交互,而使用这些业务的类只需要和它交互就可以了。外观模式就是充当了这么一个角色,它为多个业务类的调用提供统一的入口,简化了类与类之间的交互。
业务设计
公司开发的商城系统中,下订单这个过程是一个复杂的过程,它包含3个部分,分别是扣费用,减库存,加发货单。为了符合单一职责原则,这三个过程分别在三个不同的类或服务里,这就导致每个平台在下订单时都会涉及这一系列动作。
可以看出,该方案主要有2个问题
- 三个子过程基本都是以整体的形式出现,但是在各个平台里却需要与他们逐个交互,导致很多重复代码
- 如果其中一个子过程变更,比如双十一了,扣费用服务需要变更新的服务,则需要每个平台都更换一次代码,系统维护困难,灵活性和可扩展性比较差
为了解决这两个问题,可以在平台和子过程之间引入一个外观类,由它来封装子过程的交互。
示例代码
首先建立三个子过程类,这里简单模拟
//费用服务
@Service
public class Money {
public void deduct(){
System.out.println("扣费用");
}
}
//库存服务
@Service
public class Inventory {
public void reduce(){
System.out.println("减库存");
}
}
//发货服务
@Service
public class Delivery {
public void add(){
System.out.println("加发货单");
}
}
新建一个外观类,将三个子过程类注入进来,新建一个makeOrder方法将子过程组合起来
//外观类
@Component
public class OrderFacade {
@Autowired
private Money money;
@Autowired
private Delivery delivery;
@Autowired
private Inventory inventory;
public void makeOrder(){
money.deduct();
delivery.add();
inventory.reduce();
}
}
在平台客户端注入外观类,调用外观类的makeOrder方法
//平台客户端
@Autowired
private OrderFacade orderFacade;
@Test
public void Order(){
orderFacade.makeOrder();
}
但是很容易能看出来一个问题,如果我的子过程变更了,虽然不用修改客户端类了,但是还是要修改外观类,虽然这个工作量不大,从这一方面来说,它是不满足开闭原则的。
抽象外观类
为了解决上面的问题,可以通过引入抽象外观类的方式。它可以是一个抽象类,也可以是一个接口,这里以接口为示例:
//抽象外观接口
public interface AbstractFacade {
public void makeOrder();
}
让原来的外观类继承这个接口,并给他命名OrderFacade
@Service("OrderFacade")
public class OrderFacade implements AbstractFacade{
@Autowired
private Money money;
@Autowired
private Delivery delivery;
@Autowired
private Inventory inventory;
@Override
public void makeOrder(){
money.deduct();
delivery.add();
inventory.reduce();
}
}
在客户端根据情况,使用不同的实现类即可
@Resource(name="OrderFacade")
private AbstractFacade orderFacade;
@Test
public void Order(){
orderFacade.makeOrder();
}
这样,有不同的外观需求,只需要通过扩展AbstractFacade的子类即可,非常的方便
总结
外观模式其实是一种使用非常频繁的设计模式,相信各个同学编码的过程中虽然实现方式不同,但都或多或少有着它的影子,它为复杂系统提供统一的入口,使子系统与客户端耦合度降低,简化接口调用。它不给系统增加功能,只是简化调用的过程。
当你在项目中为复杂系统提供简单入口,或者希望客户端与子系统之间解耦时,都可以考虑使用外观模式