设计模式——代理模式
本片文章总结于《狂神说Java》的设计模式篇章:
B站链接
一、代理模式
简介:
代理模式是一种结构型的设计模式,为一个对象提供一个代理对象,然后可以通过使用代理对象来访问原始对象。(Spring AOP就是通过代理模式实现的)
类图:
- 抽象主题:一般使用接口或者抽象类来实现
-真实角色:被代理的对象 - 代理角色Proxy:代理真实的角色;除了完成代理角色的工作,还会进行一些二附属的操作
- 客户Client:使用代理角色来进行一些操作
二、具体实现
代理模式分为动态代理和静态代理,区别在于是在运行时期检查还是编译时期。(静态代理自己写,动态代理交给程序运行过程中自动创建)
2.1. 静态代理
优点
- 被代理对象可以更加专注于自己的行为操作,一些公共的额外的操作可以交由代理对象统一管理,实现业务的分工
- 公共业务发生扩展的时候可以更加集中的管理
缺点
- 一个真实角色就要产生一个代理对象,当程序中的需要代理的类比较多,则需要多个代理类,会使得程序结构庞大复杂
实现
Rent:抽象的角色,表示代理的行为(一般是接口或者抽象类)
// 抽象角色,即代理的行为
public interface Rent {
void rent();
}
LandLord:真实角色,即需要代理的角色
// 需要代理的角色:房东
public class Landlord implements Rent {
@Override
public void rent() {
System.out.println("房东需要租房");
}
}
Proxy:代理角色,代理真实角色,除了完成真实角色的任务,还有一些自己的额外操作
// 代理角色
public class Proxy implements Rent{
private Landlord landlord;
public Proxy(){}
public Proxy(Landlord landlord){
this.landlord = landlord;
}
@Override
public void rent() {
// 其他的行为:看房
seeHouse();
// 代理的行为:租房
landlord.rent();
// 其他行为:签署合同
contract();
// 其他的行为:收取中介费
fare();
}
private void seeHouse(){
System.out.println("中介带你看房");
}
private void contract(){
System.out.println("中介带你签合同");
}
private void fare(){
System.out.println("中介收取中介费");
}
}
Client:客户
public class Client {
public static void main(String[] args) {
// 房东要租房(只有一个出租房屋的行为)
Landlord landlord = new Landlord();
// 中介帮房东(出租房屋),并且还有其他行为(签合同、看房等)
Proxy proxy = new Proxy(landlord);
// 客户直接找房东租房
proxy.rent();
}
}
运行结果
2.2. 动态代理
优点:
- 被代理对象可以更加专注于自己的行为操作,一些公共的额外的操作可以交由代理对象统一管理,实现业务的分工
- 公共业务发生扩展的时候可以更加集中的管理
- 在JVM运行时期动态构建对象和动态地调用代理方法,可以很好解决静态代理一个真实对象就需要一个代理类的缺点,它可以代理多个类。
-动态代理的是某一类的业务
动态代理主要有JDK 动态代理(基于接口)和 Cglib 的动态代理(基于类),下文主要是基于JDK 的动态代理。
抽象主题
public interface Rent {
void rent();
}
真实对象
public class Landlord implements Rent {
@Override
public void rent() {
System.out.println("房东需要租房");
}
}
代理对象,与静态代理不同我们不再主动写死真实对象,利用反射机制,实现InvocationHandler接口创建动态代理类,我们的代理对象使用的是Object,而不再是上面单一的Landlord,通过Proxy.newProxyInstance动态根据传入的target生成代理类,代理的行为则重写invoke方法,通过**method.invoke(tarhet , this)**来实现,代理类的其他行为可以加载invoke里面
public class ProxyInvocationHandle implements InvocationHandler {
// 被代理的接口或者行为
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// 动态生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// 处理代理的的业务逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("其他方法1");
Object result = method.invoke(target, args);
System.out.println("其他方法2");
return result;
}
Client
public class Client {
public static void main(String[] args) {
// 真实的角色(需要代理的人):房东
Landlord landlord = new Landlord();
// 获得代理角色
ProxyInvocationHandle proxyHandle_rent = new ProxyInvocationHandle();
// 设置代理对象(代理的内容)
proxyHandle_rent.setTarget(landlord);
Rent proxy_rent = (Rent) proxyHandle_rent.getProxy();
proxy_rent.rent();
}
}
运行结果
与静态代理不同的是,我们可以通过这个方法代理多个真实对象,或者多个主题:
新加主题:Arrange
public interface Arrange {
void arrange();
}
真实对象:
public class Marry implements Arrange{
@Override
public void arrange() {
System.out.println("结婚布置场所");
}
}
Client:我们直接使用前面的ProxyInvocationHandle,而不需要重新写一个代理对象
public class Client {
public static void main(String[] args) {
// 真实的角色(需要代理的人):房东
Landlord landlord = new Landlord();
// 真实的角色(需要代理的人):结婚对象
Marry marry = new Marry();
// 获得代理角色
ProxyInvocationHandle proxyHandle_rent = new ProxyInvocationHandle();
// 设置代理对象(代理的内容)
proxyHandle_rent.setTarget(landlord);
Rent proxy_rent = (Rent) proxyHandle_rent.getProxy();
proxy_rent.rent();
ProxyInvocationHandle proxyHandle_arrange = new ProxyInvocationHandle();
proxyHandle_arrange.setTarget(marry);
Arrange proxy_marry = (Arrange) proxyHandle_arrange.getProxy();
proxy_marry.arrange();
}
}
结果:
类似的,同一个主题的不同实现类我们也可以用一个ProxyInvocationHandle去完成代理