一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
门面模式,也叫外观模式,在 GoF 的《设计模式》一书中,门面模式是这样定义的:门面模式为子系统提供一组统一的接口,定义一组高层接口让子系统更易用。
如果你的日常工作中涉及接口开发,不知道你有没有关注过接口的粒度问题。为了使接口更加通用(可复用性),我们会将接口设计的更细粒度一点,这也符合单一职责原则。但是如果接口的粒度太小,就导致使用者在调用的时候需要调用很多接口才能完成一次事务。相反,如果接口设计的粒度太大,一个接口做很多事情,又会导致接口不够通用,为此针对不同的业务需求,我们就需要开发很多不同的接口来满足,这会导致系统的接口不断膨胀,可复用性也很差。门面模式就是为解决接口的可复用性(通用性)和易用性之间的矛盾而来。
应用场景
-
封装系统的底层实现,隐藏系统的复杂性。
-
解决性能问题。例如多个http请求的接口耗时,合并成一个请求后节省了网络通信的耗时。
-
解决分布式事务问题。封装多个不同的系统接口,在一个接口内处理事务,避免了使用复杂的分布式事务框架或者事后补偿的机制的解决方案。
类图
类图
Facade类通过构造函数注入了两个模块ModuleA和ModuleB,并将ModuleA中和getInteger()方法和ModuleB中的getString()方法组合后返回。
代码实现
ModuleA
public interface ModuleA {
Integer getInteger();
}
ModuleAImpl
public class ModuleAImpl implements ModuleA {
@Override
public Integer getInteger() {
return 1;
}
}
ModuleB
public interface ModuleB {
String getString();
}
ModuleBImpl
public class ModuleBImpl implements ModuleB {
@Override
public String getString() {
return "hello";
}
}
VO
public class VO {
private Integer integer;
private String string;
public Integer getInteger() {
return integer;
}
public void setInteger(Integer integer) {
this.integer = integer;
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
@Override
public String toString() {
return "VO{" +
"integer=" + integer +
", string='" + string + '\'' +
'}';
}
}
Facade
public class Facade {
private ModuleA moduleA;
private ModuleB moduleB;
public Facade(ModuleA moduleA, ModuleB moduleB) {
this.moduleA = moduleA;
this.moduleB = moduleB;
}
public VO comb() {
VO vo = new VO();
vo.setInteger(moduleA.getInteger());
vo.setString(moduleB.getString());
return vo;
}
}
Main
public class Main {
public static void main(String[] args) {
ModuleA moduleA = new ModuleAImpl();
ModuleB moduleB = new ModuleBImpl();
Facade facade = new Facade(moduleA, moduleB);
VO vo = facade.comb();
System.out.println(vo.toString());
}
}
接口粒度设计得太大,太小都不好。太大会导致接口复用性差,太小会导致接口使用复杂。在实际的开发中,接口的可复用性和易用性需要“微妙”的权衡。对于接口设计,建议 「尽量保持接口的可复用性,但针对特殊情况,允许提供冗余的门面接口,来提供更易用的接口。」