结构型模式Structural Pattern

结构型模式Structural Pattern

概念

  • 描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过 简单积木的组合形成复杂的、功能更为强大的结构

分类

  • 类结构型模式

    • 该结构模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系
  • ⭐️对象结构型模式

    • 该结构模式关心类与对象的组合,通过关联关系(代理类通过成员变量已用另一个类对象)使得在一 个类中定义另一个类的实例对象,然后通过该对象调用其方法
  • 总结:根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式

对象结构型模式

  • 代理模式(Proxy Pattern)

    • 静态代理

      • 动机

        • 为其他对象提供一种代理对象以控制对这个对象的访问,代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。
      • 模式结构

        • 包含的角色

          • Subject: 抽象主题角色,是真实对象和代理对象的共同接口
          • Proxy: 代理主题角色
          • RealSubject: 真实主题角色
        • UML类图

        • UML时序图

      • 什么是静态代理

        • 代理类和真实类要实现相同的接口,从而代理对象可以代替真实对象做同样的事情。
        • 代理类知道要代理的真实类,故在代理类的类内部声明真实类的对象。
        • 在代理类中,在代替真实类做同样的事情的时候可以添加新的操作。
      • 现实中的例子

        • HTTP代理
        • Spring AOP
      • 何时使用:想在访问一个类时做一些控制。

      • 如何解决:增加中间层。

      • 关键代码:实现与被代理类组合。

      • 特点

        • 优点

          • 职责清晰
          • 高拓展性
        • 缺点

          • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
          • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
    • 动态代理

      • 动态代理是一种较为高级的代理模式,它的典型应用就是Spring AOP

      • 什么是动态代理

        • 被代理的对象(真实主题(RealSubject))可以在运行时动态改变
        • 需要控制的接口(抽象主题(Subject))可以在运行时改变,控制的方式也可以动态改变,从而实现了非常灵活的动态代理关系。
      • 在传统的代理模式中,客户端通过Proxy调用RealSubject类的request()方法,同时还在代理类中封装了其他方法(如preRequest()postRequest()),可以处理一些其他问题。

        • 如果按照这种方法使用代理模式,那么真实主题角色必须是事先已经存在的,并将其作为代理对象的内部成员属性。如果一个真实主题角色必须对应一个代理主题角色,这将导致系统中的类个数急剧增加,因此需要想办法减少系统中类的个数,此外,如何在事先不知道真实主题角色的情况下使用代理主题角色,这都是动态代理需要解决的问题。
      • 代码示例

          public void doFilter(final ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
            final HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) resp;
        

        response.setContentType("text/html;charset=UTF-8");
            request.setCharacterEncoding("UTF-8");

        //放出去的是代理对象
            chain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader(), request.getClass().getInterfaces(), new InvocationHandler() {
              @Override
              public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //判断是不是getParameter方法
                if (!method.getName().equals("getParameter")) {

        //不是就使用request调用
                  return method.invoke(request, args);
                }

        //判断是否是get类型的
                if (!request.getMethod().equalsIgnoreCase("get")) {
                  return method.invoke(request, args);
                }

        //执行到这里,只能是get类型的getParameter方法了。
                String value = (String) method.invoke(request, args);
                if (value == null) {
                  return null;
                }
                return new String(value.getBytes("ISO8859-1"), "UTF-8");
              }

        }), response);

        }

      • 动态代理分析未完成

  • 装饰模式(Decorator)

    • 模式动机

      • 动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

        • 继承

          • 继承父类,子类来拓展功能,非常不灵活,而且会导致继承的层次增加,如果父类字段带有值,子类只能继承字段,但是不能让自己继承的字段有和父类一样的值
        • 装饰器模式

          • 通过使用包装的方式来增强对象,最适合用来增强功能,本质和代理模式一样,主要的功能都是由被装饰的对象完成
        • 代理模式

          • 可以用来增强功能,但是更多的为了访问控制,可以从UML类图中看出来
    • 别名

      • 其别名也可以称为包装器(Wrapper),与适配器模式的别名相同,但它们适用于不同的场合
    • 模式结构

      • 包含的角色

        • Component: 抽象构件
        • ConcreteComponent: 具体构件
        • Decorator: 抽象装饰类
        • ConcreteDecorator: 具体装饰类
      • UML类图

      • UML时序图

    • 我的实例

    • 特点

      • 优点

        • 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。
        • 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。
        • 通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。
        • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”
      • 缺点

        • 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。
    • 适用环境

      • 在不想增加很多子类的情况下扩展类。
      • 需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。
    • 和代理模式的区别

    • 精华总结

      • 装饰模式用于动态地给一个对象增加一些额外的职责,就增加对象功 能来说,装饰模式比生成子类实现更为灵活。它是一种对象结构型模 式。
      • 装饰模式包含四个角色:抽象构件定义了对象的接口,可以给这些对 象动态增加职责(方法);具体构件定义了具体的构件对象,实现了 在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法); 抽象装饰类是抽象构件类的子类,用于给具体构件增加职责,但是具 体职责在其子类中实现;具体装饰类是抽象装饰类的子类,负责向构 件添加新的职责。
      • 使用装饰模式来实现扩展比继承更加灵活,它以对客户透明的方式动 态地给一个对象附加更多的责任。装饰模式可以在不需要创造更多子 类的情况下,将对象的功能加以扩展。
      • 装饰模式的主要优点在于可以提供比继承更多的灵活性,可以通过一种动态的 方式来扩展一个对象的功能,并通过使用不同的具体装饰类以及这些装饰类的 排列组合,可以创造出很多不同行为的组合,而且具体构件类与具体装饰类可 以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类;其主要缺 点在于使用装饰模式进行系统设计时将产生很多小对象,而且装饰模式比继承 更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需 要逐级排查,较为烦琐。
      • 装饰模式适用情况包括:在不影响其他对象的情况下,以动态、透明的方式给 单个对象添加职责;需要动态地给一个对象增加功能,这些功能也可以动态地 被撤销;当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展 和维护时。
      • 装饰模式可分为透明装饰模式和半透明装饰模式:在透明装饰模式中,要求客 户端完全针对抽象编程,装饰模式的透明性要求客户端程序不应该声明具体构 件类型和具体装饰类型,而应该全部声明为抽象构件类型;半透明装饰模式允 许用户在客户端声明具体装饰者类型的对象,调用在具体装饰者中新增的方法。
  • 子主题 5

    • 注意事项: 1、和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 2、和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
posted @ 2025-03-14 10:38  红豆绿豆abc  阅读(806)  评论(0)    收藏  举报