天天看点

设计模式GOF23之第二回

1. 概述

结构型模式的作用:从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题。

2. 适配器模式(Adapter)

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

设计模式GOF23之第二回

常见的的使用,字节流转字符流就是使用适配器模式。

java.io.InputStreamReader(InputStream)

java.io.OutputStreamWriter(OutputStream)

3. 代理模式(Proxy)

通过代理,控制对对象的访问! 使对象专注于核心逻辑的处理。

可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。(即:AOP的微观实现!)

AOP(Aspect Oriented Programming面向切面编程)的核心实现机制!实现了横向,跨类的代码共享。

应用场景:

  • 安全代理:屏蔽对真实角色的直接访问。
  • 远程代理:通过代理类处理远程方法调用(RMI)
  • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。

分类:

  • 静态代理(静态定义代理类)
  • 动态代理(动态生成代理类)
  • JDK自带的动态代理
  • javaassist字节码操作库实现
  • CGLIB
  • ASM(底层使用指令,可维护性较差)

静态代理

设计模式GOF23之第二回

动态代理

  1. JDK自带的动态代理

    java.lang.reflect.Proxy

    作用:动态生成代理类和对象

  2. java.lang.reflect.InvocationHandler(处理器接口)

    可以通过invoke方法实现对真实角色的代理访问

    每次通过Proxy生成代理类对象时都要指定对应的处理器对象

设计模式GOF23之第二回

被代理的对象会通过handler成员变量,在每一个方法内部调用invoke(),因此被代理对象所有方法的调用都会进入invoke()方法体内处理。

开源的AOP框架:AspectJ

4. 桥接模式(Bridge)

层次继承结构中,如果新增一个类别,则需在各分支下新增很多类,导致扩展性问题。

违反了单一职责原则。存在多个促使类变化的原因。

设计模式GOF23之第二回

构建正交的概念维度,使类之间相互独立。

设计模式GOF23之第二回

引入桥接模式后

使用组合来代替继承关系。

设计模式GOF23之第二回

桥接模式总结:

桥接模式可以取代多层继承的方案。 多层继承违背了单一职责原则,复用性较差,类的个数也非常多。桥接模式可以极大的减少子类的个数,从而降低管理和维护的成本。

桥接模式极大的提高了系统可扩展性,在两个变化维度中任意扩展一个维度,都不需要修改原有的系统,符合开闭原则。

桥接模式实际开发中应用场景

  • JDBC驱动程序
  • AWT中的Peer架构
  • 银行日志管理:
  • 格式分类:操作日志、交易日志、异常日志
  • 距离分类:本地记录日志、异地记录日志
  • 人力资源系统中的奖金计算模块:
  • 奖金分类:个人奖金、团体奖金、激励奖金。
  • 部门分类:人事部门、销售部门、研发部门。
  • OA系统中的消息处理:
  • 业务类型:普通消息、加急消息、特急消息
  • 发送消息方式:系统内消息、手机短信、邮件

5. 组合模式(Composite)

使用组合模式的场景:

  • 把部分和整体的关系用树形结构来表示,从而使客户端可以使用统一的方式处理部分对象和整体对象。

组合模式核心:

  • 抽象构件(Component)角色: 定义了叶子和容器构件的共同点
  • 叶子(Leaf)构件角色:无子节点
  • 容器(Composite)构件角色: 有容器特征,可以包含子节点

组合模式工作流程分析:

  • 组合模式为处理树形结构提供了完美的解决方案,描述了如何将容器和叶子进行递归组合,使得用户在使用时可以一致性的对待容器和叶子。
  • 当容器对象的指定方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并调用执行。其中,使用了递归调用的机制对整个结构进行处理。
设计模式GOF23之第二回

6. 装饰模式(Decorator)

职责:

  • 动态的为一个对象增加新的功能。
  • 装饰模式是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
设计模式GOF23之第二回
设计模式GOF23之第二回

上图中SuperCar就是Decorator。它作为父类(抽象类)用于保存传进来的对象参数。

总结:

  • 装饰模式(Decorator)也叫包装器模式(Wrapper)
  • 装饰模式降低系统的耦合度,可以动态地增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类。

优点

  • 扩展对象功能,比继承灵活,不会导致类个数急剧增加
  • 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
  • 具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类。

缺点

  • 产生很多小对象。大量小对象占据内存,一定程度上影响性能。
  • 装饰模式易于出错,调试排查比较麻烦。

装饰模式和桥接模式的区别:

两个模式都是为了解决过多子类对象问题。但他们的诱因不一样。桥模式是对象自身现有机制​

​沿着多个维度变化​

​​,是既有部分不稳定。装饰模式是为了​

​增加新的功能​

​。

7. 外观模式(Facade)

迪米特法则(最少知识原则):

一个软件实体应当尽可能少的与其他实体发生相互作用。

设计模式GOF23之第二回

外观模式核心:

为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。未使用外观模式时

设计模式GOF23之第二回

外观模式

设计模式GOF23之第二回

RegisterFacade类提供了统一处理的界面,收敛了面向客户端的界面。

在各类工具类XXUtils中都用到了这个“门面”的思想。

8. 享元模式(FlyWeight,轻量级)

场景:

  • 内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的对象,我们可以通过享元模式,节省内存。

核心:

  • 享元模式以共享的方式高效地支持大量细粒度对象的重用。

享元对象能做到共享的关键是区分了内部状态和外部状态。

  • 内部状态:可以共享,不会随环境变化而改变
  • 外部状态:不可以共享,会随环境变化而改变

享元模式的实现

设计模式GOF23之第二回

实现要点:

  • 工厂 + 私有属性(享元池)
  • 外部状态用专门的类对象单独处理
  • 内部状态使用享元类单独处理
设计模式GOF23之第二回

享元模式常见于各类资源池,如:String常量池,数据库连接池,线程池等。

  • 极大减少内存中对象的数量
  • 相同或相似对象内存中只存一份,极大的节约资源,提高系统性能
  • 外部状态相对独立,不影响内部状态
  • 模式较复杂,使程序逻辑复杂化
  • 为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长。
  • 用时间换取了空间。