javaEE设计模式——门面模式

时间:2022-10-15 09:39:02

1.本节内容

  • 门面模式的意图介绍
  • 门面模式带来的好处
  • 门面模式的应用场景
  • 实现模式的3中方式:POJO、无状态与有状态回话Bean门面
  • 有状态与无状态回话Bean门面的重要差别
  • 关于门面模式使用的警告以及潜在陷阱

2.门面模式简介

  GoF一书中是这样描述门面模式的:“为子系统中的一组接口提供一个统一的接口”。Head First Design Patterns给出了相同的解释,同时又指出,在隐藏子系统复杂性的同时,门面模式又通过一个易于使用的接口提供子系统的全部功能。其基本类图如图2-1

javaEE设计模式——门面模式

图2-1 门面模式类图

3.门面模式带来的好处

  (1)降低了耦合度,因为客户端对子系统一无所知。

  (2)在变更时增强了可维护性和可管理性。

  (3)实现功能重用,因为门面模式鼓励控制重用以及细粒度逻辑。

  (4)每次方法调用时都会调用相同的方法,从而确保了服务执行的一致性。

  (5)分组相关方法并从一个方法调用中来调用它们,从而降低业务逻辑复杂度。

  (6)*化的安全与事务控制管理。

  (7)可测试性与可模拟性的模式实现。

4.门面模式的应用场景

  (1)为遗留的后端系统提供简单且统一的访问。

  (2)为类创建一个公开的API,如驱动程序。

  (3)为可用服务提供粗粒度访问。

  (4)减少网络调用。门面会对子系统发起多次调用,而远程客户端只对门面进行一次调用。

  (5)将应用的流程与内部细节封装起来,从而提升安全性并简化操作。

5.实现门面模式

5.1 POJO方式实现

public class WashingMachine {
/**
* 洗衣机呈现给用户的功能是
* 1.强力洗涤 2.轻度洗涤
* 那么用户在操作时只需要设定是强力洗涤还是轻度洗涤,不用取关心水温,转速等等
* 细粒度的功能
* 这就是一个典型的门面模式
*/
public void heavilySoiled(){
setWaterTemperature(100);
setWashCycleDuration(90);
setSpinCycleDuration(10);
addDetergent();
addBleach();
addFabricSoftener();
heatWater();
startWash();
} public void lightlySoiled(){
setWaterTemperature(40);
setWashCycleDuration(20);
setSpinCycleDuration(10);
addDetergent();
heatWater();
startWash();
}
private void startWash() {
} private void heatWater() {
} private void addFabricSoftener() { } private void addBleach() { } private void addDetergent() {
} private void setSpinCycleDuration(int i) { } private void setWashCycleDuration(int i) {
} private void setWaterTemperature(int i) {
}
}

5.2 无状态Bean的门面模式

@Stateless
public class CustomerService {
public long getCustomer(int sessionID){
return 100005L;
}
public boolean checkId(long x){
return true;
}
}
@Stateless
public class LoanService {
public boolean checkCreditRating(long id,double amount){
// check if customer is eligible for the amount
return true;
} }
public class AccountService {
public boolean getLoan(double amount){
//check if bank value has enough
return true;
}
public boolean setCustomerbalance(long id,double amount){
//set new customer balance
return true;
}
}
@Stateless
public class BankServiceFacade { @Inject
CustomerService customerService;
@Inject
LoanService loanService;
@Inject
AccountService accountService; public boolean getLoan(int sessionId,double amount){
boolean result = false;
long id = customerService.getCustomer(sessionId); if(customerService.checkId(id)){
if(loanService.checkCreditRating(id, amount)){
if(accountService.getLoan(amount)){
result = accountService.setCustomerbalance(id, amount);
}
}
}
return result;
}
}

  以上就是门面模式在javaEE中的应用,注意两个注解

    @Stateless:表示无状态session Bean

    @Inject:表示依赖注入

  从以上代码可以看出一个门面可以调用其他子系统中的门面,这反过来又会封装他们自己的逻辑与流程。这展示了使用门面的一个好处:简化了方法调用层级。

5.3 有状态Bean实现门面

  用状态Bean实现门面大体与无状态Bean实现门面一样,唯一不同的就是将@Stateless注解改为@Stateful注解,该注解会将Bean标记为有状态。

6 有关使用门面模式的警告和潜在威胁

  门面模式应该应用与高层封装复杂(业务)逻辑,并通过一个API提供整洁的访问单点。

  如果要为其他人提供一个接口或API,请首先考虑逻辑的复杂性,以及可能会出现的变更。门面模式在提供一个简洁的API的同时,又隐藏掉可能会发生变化的部分方面很有优势。

不过,毫无必要的将方法包装到门面中却不是一个好的做法,还会增加不必要的层次。不当的封装可能会导致太多的调用,以及毫无价值的层次。

  在实现会话门面时,需要确定用例是否需要维持状态,只调用门面的一个方法来接受所需服务的用例是非对话式的,因此没有必要在方法调用间保持会话状态,另一方面,如果必须在方法调用间保持会话状态,那么最恰当的方式就是将这种门面实现为有状态会话Bean。

  需要注意的就是,有状态会话门面使用时,他会占用服务器资源,直到客户端触发会话将其释放掉或时超时。这意味着在大多数时间内,有会话Bean门面会绑定到客户端,但却什么都没做,它仅维持着状态并使用资源。与无状态会话Bean门面不同的是,它无法在其他客户端之间重用和共享,因为,每个请求都会创建无状态门面的新实例,并且维持着对该客户端会话的状态。

7.小结

  可将门面模式实现为POJO、无状态会话Bean、有状态会话Bean。实现门面模式的各种方式解决了不同用例场景下的不同问题。不过在实现并没有背离其主要意图:为复杂的子系统提供一个高层次、简单的接口。

  在决定将门面实现为有状态会话Bean时要小心,确保它不会导致资源消耗问题。

  设计良好的应用会充分利用门面模式来封装复杂逻辑,并将子系统与客户端解耦;不过,对门面模式的不当使用和过度使用会导致更加复杂、拥有多个层次的系统。

  会话门面模式类似于实体-控制-边界架构模式中的边界,并且也与适配器和包装模式有关。