1.门面模式
1.1门面模式定义
又叫外观模式,提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构性模式。
1.2门面模式应用场景
1.2.1子系统越来越复杂,增加门面模式提供简单接口
1.2.2构建多层系统结构,利用门面对象作为每层的入口,简化层间调用。
1.3门面模式通用写法
门面模式主要包含2 种角色:统一接口(门面角色,类图中的Facade) ,子系统角色(类图中的SubSystemA、SubSystemB、SubSystemC)
1.4门面模式业务场景实例
public class GiftInfo { private String name; public GiftInfo(String name) { this.name = name; } public String getName() { return name; } } //子系统角色 public class PaymentService { public boolean pay(GiftInfo giftInfo){ System.out.println("扣减" + giftInfo.getName() + " 积分成功"); return true; } } //子系统角色 public class QualifyService { public boolean isAvailable(GiftInfo giftInfo){ System.out.println("校验" +giftInfo.getName() + "积分通过,库存通过。"); return true; } } //子系统角色 public class ShippingService { public String delivery(GiftInfo giftInfo){ System.out.println(giftInfo.getName() + "进入物流系统"); String shippingNo = "666"; return shippingNo; } } //外观角色 public class FacadeService { private QualifyService qualifyService = new QualifyService(); private PaymentService paymentService = new PaymentService(); private ShippingService shippingService = new ShippingService(); public void exchange(GiftInfo giftInfo){ if(qualifyService.isAvailable(giftInfo)){ if(paymentService.pay(giftInfo)){ String shippingNo = shippingService.delivery(giftInfo); System.out.println("物流系统下单成功,物流单号是:" + shippingNo); } } } } //测试类 public class Test { public static void main(String[] args) { FacadeService facadeService = new FacadeService(); GiftInfo giftInfo = new GiftInfo("《Spring 5核心原理》"); facadeService.exchange(giftInfo); } }
测试结果展示
校验《Spring 5核心原理》积分通过,库存通过。
扣减《Spring 5核心原理》 积分成功
《Spring 5核心原理》进入物流系统
物流系统下单成功,物流单号是:666
1.5门面模式在源码中的应用
1.5.1Spring JDBC 模块下的JdbcUtils 类,它封装了和JDBC 相关的所有操作
1.5.2MyBatis 中的Configuration 类。它其中有很多new 开头的方法
1.5.3Tomcat 的源码中RequestFacade 类它封装了非常多的request 的操作,也整合了很多servlet-api 以外的一些内容,给用户使用提供了很大便捷。同样,Tomcat 对Response 和Session 当也封装了
ResponseFacade 和StandardSessionFacade 类。
1.6门面模式的优缺点
1.6.1优点:
1、简化了调用过程,无需深入了解子系统,以防给子系统带来风险。
2、减少系统依赖、松散耦合
3、更好地划分访问层次,提高了安全性
4、遵循迪米特法则,即最少知道原则。
1.6.2缺点:
1、当增加子系统和扩展子系统行为时,可能容易带来未知风险
2、不符合开闭原则
3、某些情况下可能违背单一职责原则。
2.装饰器模式
2.1定义
在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。装饰器模式的核心是功能扩展。使用装饰器模式可以透明且动态地扩展类的功能。
通用装饰器UML图:
如上图,装饰器主要包括4种角色:
1).抽象组件(Component):可以是一个接口或者抽象类,其充当被装饰类的原始对象,规定了被装饰对象的行为;
2).具体组件(ConcreteComponent):实现或继承Component 的一个具体对象,也即被装饰对象;
3).抽象装饰器(Decorator):通用的装饰ConcreteComponent 的装饰器.内部构成包括:
a.一个属性指向Component 抽象组件
b.该类一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个Component 抽象组件,这是强制的通用行为.
c.具体装饰器(ConcreteDecorator):Decorator 的具体实现类,理论上,每个ConcreteDecorator都扩展了Component 对象的一种功能;
抽象装饰器源码:
public abstract class Decorator extends Component { /** * 持有组件对象 */ protected Component component; /** * 构造方法,传入组件对象 * @param component 组件对象 */ public Decorator(Component component) { this.component = component; } public void operation() { //转发请求给组件对象,可以在转发前后执行一些附加动作 component.operation(); } }
测试类源码:
public class Client{ public static void main(String[] args){ Component c1 = new ConcreteComponent (); //首先创建需要被装饰的原始对象(即要被装饰的对象) Decorator decoratorA = new ConcreteDecoratorA(c1); //给对象透明的增加功能A并调用 decoratorA .operation(); Decorator decoratorB = new ConcreteDecoratorB(c1); //给对象透明的增加功能B并调用 decoratorB .operation(); Decorator decoratorBandA = new ConcreteDecoratorB(decoratorA);//装饰器也可以装饰具体的装饰对象,此时相当于给对象在增加A的功能基础上在添加功能B decoratorBandA.operation(); } }
2.2装饰器模式在源码中的应用
2.2.1JDK 中体现最明显的类就是IO 相关的类, 如BufferedReader、InputStream、OutputStream.类图如下:
2.2.2Spring 中的TransactionAwareCacheDecorator 类。这个类主要是用来处理事务缓存的。
public class TransactionAwareCacheDecorator implements Cache { private final Cache targetCache; public TransactionAwareCacheDecorator(Cache targetCache) { Assert.notNull(targetCache, "Target Cache must not be null"); this.targetCache = targetCache; }p ublic Cache getTargetCache() { return this.targetCache; } ... }
2.2.3MVC 中的装饰器模式HttpHeadResponseDecorator 类
2.3装饰器模式和代理模式对比
2.3.1装饰器模式其实是一种特殊的代理模式
2.3.2装饰器模式强调自身功能的扩展,着重类功能的变化
2.3.3代理模式强调对代理过程的控制
2.4装饰器模式的优缺点
2.4.1优点:
1)装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。
2)通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。
3)装饰器完全遵守开闭原则
2.4.2缺点
1)会出现更多的代码,更多的类,增加程序复杂性。
2)动态装饰时,多层装饰时会更复杂。