为了账号安全,请及时绑定邮箱和手机立即绑定

结构型设计模式

标签:
Java


架构型设计模式成员

门面模式

代理模式

装饰器模式

组合模式

享元模式

桥接模式

适配器模式

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动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理

©著作权归作者所有:来自51CTO博客作者悠娜的奶爸的原创作品,如需转载,请注明出处,否则将追究法律责任


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消