门面模式(Facade Pattern) 又叫外观模式,提供了一个统一的接口,用来访问子系统中的一群接口 。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构型模式。在我们日常编码中也在无意中大量的使用着门面模式,例如
ServiceA
中调用其他多个Service的方法,然后再将ServiceA
的方法暴露给Controller调用,ServiceA
就相当于一个门面使得Controller能够间接的调用其他Service子系统,这也就是门面模式的一种应用。
子系统越来越复杂,增加门面模式提供简单接口
构建多层系统结构,利用门面对象作为每层的入口,简化层间调用
SubSystem
): 可以同时有一个或多个SubSystem
。每个SubSystem
都不是一个单独的类,而是一个类的集合。SubSystem
并不知道Facade 的存在,对于SubSystem
而言,Facade只是另外一个客户端而已(即Facade对SubSystem
是透明的)。我们先分别创建3个子系统的业务逻辑SubSystemA
、SubSystemB
、SubSystemC
/**
* 子系统角色 - SubSystemA
*
* @author zdp
* @date 2022/9/3 14:38
*/
public class SubSystemA {
public void doA() {
System.out.println("doing A stuff");
}
}
/**
* 子系统角色 - SubSystemB
*
* @author zdp
* @date 2022/9/3 14:38
*/
public class SubSystemB {
public void doB() {
System.out.println("doing B stuff");
}
}
/**
* 子系统角色 - SubSystemC
*
* @author zdp
* @date 2022/9/3 14:38
*/
public class SubSystemC {
public void doC() {
System.out.println("doing C stuff");
}
}
紧接着再创建一个外观角色类Facade :
/**
* 外观角色 Facade 相当于注入其他Service,封装其方法暴露给客户端
*
* @author zdp
* @date 2022/9/3 14:34
*/
public class Facade {
//相当于@Autowire注入
private SubSystemA a = new SubSystemA();
private SubSystemB b = new SubSystemB();
private SubSystemC c = new SubSystemC();
// 对外接口
public void doA() {
this.a.doA();
}
// 对外接口
public void doB() {
this.b.doB();
}
// 对外接口
public void doC() {
this.c.doC();
}
}
编写测试类
/**
* facade 通用写法
*
* @author zdp
* @date 2022/9/3 14:36
*/
class Test {
// 客户 (相当于Controller)
public static void main(String[] args) {
Facade facade = new Facade();
facade.doA();
facade.doB();
facade.doC();
}
}
需求:现有积分、支付、库存、物流系统,需要做一个积分兑换商城
/**
* 商品详情信息
*
* @author zdp
* @date 2022/9/3 14:52
*/
@Data
@Builder
public class GoodsInfo {
private String name;
private Integer integral;
private BigDecimal price;
}
/**
* 积分系统
*
* @author zdp
* @date 2022/9/3 14:51
*/
@Slf4j
public class IntegralSystem {
/**
* 扣减积分
*
* @param info GoodsInfo
* @author zdp
* @date 2022/9/3 15:10
* @return result
*/
public boolean deductIntegral(GoodsInfo info){
log.info("商品【{}】扣减积分成功", info.getName());
return true;
}
}
/**
* 库存系统
*
* @author zdp
* @date 2022/9/3 14:54
*/
@Slf4j
public class StockSystem {
public static int goodsStock = 2;
/**
* 扣减库存
*
* @param info GoodsInfo
* @author zdp
* @date 2022/9/3 15:07
* @return result
*/
public boolean deductStock(GoodsInfo info){
goodsStock -= 1;
if (goodsStock < 0) {
log.info("商品【{}】扣减库存失败,库存不足~", info.getName());
return false;
}
log.info("商品【{}】扣减库存成功~", info.getName());
return true;
}
}
/**
* 支付系统
*
* @author zdp
* @date 2022/9/3 14:52
*/
@Slf4j
public class PaymentSystem {
StockSystem stock = new StockSystem();
IntegralSystem integral = new IntegralSystem();
/**
* 付款
*
* @param info GoodsInfo
* @author zdp
* @date 2022/9/3 15:08
* @return result
*/
public boolean pay(GoodsInfo info){
if (stock.deductStock(info)) {
integral.deductIntegral(info);
log.info("商品【{}】支付成功,准备发货~", info.getName());
return true;
}
return false;
}
}
/**
* 物流系统
*
* @author zdp
* @date 2022/9/3 14:49
*/
@Slf4j
public class LogisticsSystem {
/**
* 对接物流系统,商品发货
*
* @param info goods info
* @author zdp
* @date 2022/9/3 14:57
* @return java.lang.String 物流单号
*/
public void deliverGoods(GoodsInfo info){
//对接物流系统...
log.info("商品【{}】,进入物流系统,单号: {}", info.getName(), new Date().getTime());
}
}
/**
* 外观角色 Facade 商品兑换门面 整合了支付和物流系统,使得前端开发逻辑处理简单,不用再调用多个系统
*
* @author zdp
* @date 2022/9/3 15:15
*/
public class GoodsFacadeSystem {
PaymentSystem payment = new PaymentSystem();
LogisticsSystem logistics = new LogisticsSystem();
/**
* 商品兑换
*
* @param info GoodsInfo
* @author zdp
* @date 2022/9/3 15:16
* @return 商品兑换结果
*/
public boolean exchange(GoodsInfo info){
if (!payment.pay(info)) {
return false;
}
logistics.deliverGoods(info);
return true;
}
}
public class Test {
public static void main(String[] args) throws Exception{
GoodsFacadeSystem facade = new GoodsFacadeSystem();
for (int i = 0; i < 3; i++) {
GoodsInfo info = GoodsInfo.builder()
.name("拖孩儿")
.integral(100)
.price(new BigDecimal("10.05"))
.build();
facade.exchange(info);
TimeUnit.MILLISECONDS.sleep(1);
}
}
}