在生活中,比如在医院有接待员帮助病人完成门诊、挂号、付费以及取药,病人只接触接待员即可,由接待员负责与医院的各个部门打交道。
再如,诸多交易场景,也是需要一个客户服务的门面,完成诸如订单、支付和航运相关的服务。
类似这些场景,就是我们今天要聊的门面模式可以做的事情。
一、门面模式基本介绍
1.1 意图
门面模式是一种对象结构型模式,其意图是为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
1.2 结构
门面模式的基本结构如下:
二、为什么要使用Facade
随着系统越来越复杂,一般会划分成若干个子系统降低系统的复杂性。如果每个客户需要与一个或者多个子系统进行交互,势必会增加耦合性。
接下来我们模拟一个系统,其中子系统有产品服务、设备服务、账号服务等,多个业务场景需要调用到产品服务、设备服务等。如:
2.1 是是
2.1 不使用Facade
在这种情况下,业务系统直接各个子系统进行交互。简单的代码如下:
public interface ProductService {
ProductDTO findByProductKey(String productKey);
}
public interface DeviceService {
Long countByProductKey(String productKey);
}
ProductService和DeviceService可以是微服务,如Dubbo。
public class ProductServiceImpl implements ProductService {
private ProductDTO mockProductDTO() {
ProductDTO productDTO = new ProductDTO();
productDTO.setName("Product 1");
productDTO.setProductKey("1234567890");
return productDTO;
}
public ProductDTO findByProductKey(String productKey) {
return mockProductDTO();
}
}
public class DeviceServiceImpl implements DeviceService {
public Long countByProductKey(String productKey) {
return 100L;
}
}
ProductDTO - 简单的产品信息
import java.io.Serializable;
public class ProductDTO implements Serializable {
private static final long serialVersionUID = 2571209854790235084L;
private String productKey;
private String name;
/**
* @return the productKey
*/
public String getProductKey() {
return productKey;
}
/**
* @param productKey the productKey to set
*/
public void setProductKey(String productKey) {
this.productKey = productKey;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "ProductDTO [productKey=" + productKey + ", name=" + name + ", getProductKey()=" + getProductKey()
+ ", getName()=" + getName() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
+ ", toString()=" + super.toString() + "]";
}
}
DeviceDTO - 简单的设备信息
import java.io.Serializable;
public class DeviceDTO implements Serializable {
private static final long serialVersionUID = -5464821636761682860L;
private String name;
private String productKey;
private String accountId;
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the productKey
*/
public String getProductKey() {
return productKey;
}
/**
* @param productKey the productKey to set
*/
public void setProductKey(String productKey) {
this.productKey = productKey;
}
/**
* @return the accountId
*/
public String getAccountId() {
return accountId;
}
/**
* @param accountId the accountId to set
*/
public void setAccountId(String accountId) {
this.accountId = accountId;
}
@Override
public String toString() {
return "DeviceDTO [name=" + name + ", productKey=" + productKey + ", accountId=" + accountId + "]";
}
}
ProductDetailDTO - 包含产品设备数的产品信息
import java.io.Serializable;
public class ProductDetailDTO implements Serializable {
private static final long serialVersionUID = 9105918059993472221L;
private String productKey;
private String name;
private Long deviceCount;
/**
* @return the productKey
*/
public String getProductKey() {
return productKey;
}
/**
* @param productKey the productKey to set
*/
public void setProductKey(String productKey) {
this.productKey = productKey;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the deviceCount
*/
public Long getDeviceCount() {
return deviceCount;
}
/**
* @param deviceCount the deviceCount to set
*/
public void setDeviceCount(Long deviceCount) {
this.deviceCount = deviceCount;
}
@Override
public String toString() {
return "ProductDetailDTO [productKey=" + productKey + ", name=" + name + ", deviceCount=" + deviceCount + "]";
}
}
业务A
public class BusinessA {
private ProductService productService;
private DeviceService deviceService;
public ProductDetailDTO findByProductKey(String productKey) {
ProductDTO productDTO = productService.findByProductKey(productKey);
Long deviceCount = deviceService.countByProductKey(productKey);
/**
* 将productDTO和deviceCount拼成ProductDetailDTO信息
*/
ProductDetailDTO productDetailDTO = new ProductDetailDTO();
productDetailDTO.setDeviceCount(deviceCount);
productDetailDTO.setName(productDTO.getName());
productDetailDTO.setProductKey(productDTO.getProductKey());
return productDetailDTO;
}
/**
* @param productService the productService to set
*/
public void setProductService(ProductService productService) {
this.productService = productService;
}
/**
* @param deviceService the deviceService to set
*/
public void setDeviceService(DeviceService deviceService) {
this.deviceService = deviceService;
}
}
业务B
public class BusinessB {
private ProductService productService;
private DeviceService deviceService;
public ProductDetailDTO findByProductKey(String productKey) {
ProductDTO productDTO = productService.findByProductKey(productKey);
Long deviceCount = deviceService.countByProductKey(productKey);
/**
* 将productDTO和deviceCount拼成ProductDetailDTO信息
*/
ProductDetailDTO productDetailDTO = new ProductDetailDTO();
productDetailDTO.setDeviceCount(deviceCount);
productDetailDTO.setName(productDTO.getName());
productDetailDTO.setProductKey(productDTO.getProductKey());
return productDetailDTO;
}
/**
* @param productService the productService to set
*/
public void setProductService(ProductService productService) {
this.productService = productService;
}
/**
* @param deviceService the deviceService to set
*/
public void setDeviceService(DeviceService deviceService) {
this.deviceService = deviceService;
}
}
如果采用上述方式来处理,那么我们可以看到如下的问题:
为了解决上述问题,可以引入一个Facade。
2.2 使用Facade
public interface ProductFacade {
ProductDetailDTO findByProductKey(String productKey);
}
ProductFacade的实现,其调用子系统的接口,然后提供服务。
public class ProductFacadeImpl implements ProductFacade {
private ProductService productService;
private DeviceService deviceService;
public ProductDetailDTO findByProductKey(String productKey) {
ProductDTO productDTO = productService.findByProductKey(productKey);
Long deviceCount = deviceService.countByProductKey(productKey);
/**
* 将productDTO和deviceCount拼成ProductDetailDTO信息
*/
ProductDetailDTO productDetailDTO = new ProductDetailDTO();
productDetailDTO.setDeviceCount(deviceCount);
productDetailDTO.setName(productDTO.getName());
productDetailDTO.setProductKey(productDTO.getProductKey());
return productDetailDTO;
}
/**
* @return the productService
*/
public ProductService getProductService() {
return productService;
}
/**
* @param productService the productService to set
*/
public void setProductService(ProductService productService) {
this.productService = productService;
}
/**
* @return the deviceService
*/
public DeviceService getDeviceService() {
return deviceService;
}
/**
* @param deviceService the deviceService to set
*/
public void setDeviceService(DeviceService deviceService) {
this.deviceService = deviceService;
}
}
有了Facade,业务方只需要和Facade进行交互,与各个子系统是没有直接的关联关系的,这样,业务方只要维护一个Facade的版本即可。
业务A和业务B调整后如下,其只要和Facade进行交互即可。Facade可以完成和子系统的交互。
public class NewBusinessA {
private ProductFacade productFacade;
public ProductDetailDTO findByProductKey(String productKey) {
return productFacade.findByProductKey(productKey);
}
/**
* @param productFacade the productFacade to set
*/
public void setProductFacade(ProductFacade productFacade) {
this.productFacade = productFacade;
}
}
public class NewBusinessB {
private ProductFacade productFacade;
public ProductDetailDTO findByProductKey(String productKey) {
return productFacade.findByProductKey(productKey);
}
/**
* @param productFacade the productFacade to set
*/
public void setProductFacade(ProductFacade productFacade) {
this.productFacade = productFacade;
}
}
这样,一个简单的Facade示例就完成了。
三、小结
最后,我们再来做一个小结。