外观模式
一. 说明
外观模式又叫门面模式,是一种结构型模式。
外观模式提供一个简单、统一、解耦的接口,使得客户端能够更加方便地访问和使用复杂的子系统,同时,它还能隔离变化,提高系统的可维护性和可扩展性。
二.应用场景
- 在SpringCloud中的FeignClient通过接口调用其他系统的远程接口,这是一种外观模式的使用。
- 在日志系统中,经常使用的SLF4J也是一种外观模式的实践,我们使用统一的日志获取方式获得log4j或者logback不同的日志实现。
- 在DDD思想中,不同业务域之间需要一层facade做防腐也是一种外观模式的应用。
- 生活中我们在理财购买基金时,基金机构会将基金分散投资到各个领域中,我们只用关心我们的基金收益而不用关心基金机构是如何投资理财的,这也是一种门面模式。
三.代码示例
我们以工作中常见的获取用户信息为例子,在订单服务下单时调用用户服务获取用户信息的feign接口,该接口还需要从账户服务中获取用户余额信息,但订单只需调用用户服务一次。
我们先建立用户实体和账户实体,还有聚合对象
@Data
public class User {
private String userId;
private String username;
private String gender;
private Integer age;
}
@Data
public class Account {
private Integer account;
private Integer gold;
}
//用户和账户的聚合对象
@Data
public class UserInfo {
private String userId;
private String username;
private String gender;
private Integer age;
private Integer account;
private Integer gold;
}
我们再模拟一个获取用户信息的feign接口,并在用户服务中实现它
public interface UserFeign {
UserInfo queryUserInfo(String userId);
}
//模拟用户服务实现查询用户信息的feign接口
public class UserCenter implements UserFeign {
@Override
public UserInfo queryUserInfo(String userId) {
//查询用户基本信息
User user = queryById(userId);
//远程查询用户账户信息
AccountCenter accountCenter = new AccountCenter();
Account account = accountCenter.queryUserAccount(userId);
//封装聚合对象
UserInfo userInfo = new UserInfo();
userInfo.setUserId(user.getUserId());
userInfo.setUsername(user.getUsername());
userInfo.setGender(user.getGender());
userInfo.setAge(user.getAge());
userInfo.setAccount(account.getAccount());
userInfo.setGold(account.getGold());
return userInfo;
}
/**
* 模拟从数据库查询
*/
private User queryById(String userId){
User user = new User();
user.setUserId(userId);
user.setUsername("张三");
user.setGender("男");
user.setAge(20);
return user;
}
}
//模拟账户服务查询用户账户信息
public class AccountCenter {
//模拟从账户中心获取用户余额信息
public Account queryUserAccount(String userId){
Account account = new Account();
account.setAccount(100);
account.setGold(999);
return account;
}
}
再编写订单服务调用用户服务,并测试代码
public class OrderCenter {
public void createOrder(){
//模拟下单中查询用户信息
UserFeign userFeign = new UserCenter();
UserInfo userInfo = userFeign.queryUserInfo("10000");
System.out.println(userInfo.toString());
}
//模拟下单
public static void main(String[] args) {
OrderCenter orderCenter = new OrderCenter();
orderCenter.createOrder();
}
}
输出打印结果
在这个例子中,UserFeign 就是一层门面,隐藏了用户服务中查询从数据库用户信息和远程调用账户信息的细节,订单服务只需要调用UserFeign的queryUserInfo一次就可以获取到所需的数据。
四. 总结
外观模式可以降低系统的复杂度,减少系统之间的依赖,提供系统的灵活性和安全性,它常常是在软件设计阶段就被使用的。它遵循最少知道原则但不符合开闭原则,因为扩展功能需要更改接口和实现,继承重写也很麻烦,所以一定要在非常适合的场景使用它。