04-结构型设计模式

nobility 发布于 2020-05-12 196 次阅读


结构型设计模式

适配器模式

定义

将一个类的接口转化成用户期望的另一个接口,使原本接口不兼容的类可以一起工作

UML类图

适配器模式

适用场景

  • 已经存在的类,他的方法和需求不匹配时
  • 不是软件设计阶段考虑的,是随着维护,由于不同产品不同厂家造成功能类似,接口不相同情况下的解决方案

优缺点

优点:提高类的透明性和复用性,现有的类复用但不需要改变,目标类和适配器类解耦,提高程序扩展性

缺点:适配器编写过程中需要全面考虑,可能会增加系统复杂性,增加系统代码可读难度

装饰器模式

定义

在不改变原有对象的基础上,将功能附加到对象上,是比继承更有弹性的替代方案,也是扩展原有对象功能

UML类图

装饰器模式

适用场景

  • 扩展一个类的功能,或添加附加职责时
  • 动态的给一个对象添加功能,这些功能也可以动态的撤销
  • 被装饰者和装饰品有不同的排列组合

优缺点

优点:是继承的补充,比继承灵活,未改变原有对象,而且使用不同装饰类以及这些装饰类的排列组合可以实现不同效果,扩展增加装饰类或装饰品也比较方便

缺点:会出现更多的代码和类,增加程序的复杂性,动态装饰和多层装饰会更加复杂

代理模式

定义

为其他对象提供一种代理, 以控制对这个对象的访问,代理对象在客户端和目标对象之间起中介作用

UML类图

静态代理

代理模式

动态代理

动态代理的动态是指动态生成代理类对象,通过JDK自带的API来实现

要求:被代理对象类要实现接口

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class Main {
  static interface Inter {
    void hello();
  }

  static class Src implements Inter {
    @Override
    public void hello() {
      System.out.println("hello world");
    }
  }

  public static void main(String[] args) {
    Src src = new Src();  //要被代理的源对象
    /**
     * 动态代理类的创建接收三个参数
     * ClassLoader loader    :类加载器,一般与被代理对象使用同一个加载器
     * Class<?>[] interfaces :被代理类实现的接口,可以单独指定,也可以使用反射获取代理类实现所有接口
     * InvocationHandler h   :调用处理器对象,其中要实现invoke方法,拦截对源对象方法的调用
     *      invoke方法也接收三个参数
     *      Object proxy  :指向生成的代理对象
     *      Method method :运行时所调用的方法,method.getName()可获得具体方法名
     *      Object[] args :运行时所调用方法的参数
     */
    Inter proxy = (Inter) Proxy.newProxyInstance(src.getClass().getClassLoader(),
        src.getClass().getInterfaces(),
        new InvocationHandler() {
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            // before code
            Object res = method.invoke(src, args);	//反射调用被代理对象方法
            //after code
            return res;
          }
        });	//代理对象,必须要强转成要被代理对象的接口,而并非代理对象类
    proxy.hello();	//代理调用方法
    /**
     * 若调用处理器对象中逻辑足够简单可以使用lambda表达式,要注意lambda中的参数不要和外界冲突
     * (proxy1, method, args1) -> {
     *   // before code
     *   Object res = method.invoke(src, args1);
     *   //after code
     *   return res;
     * }
     */
  }
}
CGlib代理

也属于动态代理的一种,通过继承要被代理的类来实现的代理,所以并不需要被代理对象一定实现接口,被代理类也不能是final的,要代理的方法不能是final和static,因为这些都是无法继承的或复写的

需要引入相关jar包,从maven官网中查找CGlib并下载,以及下载相关依赖(ams、ant和junit)包导入项目即可

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class Main {

  static class Src {
    public void hello() {
      System.out.println("hello world");
    }
  }

  public static void main(String[] args) {
    Src src = new Src();  //要被代理的源对象
    Enhancer enhancer = new Enhancer(); //创建增强器,用来生成代理类对象
    enhancer.setSuperclass(src.getClass()); //设置要代理的类,即代理对象要继承的父类
    enhancer.setCallback(new MethodInterceptor() {
      @Override
      public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // before code
        Object res = method.invoke(src, args);
        //after code
        return res;
      }
    });
    //设置方法拦截器对象,即与jdk中调用处理器对象一举同工
    Src proxy = (Src) enhancer.create();  //创建代理对象,强转成要代理对象,即父类对象
    proxy.hello();  //代理调用方法
  }
}

适用场景

  • 保护目标对象
  • 增强目标对象

优缺点

优点:代理模式能将代理对象与真实被调用的目标对象分离,并且保护了目标对象,一定程度上降低系统耦合度,扩展性好

缺点:会造成系统设计中类的数目增加,增加了系统复杂度,客户与目标对象中间增加一个代理对象会造成请求处理速度变慢

外观模式

定义

提供一个统一的高层接口,用来访问子系统中的一群接口,让子系统更容易适用

UML类图

外观模式

适用场景

  • 子系统复杂,可增加外观模式提供简单调用接口
  • 构建多层系统结构,利用外观对象作为每层的入口,简化层间调用

优缺点

优点:简化了调用过程,无需了解深入子系统,防止带来风险,减少系统依赖、松散耦合,更好的划分访问层次

缺点:增加子系统、扩展子系统行为容易引入风险

桥接模式

定义

将抽象部分和与具体行为实现部分分离了,使之可以独立化变化,通过组合方式建立类之间关系而不是继承

UML类图

桥接模式

适用场景

  • 抽象和具体实现之间需要增加更多灵活性
  • 一个类存在两个或多个变化维度,并且这些维度需要独立变化,也就是说抽象部分需要独立扩展,实现部分也需要独立扩展
  • 不希望使用继承,或因为多层继承导致系统类个数爆炸

优缺点

优点:分离抽象部分以及具体实现部分,提高了系统的可扩展性

缺点:增加了系统的理解和设计难度,需要能正确的识别出系统中两个独立变化的维度

组合模式

定义

将对象组成树形结构表示部分到整体的层次结构(包含关系),客户对单个对象和组合对象保持一致处理方式

UML类图

组合模式

适用场景

  • 希望客户可以忽略组合对象与单个对象的差异
  • 处理树形结构时

优缺点

优点:清楚定义分层次的复杂对象,表示对象全部或部分层次,使得客户忽略层次差异,从而方便对整个层次结构进行控制,同时还简化了客户的代码

缺点:限制类型时较为复杂,并且设计会更加抽象

享元模式

定义

提供减少对象数量从而改善应用所需的对象结构方式,使用共享技术有效的支持大量细粒度的对象

UML类图

享元模式

适用场景

  • 用于系统底层开发,以便解决系统性能问题
  • 系统中有大量相似对象,需要缓冲池

优缺点

优点:减少对象创建,降低内存中对象的数量,降低系统的内存以及其他资源占用,提高效率

缺点:关注内外部状态和线程安全问题,使得系统程序逻辑复杂化

此作者没有提供个人介绍
最后更新于 2020-05-12