面向对象编程设计模式------代理模式(静态代理、动态代理)

本文详细介绍了代理模式,包括其定义、作用和关键角色。重点讲解了静态代理和动态代理,其中静态代理包括聚合和继承两种实现方式,而动态代理则主要讨论了JDK动态代理和CGLIB动态代理的实现机制和应用场景。通过实例展示了如何使用这些代理技术进行代码扩展和功能增强。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代理模式

  代理模式的定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
  代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
  这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。
  举个例子来说明代理的作用:假设我们想邀请一位明星,那么并不是直接联系明星,而是联系明星的经纪人,来达到同样的目的。明星就是一个目标对象,他只要负责活动中的节目,而其他琐碎的事情就交给他的代理人(经纪人)来解决。这就是代理思想在现实中的一个例子。

  代理模式的关键点是:代理对象与目标对象。代理对象是对目标对象的扩展,并会调用目标对象。
  代理模式包含如下角色:
  ISubject:抽象主题角色,是一个接口。该接口是对象和它的代理共用的接口。
  RealSubject:真实主题角色,是实现抽象主题接口的类。
  Proxy:代理角色,内部含有对真实对象RealSubject的引用,从而可以操作真实对象。代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
  代理模式的应用:
  远程代理:也就是为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。
  虚拟代理:是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。
  安全代理:用来控制真实对象访问时的权限。
  智能代理:是指当调用真实的对象时,代理处理一些另外的事情。
  一般将代理分类的话,可分为静态代理和动态代理两种。

静态代理

  静态代理比较简单,是由程序员编写的代理类,并在程序运行前就编译好的,而不是由程序动态产生代理类,这就是所谓的静态。
  考虑这样的场景,管理员在网站上执行操作,在生成操作结果的同时需要记录操作日志,这是很常见的。此时就可以使用代理模式,代理模式可以通过聚合和继承两种方式实现:

/**
 * @Description: 抽象主题接口
 * @author: zxt
 * @time: 2018年7月7日 下午2:29:46
 */
public interface Manager {
   
   
	public void doSomething();
}

/**
 * @Description: 真实的主题类
 * @author: zxt
 * @time: 2018年7月7日 下午2:31:21
 */
public class Admin implements Manager {
   
   
	@Override
	public void doSomething() {
   
   
		System.out.println("这是真实的主题类:Admin doSomething!!!");
	}
}

/**
 * @Description: 以聚合的方式实现代理主题
 * @author: zxt
 * @time: 2018年7月7日 下午2:37:08
 */
public class AdminPoly implements Manager {
   
   
	// 真实主题类的引用
	private Admin admin;
	
	public AdminPoly(Admin admin) {
   
   
		this.admin = admin;
	}
	
	@Override
	public void doSomething() {
   
   
		System.out.println("聚合方式实现代理:Admin操作开始!!");
		admin.doSomething();
		System.out.println("聚合方式实现代理:Admin操作结束!!");
	}
}

/**
 * @Description: 继承方式实现代理
 * @author: zxt
 * @time: 2018年7月7日 下午2:40:39
 */
public class AdminProxy extends Admin {
   
   
	@Override
	public void doSomething() {
   
   
		System.out.println("继承方式实现代理:Admin操作开始!!");
		super.doSomething();
		System.out.println("继承方式实现代理:Admin操作结束!!");
	}
}

public static void main(String[] args) {
   
   
	// 1、聚合方式的测试
	Admin admin = new Admin();
	Manager manager = new AdminPoly(admin);
	manager.doSomething();
	
	System.out.println("============================");
	// 2、继承方式的测试
	AdminProxy proxy = new AdminProxy();
	proxy.doSomething();
}

  聚合实现方式中代理类聚合了被代理类,且代理类及被代理类都实现了同一个接口,可实现灵活多变。继承式的实现方式则不够灵活。
  比如,在管理员操作的同时需要进行权限的处理,操作内容的日志记录,操作后数据的变化三个功能。三个功能的排列组合有6种,也就是说使用继承要编写6个继承了Admin的代理类,而使用聚合,仅需要针对权限的处理、日志记录和数据变化三个功能编写代理类,在业务逻辑中根据具体需求改变代码顺序即可。
  缺点:
  1)、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
  2)、代理对象只服务于一种类型的对象,如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。

动态代理

  实现动态代理的关键技术是反射。
  一般来说,对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。
  但是,也存在这样的情况,有n各主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同。也就是说,多个主题类对应一个代理类,共享“前处理,后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点。动态代理主要有两种:JDK自带的动态代理和CGLIB动态代理。
  首先是另一个静态代理的实例:
1、一个可移动接口

public interface Moveable {
   
   
	
	public void move();
}

2、一个实现了该接口的Car类

public class Car implements Moveable {
   
   

	@Override
	public void move() {
   
   
		try {
   
   
			Thread.sleep(new Random().nextInt(1000));
			System.out.println("汽车行驶中----");
		} catch (InterruptedException e) {
   
   
			e.printStackTrace();
		}
	}
}

3、现在需要有一个代理类来记录Car的运行时间:

public class CarTimeProxy implements Moveable {
   
   
	private Moveable m;
	
	public CarTimeProxy(Moveable m) {
   
   
		super();
		this.m = m;
	}

	@Override
	public void move() {
   
   
		long startTime = System.currentTimeMillis();
		System.out.println("汽车行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值