设计模式——代理模式

代理模式

代理模式通俗的将就是原来是自己做的事,现在交给别人去做

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强

image

  • 代理类和被代理类需要继承同一个接口,有相同的行为
  • 接口中的方法就可以被代理执行
  • 用户在通过接口调用方法时,执行的是代理类中实现的方法
  • 在代理类的内部,调用了被代理类
  • 实际接口的实现是由被代理类实现的
  • 代理类可以在原来的基础上扩展

代理又有静态代理和动态代理

静态代理

通过例子来模拟静态代理

模拟一下,委托别人买票的例子

我有1000元,想买一张票,但是自己买不到,委托别人去给我买,但是他需要收取小费才给我买票

首先要有一个共同的买票的行为,就是共同的接口

public interface BuyTicket {

    void buy(float money);
}

被代理人真正的实现这个接口

public class BuyTicketImpl implements BuyTicket {
    @Override
    public void buy(float money) {
        System.out.println("购票成功,花费了" + money + "元!");
    }
}

代理类通过构造器的方式将被代理类传递进来,并在买票之前收取小费

public class ProxyBuyTicketImpl implements BuyTicket {

    private BuyTicketImpl buyTicket;

    public ProxyBuyTicketImpl(BuyTicketImpl buyTicket) {
        this.buyTicket = buyTicket;
    }

    @Override
    public void buy(float money) {
        // 在买票之前需要收100小费
        money -= 100;
        System.out.println("收取了100的小费!");
        // 再真正的执行买票的操作
        buyTicket.buy(money);
    }
}
@Test
public void test1(){
	// 被代理类
	BuyTicketImpl buyTicket = new BuyTicketImpl();
	// 代理类
	ProxyBuyTicketImpl proxyBuyTicket = new ProxyBuyTicketImpl(buyTicket);
	proxyBuyTicket.buy(1000);
}

image

代理类和被代理类应该共同实现一个接口,或者是共同继承某个类
静态代理的类型是事先就确定好的,所以叫做动态代理

基于JDK的动态代理

JDK中提供了一个Proxy类来实现动态代理

该类中提供了一个newProxyInstance返回指定接口的代理类的实例

public static Object newProxyInstance(
    ClassLoader loader,
    Class<?>[] interfaces,
    InvocationHandler h
) throws IllegalArgumentException
  • loader 类加载器来定义代理类
  • interfaces 代理类实现的接口列表
  • h 调度方法调用的调用处理函数,这个就是代理具体要做的事情

依然是刚才的例子,使用JDK的动态代理来实现

首先要写一个调度方法

public class MyInvocationHandler implements InvocationHandler {

    BuyTicketImpl buyTicket;

    public MyInvocationHandler(BuyTicketImpl buyTicket) {
        this.buyTicket = buyTicket;
    }

    /**
    * 代理执行的具体操作
    */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("buy".equals(method.getName())){
            float money = (float) args[0];
            money -= 100;
            System.out.println("收了100的小费!");
            method.invoke(buyTicket, money);
        }
        return null;
    }
}

创建代理对象

@Test
public void test2(){
	// 被代理对象
	BuyTicketImpl buyTicket = new BuyTicketImpl();
	// 创建代理对象
	BuyTicket proxy = (BuyTicket) Proxy.newProxyInstance(
		buyTicket.getClass().getClassLoader(),
		buyTicket.getClass().getInterfaces(),
		new MyInvocationHandler(buyTicket)
	);
	// 代理执行
	proxy.buy(1000);
}

使用JDK的动态代理,我们就可以动态的生成代理,可以很方便的生成多个不同的代理

JDK的动态代理需要有一个代理的接口

基于cglib的动态代理

使用cglib的动态代理需要使用两个包
asm-4.1.jar
cglib-3.1.jar

并且使用cglib动态代理不需要接口就可以实现,可以直接给类创建一个代理对象

比如还是买票的例子

现在我只有类 并没有实现接口

public class BuyTicketImpl{
    public void buy(float money) {
        System.out.println("购票成功,花费了" + money + "元!");
    }
}

使用cglib动态代理

@Test
public void test03(){
	// 被代理对象
	BuyTicketImpl buyTicket = new BuyTicketImpl();

	//创建代理
	BuyTicketImpl buyTicketProxy = (BuyTicketImpl)Enhancer.create(buyTicket.getClass(), new InvocationHandler() {
		@Override
		public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
			if ("buy".equals(method.getName())) {
				float money = (float) objects[0];
				money -= 100;
				System.out.println("收了100的小费!");
				method.invoke(buyTicket, money);
			}
			return null;
		}
	});
	buyTicketProxy.buy(1000);
}

使用cglib也需要一个InvocationHandler出来,里面的方法就是具体代理要做的内容

posted @ 2021-12-07 17:08  茶音白  阅读(49)  评论(0)    收藏  举报