设计模式-8.代理模式

1.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。用户可以在代理对象中操作原对象。

2.代理模式的一般应用:提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求。

3.代理模式分为静态代理和动态代理

  现在用一个小需求展示:给所有方法添加日志打印功能 打印请求参数。

public class Calculator {

	//加
	public int add(int a, int b) {
		int result = a + b;
		return result;
	}

	//减
	public int subtract(int a, int b) {
		int result = a - b;
		return result;
	}

	//乘法、除法...
}

4.很多时候我们都是直接在方法体内打印

public class Calculator {

	//加
	public int add(int a, int b) {
		System.out.println("add方法开始...");
		int result = a + b;
		System.out.println("add方法结束...");
		return result;
	}

	//减
	public int subtract(int a, int b) {
		System.out.println("subtract方法开始...");
		int result = a - b;
		System.out.println("subtract方法结束...");
		return result;
	}

	//乘法、除法...
}

上面的方案是有问题的:

  1. 直接修改源程序,不符合开闭原则。应该对扩展开放,对修改关闭
  2. 如果Calculator有几十个、上百个方法,修改量太大
  3. 存在重复代码(都是在核心代码前后打印日志)
  4. 日志打印硬编码在代理类中,不利于后期维护:比如你花了一上午终于写完了,组长告诉你这个功能取消,于是你又要打开Calculator花十分钟删除日志打印的代码!

静态代理实现日志打印

目标接口

public interface Calculator {

	//加法
	public int add(int a,int b);
	//减法
	public int subtract(int a,int b);
	
	
}

 目标接口的实现类

package com.newland.draw.jdkproxy;

public class CalculatorImpl implements Calculator{

	@Override
	public int add(int a, int b) {
		// TODO Auto-generated method stub
		return a+b;
	}

	@Override
	public int subtract(int a, int b) {
		// TODO Auto-generated method stub
		return a-b;
	}

}

静态代理对象类

package com.newland.draw.jdkproxy;

public class CalculatorStaticProxy implements Calculator{

	private Calculator target;
	
	public CalculatorStaticProxy(Calculator target) {
		this.target = target;
	}
	
	@Override
	public int add(int a, int b) {
		System.out.println("add方法开始...");
		int result = target.add(a, b);
		System.out.println("add方法结束...");
		return result;
	}

	@Override
	public int subtract(int a, int b) {
		System.out.println("subtract方法开始...");
		int result = target.subtract(a, b);
		System.out.println("subtract方法结束...");
		return result;
	}

	
}

客户端

package com.newland.draw.jdkproxy;

public class Client {

	public static void main(String[] args) {
		
		//把目标对象通过构造器塞入代理对象
		Calculator calculator = new CalculatorStaticProxy(new CalculatorImpl());
		//代理对象调用目标对象方法完成计算,并在前后打印日志
		calculator.add(1, 2);
		calculator.subtract(2, 1);

	}
}

输出结果:

 

静态代理的优点:可以在不修改目标对象的前提下,对目标对象进行功能的扩展和拦截。但是它也仅仅解决了上一种方案4大缺点中的第1点:

  1. 直接修改源程序,不符合开闭原则。应该对扩展开放,对修改关闭 √
  2. 如果Calculator有几十个、上百个方法,修改量太大 ×
  3. 存在重复代码(都是在核心代码前后打印日志) ×
  4. 日志打印硬编码在代理类中,不利于后期维护:比如你花了一上午终于写完了,组长告诉你这个功能取消,于是你又要打开Calculator花十分钟删除全部新增代码!×

静态代理的问题

上面案例中,代理类是我们事先编写的,而且要和目标对象类实现相同接口。由于CalculatorImpl(目标对象)需要日志功能,我们即编写了CalculatorProxy(代理对象),并通过构造器传入CalculatorImpl(目标对象),调用目标对象同名方法的同时添加增强代码。

但是这里有个问题!代理对象构造器的参数类型是Calculator,这意味着它只能接受Calculator的实现类对象,亦即我们写的代理类CalculatorProxy只能给Calculator做代理,它们绑定死了!

如果现在我们系统需要全面改造,给其他类也添加日志打印功能,就得为其他几百个接口都各自写一份代理类...

 

自己手动写一个类并实现接口实在太麻烦了。仔细一想,我们其实想要的并不是代理类,而是代理对象!那么,能否让JVM根据接口自动生成代理对象呢?

比如,有没有一个方法,我传入接口,它就给我自动返回代理对象呢?

答案是肯定的。这就引出了动态代理,动态代理分为JDK代理和CGLIB动态代理,在设计模式当中就不细讲了,我会放在spring中讲解。

最详细JDK动态代理地址:https://blog.csdn.net/qq_38669394/article/details/107212422

CGLIB动态代理地址:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值