代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问
使用场景:当无法或者不想直接访问某个对象或访问某个对象存在困难时可以同一个代理对象来简介范根,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
静态代理
代理模式的通用模式代码
/**
* 抽象主题类
*/
public abstract class Subject {
/**
* 一个普通的业务方法
*/
public abstract visit();
}
/**
* 实现抽象主题的真实主题类
*/
public class RealSubject extends Subject {
@Override
public void visit() {
// RealSubject中visit的具体逻辑
System.out.println("Real subject");
}
}
/**
* 代理类
*/
public class ProxySubject extends Subject {
// 持有真实主题类的引用
private RealSubject mSubject;
public ProxySubject(RealSubject subject) {
this.mSubject = subject;
}
@Override
public void visit() {
// 通过真实主题引用的对象调用真实主题中的方法
mSubject.visit();
}
}
/**
* 客户类
*/
public class Client {
public static void main(String[] args) {
// 构造一个真实主题对象
RealSubject realSubject = new RealSubject();
// 通过真实主题对象构造一个代理对象
ProxySubject proxy = new ProxySubject(realSubject);
// 调用代理的相关方法
proxy.visit();
}
}
代理模式的角色介绍
Subject:
抽象主题类
该类的主要职责是声明真实主题与代理的共同接口方法,该类既可以是一个抽象类也可以是一个接口。
RealSubject:
真实主题类
该类也称为被委托类或被代理类,该类定义了代理所表示的真实对象,由其执行具体的业务逻辑方法 而客户类则通过代理类间接地调用了真实主题中定义的方法。
ProxySubject:
代理类
该类也称为委托类或代理类,该类持有一个真实主题类的引用,在其所实现的接口方法中调用真实主题中相应的接口方法执行,以此起到代理的作用
Client:
客户类,即使用代理类的类型
这样看来静态代理的实现也比较简单,就是构造一个代理对象持有一个这是主题对象的引用,通过代理对象调用真实主题的方法。这样实现起来是比较容易,但是如果后面又有多个真实主题对象呢?要用静态代理模式实现的话,是不是要创建多个代理类呢?然后修改代码通过各自的代理类来调用各个真实主题的方法。这时我们就发现了静态代理模式的弊端,可维护性、可扩展性差,也就是违反了面向对象的六大原则之一的开闭原则(开放增加,关闭修改),这样一来就引出了动态代理。
动态代理
举个例子,比如你有一个女朋友要买鞋子,找某鞋子的品牌代理也就是代购,如果你又有一个女朋友要买包包,找某包包的品牌代理,如果你有多个女朋友,每个要买的东西都不一样,要通过不同渠道找不同的代购是不是很麻烦,可不可以找一个平台或中介,每次买东西,就找他们,由平台根据客户要买的东西,再去找具体商品的代购。例子可能不太恰当,但是个人认为已经足够解释动态代理的大概意思了,接下来是代码环节。
/**
* 抽象主题(买包包)接口类
*/
public interface IBuyBag {
// 买包包
void buyBag();
}
/**
* 真实主题类(老婆要买包包)
*/
public class Wife implements IBuyBag {
@Override
public void buyBag() {
System.out.println("给老娘买个包...");
}
}
/**
* 抽象主题(买鞋子)接口类
*/
public interface IBuyBag {
// 买鞋子
void buyShoes();
}
/**
* 真实主题类(女朋友要买鞋子)
*/
public class GirlFriend implements IBuyShoes {
@Override
public void buyShoes() {
System.out.println("给人家买双鞋子啦...");
}
}
上面分别是两个抽象主题类和真实主题类,如果是静态代理,要两个创建代理对象(类), 来分别代理实现,也就是说在我们的代码运行之前代理类的class
编译文件就已经存在;而动态代理则与静态代理相反,通过反射机制动态地生成代理者的对象,也就是在code
阶段压根就不需要知道代理谁,代理谁将会在执行阶段决定。
/**
* 动态代理类
*/
public class DynamicProxy implements InvocationHandler {
// 被代理的引用
Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用被代理对象的方法
Object result = method.invoke(obj, args);
return result;
}
}
如上述代码所述,我们声明了一个Object
的引用,该引用指向被代理类,而我们调用被代理类的具体方法在invoke
方法中执行。也就是说原来由代理类所做的工作现在由InvocationHandler
来处理,不需要再关心到底代理谁,下面是使用代理类的客户类。
public class Client {
public static void main(String[] args) {
// 创建wife对象
IBuyBag wife = new Wife();
// 构造一个动态代理
DynamicProxy proxy1 = new DynamicProxy(wife);
// 动态构造一个处理wife购买需求的代理者
IBuyBag wifeProxy = (IBuyBag) Proxy.newProxyInstance(wife.getClass(