一、简介
- 概念:
- 代理模式:为对象提供一个替身或者代理,控制对该对象的访问。即通过代理对象去访问目标对象,这样可以动态扩展目标对象的功能。
- 代理模式有三种模式:
- 静态代理
- 动态代理(JDK代理/接口代理)
- Cglib代理
- 通用类图:
即客户端通过代理对象去访问目标对象,而不是直接访问目标对象,可以控制目标对象的访问。
本文先讲解一下静态代理模式的实现方法。
二、静态代理
【a】静态代理实现步骤:
需要定义一个接口或者抽象类,然后代理对象和被代理的对象都要实现这个接口或者继承这个抽象类。
示例:我们拿生活中找中介租房子的示例来说明静态代理的实现方式。
相关UML类图:
角色分析:
- 抽象角色:声明了真实对象和代理对象共同的接口,往往是一个接口或者是抽象类,对应上图的抽象接口类DailyBehavior;
- 代理角色:内部含有一个对被代理对象的引用,目的在于可以操作被代理对象,期间可以对被代理的对象功能进行扩展,实际上封装了被代理对象的功能,对应上图的LettingAgentProxy类;
- 真实角色:其实就是被代理对象,对应上图中的房东类Landlord ;
详细代码如下:
【a】抽象接口:真实对象和代理对象共同的接口
public interface DailyBehavior {
/**
* 租房子
*/
void rentApartment();
}
【b】房东类:被代理对象
public class Landlord implements DailyBehavior {
@Override
public void rentApartment() {
System.out.println("房东将房子租给我们...");
}
}
【c】代理中介类:持有一个被代理对象的引用
public class LettingAgentProxy implements DailyBehavior {
/**
* 持有一个被代理对象的引用
*/
private Landlord landlord;
public LettingAgentProxy(Landlord landlord) {
this.landlord = landlord;
}
@Override
public void rentApartment() {
this.prev();
landlord.rentApartment();
}
private void prev() {
System.out.println("中介帮忙找房东...");
}
}
【d】客户端:也就是租客自己
public class Client {
public static void main(String[] args) {
//我们只与中介打交道,实际上出租房子的还是房东
DailyBehavior proxy = new LettingAgentProxy(new Landlord());
proxy.rentApartment();
}
}
【e】运行结果
如上所示,我们客户端直接面对的是代理角色,让代理角色去跟真实角色打交道,实际操作还是由真实角色去完成,期间可以扩展真实角色的功能,进行一些额外的处理来增强。
三、总结
- 优点:
- 在不改变目标对象功能的前提下,可以扩展其功能;
- 缺点:
- 因为代理类Proxy需要与被代理类实现相同的接口或者继承相同的父类,这就会产生大量的代理类;
- 如果抽象接口新增了方法,那么代理类和被代理类都要修改,违反了开闭原则,维护相对困难;