美文网首页
设计模式之结构型(7)

设计模式之结构型(7)

作者: 宏势 | 来源:发表于2023-09-10 16:56 被阅读0次

结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

一.适配器模式

1.一句话描述

  • 修改一个类接口以适用用户期望的另一接口

2.类图/代码

image.png

Callable 目标接口, Runnable 被适配接口, RunnableAdapter适配类, 属于对象适配器

3.模式分类

根据适配类和被适配类的关系 分成两种

  • 对象适配模式: 适配类与被适配类是组合关系
  • 类适配模式: 适配类继承被适配类

4.实战案例

  • Spring工具包的枚举迭代器EnumerationIterator


    image.png
  • SpringMVC的HandlerAdapter


    image.png
  • JDK RunnableAdapter类 把Runnable 适配成Callable

5.总结

  • 1.接口转换, 转换成用户期望的接口
  • 2.代码复用,可以复用旧类(被适配类)代码
  • 3.便于扩展, 只需增加适配器类就可以使其与现有代码无缝集成

生活中的插座/转接线 也是非常典型的适配模式,

二、装饰器模式

1.一句话描述

  • 在原有的类上增强一个类的功能

2.类图

image.png

FilterInputStream 是装饰器, 以组合方式引用 Inpustream, 增强具体InputStream之类的功能

3. 实战案例

  • JDK IO输入流设计


    image.png
  • JDK IO输出流设计


    image.png

4.总结

1.动态地将功能附加到类上,无需修改原有类代码, 灵活性高
2.每个具体装饰器类专注于一个特定功能, 吻合单一职责原则
3.多个装饰器可以按需组合,实现复杂的功能组合

三、代理模式

1. 一句话描述

  • 用代理对象来代替真实对象,以控制对真实对象的访问

2.类图/代码/分类

代理分为静态代理动态代理

(1)静态代理

静态代理在编译时就将接口、实现类、代理类编译成class文件。


静态代理.png

(2)动态代理

动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

JDK动态代理:

RealSubject realSubject = new RealSubject();
Class c = realSubject.getClass();
Subject subject = (Subject) Proxy.newProxyInstance(c.getClassLoader(), c.getInterfaces(), new DynamicInvocationHandler(realSubject));
 subject.request();
class DynamicInvocationHandler implements InvocationHandler{
    private RealSubject realSubject;

    public DynamicInvocationHandler(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("pre ...");
        Object object =  method.invoke(realSubject,args);
        System.out.println("after ....");
        return object;
    }
}

CGLIB动态代理:

        RealSubject realSubject = new RealSubject();
        Class c = realSubject.getClass();
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(c.getClassLoader());
        // 设置被代理类
        enhancer.setSuperclass(c);
        // 设置方法拦截器
        enhancer.setCallback(new CGLibMethodInterceptor());
        RealSubject proxy = (RealSubject) enhancer.create();
        proxy.request();
class CGLibMethodInterceptor implements MethodInterceptor{

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("pre ...");
        Object object =  methodProxy.invokeSuper(o,objects);
        System.out.println("after ....1111");
        return object;
    }
}

3.实战案例

  • Spring AOP 动态代理, 如目标对象实现了接口默认使用JDK动态代理,否则采用CGLIB动态代理

4.总结

动态代理有JDK 动态代理、CGLIB 动态代理
JDK动态代理只能代理实现了接口的类,CGLIB可以代理未实现任何接口的类(继承)
JDK动态代理直接写Class字节码,CGLIB代理使用ASM框架写Class字节码,相对复杂,生成代理类的效率比较低

四、外观模式

1. 一句话描述

  • 提供统一访问入口

2.类图/代码

image.png

3.实战案例

  • SLFJ中的外观模式, 抽象了各种日志框架Logback, log4j, commons-logging, logging
  • spring jdbc中的外观模式 JdbcUtils
  • Tomcat中org.apache.catalina.connector.RequestFacade

4.总结

1.简化接口,让接口更简单,引入外观类可以将子系统与客户端解耦
2.吻合迪米特法则
3.只需增加一个外观类,客户端只跟外观类交互,由外观类跟多个子系统类交互

五、桥接模式

1.一句话描述

  • 把抽象和实现分离,使他们能独立改变

2.类图

image.png

3.实战案例

4.总结

  1. 解决一个类存在两个独立变化的维度且两个维度都需要进行扩展(吻合开闭原则)
  2. 采用组合方式,更加灵活(吻合 合成/聚合复用原则)

六、组合模式

1.一句话描述

  • 可以以一致的方式处理个别对象和对象组合(整体/部分)

2.类图

image.png

3.实战案例

  • 业务系统中菜单就是经典组合模式

4.总结

经常跟迭代器模式在一起对比,其实代码结构类似,迭代器模式侧重的遍历这个行为,是行为模式,而组合模式关注重点是结构关系,即整理和部分

七、享元模式

1.一句话描述

  • 该模式通过共享技术支持大量细粒度对象复用,以减少内存使用量

2.类图

image.png

3.实战案例

  • Integer、Long、Short、Byte等都是利用了享元模式来缓存-128到127之间的数据
       Integer i1 = 12;
       Integer i2 = new Integer(12);  //无法利用享元
        Integer i3 = Integer.valueOf(12);
        System.out.println(i==i1); //true
        System.out.println(i==i2); //false
        System.out.println(i==i3); //true
  • JVM为String类开辟 字符串常量池,存储字符串常量

  • 游戏中的道具、棋子(俄罗斯方块)

4.总结

  • 当需要创建大量相似对象时,抽取享元类(复用)和非享元类,以减少内存使用

享元模式VS单例模式,单例模式是为了保证对象全局唯一,享元模式对象复用,节省内存(多例)

相关文章

网友评论

      本文标题:设计模式之结构型(7)

      本文链接:https://www.haomeiwen.com/subject/tgmnudtx.html