运维开发网

结构型设计模式

运维开发网 https://www.qedev.com 2020-02-12 11:28 出处:网络 作者:悠娜的奶爸
架构型设计模式成员门面模式代理模式装饰器模式组合模式享元模式桥接模式适配器模式1.代理模式1.1定义为其他对象提供一种代理以控制对这个对象的访问解决问题:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上

架构型设计模式成员

  • 门面模式
  • 代理模式
  • 装饰器模式
  • 组合模式
  • 享元模式
  • 桥接模式
  • 适配器模式

1. 代理模式

1.1 定义

为其他对象提供一种代理以控制对这个对象的访问

解决问题:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层

1.2 分类

1.2.1 静态代理

  • 一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行
  • 而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码
接口类

package com.zhunongyun.spring.proxy;

public interface Image {
   void display();

   void change(String imagePath);
}

--------------------------------------------------

接口的实现类

package com.zhunongyun.spring.proxy;

public class RealImage implements Image {

   private String fileName;

   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }

   @Override
   public void display() {
      System.out.println("显示图片: " + fileName);
   }

   @Override
   public void change(String imagePath) {
      System.out.println("替换图片: " + imagePath);
   }

   private void loadFromDisk(String fileName){
      System.out.println("加载图片: " + fileName);
   }
}

-------------------------------------------------------

代理类

package com.zhunongyun.spring.proxy;

public class ProxyImage implements Image{

   private RealImage realImage;
   private String fileName;

   public ProxyImage(String fileName){
      this.fileName = fileName;
   }

   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }

   @Override
   public void change(String imagePath) {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.change(imagePath);
   }
}

---------------------------------------------------

测试类

package com.zhunongyun.spring.proxy;

public class ProxyPatternDemo {

   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");

      // 图像将从磁盘加载
      image.display(); 
      System.out.println("---------------------");
      // 图像不需要从磁盘加载
      image.display();  
   }
}

输出结果:
加载图片: test_10mb.jpg
显示图片: test_10mb.jpg
---------------------
显示图片: test_10mb.jpg

1.2.2 动态代理

1.2.2.1 JDK 自带的动态代理

  • java.lang.reflect.Proxy: 生成动态代理类和对象
  • java.lang.reflect.InvocationHandler(处理器接口):可以通过invoke方法实现对真实角色的代理访问

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

接口类

package com.zhunongyun.spring.proxy.dynamic;

public interface Subject {
    int sellBooks();

    String speak();
}

---------------------------------------------------------

接口实现类

package com.zhunongyun.spring.proxy.dynamic;

public class RealSubject implements Subject{
    @Override
    public int sellBooks() {
        System.out.println("卖书");
        return 1 ;
    }

    @Override
    public String speak() {
        System.out.println("说话");
        return "张三";
    }
}

------------------------------------------------------------------

动态代理类

package com.zhunongyun.study.toalibaba.spring.proxy.dynamic;

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

/**
 * 定义一个处理器
 *
 * @author gnehcgnaw
 * @date 2018/11/5 19:26
 */
public class MyInvocationHandler implements InvocationHandler {
    /**
     * 这其实业务实现类对象,用来调用具体的业务方法
     */
    private Object target;

    /**
     * 绑定业务对象并返回一个代理类
     */
    public Object bind(Object target) {
        //接收业务实现类对象参数
        this.target = target;

        //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
        //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    /**
     * @param proxy  代理类
     * @param method 正在调用的方法
     * @param args   方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Object result=null;

        System.out.println("预处理操作——————");
        //调用真正的业务方法  
        result=method.invoke(target, args);

        System.out.println("调用后处理——————");
        return result;
    }
}

-------------------------------------------------------------------

测试类

package com.zhunongyun.spring.proxy.dynamic;

import java.lang.reflect.Proxy;

/**
 * 调用类
 * @author gnehcgnaw
 * @date 2018/11/7 20:26
 */
public class Client {
    public static void main(String[] args) {
        //真实对象
        Subject realSubject =  new RealSubject();

        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
        //代理对象
        Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Subject.class}, myInvocationHandler);

        proxyClass.sellBooks();

        proxyClass.speak();
    }
}

------------------------------------------------------------------------
输出结果:

预处理操作——————
卖书
调用后处理——————
预处理操作——————
说话
调用后处理——————

1.2.2.2 CGlib动态代理

操作类

package com.zhunongyun.study.toalibaba.spring.proxy.cglib;

public class BookFacadeImpl {
    public void addBook() {  
        System.out.println("新增图书...");  
    }  
}  

-------------------------------------------

CGlib代理类

package com.zhunongyun.study.toalibaba.spring.proxy.cglib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class BookFacadeCglib implements MethodInterceptor {
    /**
     * 业务类对象,供代理方法中进行真正的业务方法调用
     */
    private Object target;

    /**
     * 相当于JDK动态代理中的绑定
     * @param target
     * @return
     */
    public Object getInstance(Object target) {
        //给业务对象赋值
        this.target = target;

        //创建加强器,用来创建动态代理类
        Enhancer enhancer = new Enhancer();

        //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        enhancer.setSuperclass(this.target.getClass());

        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this);

        // 创建动态代理类对象并返回
        return enhancer.create();
    }

    /**
     * 实现回调方法
     * @param obj
     * @param method
     * @param args
     * @param proxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("预处理——————");

        //调用业务类(父类中)的方法
        proxy.invokeSuper(obj, args);
        System.out.println("调用后操作——————");
        return null;
    }
}

------------------------------------------------

测试类

package com.zhunongyun.study.toalibaba.spring.proxy.cglib;

public class CglibDemo {
    public static void main(String[] args) {
        BookFacadeImpl bookFacade = new BookFacadeImpl();

        BookFacadeCglib cglib = new BookFacadeCglib();

        BookFacadeImpl bookCglib = (BookFacadeImpl) cglib.getInstance(bookFacade);

        bookCglib.addBook();
    }
}

----------------------------------------

输出结果

预处理——————
新增图书...
调用后操作——————

1.2.2.3 JDK动态代理与CGlib动态代理

  • JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法
  • CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理
0

精彩评论

暂无评论...
验证码 换一张
取 消