什么是代理模式呢,就是先创建一个接口,这个接口中定义了一些未实现的方法,再定义两个类A、B来分别实现这些接口,其中类A用来实现具体的方法,这被称为目标实现类,而另一个类B是通过设置一些条件来判断要不要来进行调用A类的接口实现,那么B被称为代理类。就是说我们可以通过代理类来间接访问目标类,下面我来举一个例子:
人的基本需求是什么?买东西啊!所以我们来定义一个人的接口如下:
interface People{
public void buy();
}
好了,但是人的欲望是无穷的,但是如果你要买东西,比如iphone,那么你的身上必须得有钱才行吧,所以我们定义了一个有‘钱’这属性的客户
class Customer implements People{
private int money;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public void buy(){
System.out.println("买了一台iphone");
}
}
我们看上面的代码,我们就会发现一个关系没有被关联起来,那就是金钱和买iphone之间的关系,并不是你有多少钱都可以买一个iphone的,你得是土豪才可以,于是我们可以在buy()方法中增加如下的判断语句
@Override
public void buy(){
if(money > 4000)
System.out.println("买了一台iphone");
}
可是Apple公司会发布新的iphone,价格也是水涨船高,那么我们就得不停地修改上面判断条件,这样的不停地改动很麻烦,也不符合面向对象中的开闭原则,即
需求的变更,新的功能的添加应该用对原有进行拓展的方式进行,而不是通过修改原有代码来实现
所以我们维持Customer类的简单性,而通过一个新增一个类来对上面的逻辑进行处理,这个类的功能是什么呢?首先检查你的钱包,假如你的钱包里面的钞票不给力,那对不起,你没有资格购买iphone,这个充当检查钱包的类被称为代理类,如下:
public class StaticProxy implements People{
People people;
public StaticProxy(People people){
this.people = people;
}
public void buy(){
if (((Customer)people).getMoney() > 4000)
people.buy();
else
System.out.println("你无法购买iphone");
}
public static void test(){
Customer customer1 = new Customer();
customer1.setMoney(5000);
StaticProxy proxy = new StaticProxy(customer1);
proxy.buy();
}
}
那么新的iphone发布的时候,我们只要修改代理类中的判断逻辑就可以了,但是这种方式有没有缺点呢,肯定的嘛,我们仔细看一下上面的代码,代理类和目标类都实现了People这个接口,假如People接口新增了方法,那么这两个类都需要进行添加方法的实现才可以,那么有没有更省事的方法呢?答案是有的,那就是动态代理。
动态代理省去了代理类添加接口实现方法的过程,那么它是怎么实现的呢,如下:
public class DynamicProxy {
private Object target;
public DynamicProxy(Object target){
this.target = target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnedValue = method.invoke(target,args);
return returnedValue;
}
});
}
}
上面的核心代码是这句:
Object returnedValue = method.invoke(target,args);
其中的invoke方法,它的作用是这样的:
1、我们通过反射根据类的方法名和方法参数来获取一个对象所属类的方法对象
2、根据方法对象的invoke方法输入对象实例和参数值来获取这个方法的输出
具体的原理可看源代码,我这里不再赘述。好了,我们看一下测试代码
People people = new Customer();
((Customer)people).setMoney(10000);
People proxy = (People) new DynamicProxy(people).getProxyInstance();
proxy.buy();
可以看到,我们并没有在动态代理中实现这个接口的方法,所以利用动态代理,我们增加接口中的方法时只需要增加目标类的实现即可。
网友评论