Java代理设计模式总结

1.代理设计模式是什么?

Proxy Pattern。所谓代理设计就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。
如客户买电脑。
&&以前的模式:客户直接找厂家买。
&&使用了代理模式后:代理商找厂家拿货,由代理商卖电脑给客户,代理商给客户提供一些售后服务(解决不了得问题再拿回给厂家)。
如:

interface IProduct{                 //产品(即接口)
    public void sell();
}

class Producer implements IProduct{     //厂家(即真实主题)
    public void sell() {
        System.out.println("客户取得商品(真实主题)");
    }
}

class Proxy implements IProduct{        //代理商(即代理主题)
    private IProduct product;
    public Proxy(IProduct product){     //设置代理的真实操作
        this.product=product;           //设置代理的子类
    }
    public void afterServiece() {
        System.out.println("售后服务(代理主题)");
    }
    public void sell() {
        this.afterServiece();           //调用与具体业务相关的操作
        this.product.sell();            //调用厂家(真实主题)操作
    }
}

public class Demo {                     //客户
    public static void main(String[] args)throws Exception {
        IProduct product =null;
        product=new Proxy(new Producer());//实例化代理,同时传入代理的真实操作
        product.sell();
    }
}

以上代码使用的就是静态代理模式。
代理设计模式基本结构:①接口②真实主题③代理主题④主类。

2.为什么要有代理设计模式?

①为了解决直接访问对象时带来的问题。当两个类需要通信时,引入第三方代理类,将两个类的关系解耦。②不修改源码的基础上对方法增强。
这样客户只需要了解代理类即可。

3.代理设计模式如何使用?

首先,先明确代理设计模式分为静态代理和动态代理。

4.既然有了静态代理为什么还要有动态代理?

静态代理设计模式的缺点:当代理功能比较多时,代理类中方法需要写很多,维护也比较困难。(接口一旦改变,代理类也需要改变)
动态代理设计模式,就是为了解决上述问题。

5.它们的区别:

静态:在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成,即字节码随用随创建,随用随加载。

6.动态代理模式:

(1)基于接口的动态代理:

		涉及的类:Proxy
		提供者:JDK官方
		如何创建代理对象:使用Proxy类中的newProxyInstance方法
		创建代理对象的要求:被代理类最少实现一个接口,如果没有则不能使用。
		newProxyInstance方法的参数:
			ClassLoader:类加载器
				它是用于加载代理对象字节码的。和被代理对象使用相同的类加载器。固定写法
			Class[]:字节码数组
				它是用于让代理对象和被代理对象有相同的方法。固定写法。
			InvocationHander:用于提供增强的代码
				它是让我们写如何代理。我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
				此接口的实现类都是谁用谁写。
				此方法的参数在下面代码中有说明。

Producer接口:

package com.proxy;
//对生产厂家要求的接口
public interface IProducer {
    public void saleProduct(float money);
    public void afterService(float money);
}

Producer类:

package com.cglib;
import com.proxy.IProducer;

public class Producer {
    //销售
    public void saleProduct(float money){
        System.out.println("销售产品并拿到钱,"+money);
    }
    //售后
    public void afterService(float money){
        System.out.println("提供售后服务并拿到钱,"+money);
    }
}
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//模拟一个消费者
public class Client {
    public static void main(String[] args) {
        final Producer producer=new Producer();
        IProducer proxyProducer=(IProducer) Proxy.newProxyInstance(producer.getClass().getClassLoader(),
                producer.getClass().getInterfaces(),
                new InvocationHandler() {
                    /**
                     * 作用:执行被代理对象的任何接口方法都会经过该方法。
                     * 方法参数的含义:
                     * @param proxy     代理对象的引用
                     * @param method    当前执行的方法
                     * @param args      当前执行方法所需的参数
                     * @return          和被代理对象有相同的返回值
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //提供增强的代码
                        Object returnValue =null;
                        //1.获取方法执行的参数
                        Float money=(Float)args[0];
                        //2.判断当前方法是不是销售
                        if("saleProduct".equals(method.getName())) {
                            returnValue= method.invoke(producer, money*0.8f);
                        }
                        return returnValue;
                    }
                });
        proxyProducer.saleProduct(10000f);
    }
}
//执行结果:销售产品并拿到钱,8000.0

(2)基于子类的动态代理:

		涉及的类:Enhancer
		提供者:第三方cglib库
		如何创建代理对象:使用Enhancer类中的create方法
		创建代理对象的要求:被代理类不能是最终类(被final修饰的类,不可继承的类)
		create方法的参数:
			Class:字节码
				它是用于指定被代理对象的字节码
			Callback:用于提供增强的代码
				它是让我们写如何代理。我们一般都是写一个该接口的实现类,通常情况下都是匿名内部类,但不是必须的。
				此接口的实现类都是谁用谁写。
				我们一般写的都是该接口的子接口实现类:MethodInterceptor

Producer类:

package com.cglib;
import com.proxy.IProducer;
public class Producer {
    //销售
    public void saleProduct(float money){
        System.out.println("销售产品并拿到钱,"+money);
    }
    //售后
    public void afterService(float money){
        System.out.println("提供售后服务并拿到钱,"+money);
    }
}
package com.cglib;
import com.proxy.IProducer;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//模拟一个消费者
public class Client {
    public static void main(String[] args) {
        final Producer producer =new Producer();
        Producer cglibProducer =(Producer)Enhancer.create(producer.getClass(), new MethodInterceptor() {
            /**
             * 执行被代理对象的任何方法都会经过该方法
             * @param proxy
             * @param method
             * @param args
             * ------以上三个参数和基于接口的动态代理中invoke方法的参数是一样的
             * @param methodProxy  当前执行方法的代理对象
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[]args, MethodProxy methodProxy) throws Throwable {
                //提供增强的代码
                Object returnValue =null;
                //1.获取方法执行的参数
                Float money=(Float)args[0];
                //2.判断当前方法是不是销售
                if("saleProduct".equals(method.getName())) {
                    returnValue= method.invoke(producer, money*0.8f);
                }
                return returnValue;
            }
        });
        cglibProducer.saleProduct(12000f);
    }
}

(3)说明:

其实无论是基于接口还是基于子类的动态代理,只要掌握了方法(newProxyInstance|create)的参数,基本就会了。

发布了30 篇原创文章 · 获赞 1 · 访问量 1885

猜你喜欢

转载自blog.csdn.net/Zzh1110/article/details/104190322