一、代理模式的概念
当一个类无法直接使用另外一个类时,使用一个代理类来达到使用的目的。
这句话是什么意思呢,举一个生活中的例子,现在的人都喜欢去北上广深打工,打工难免要租房子,而租房子,是很难直接去找到房东去租的,一般都需要通过中介来达到中间沟通的作用,这也是为什么中介可以在中间赚差价的原因。
我们把类无法直接使用的类称为目标类,在这个例子中,房东就代表目标类,而中介就是代理类,租客必须通过中介才能联系到房东,这就是代理模式的思想
二、代理模式的作用
1.功能增强:在你原有的功能之上,增加额外的功能。新增加的功能,叫做功能增强。例如:房东给出的房租是2000/月,而中介告诉你房租是2500/月这就代表功能增强,哈哈
2.控制访问:代理类不让你访问目标,例如:中介为了赚钱,不会让你和房东直接沟通
三、代理模式的实现
代理模式有两种实现方式:
1.静态代理:
1)代理类是自己手工实现的,自己创建一个java类,表示代理类。
2)同时你要代理的目标类是确定的。
下面我们用静态代理来实现上述中的例子
首先创建接口,实现租房功能
package cn.geezer.service;
public interface RentRoom {
/**
* 创建接口租房子接口,和出租方法!
*
* @return 房子的租金/月
*/
float rent();
}
创建目标类,也就是房东
package cn.geezer.target;
import cn.geezer.service.RentRoom;
public class HouseOwner implements RentRoom {
/**
* 房东实现租房接口,实现出租方法
*
* @return 房子的价格:2000/月
*/
public float rent() {
System.out.println("房东提供房租!");
return 2000.0f;
}
}
创建代理类,也就是中介
package cn.geezer.service;
import cn.geezer.target.HouseOwner;
public class HouseAgent implements RentRoom {
private RentRoom owner;//代理房东
public HouseAgent() {
this.owner = new HouseOwner();
}
/**
* @return 房子的价格 2500/月
*/
public float rent() {
float price = owner.rent();
price = price + 500;//中介在其中赚差价(功能增强)
System.out.println("中介在其中赚差价!");
return price;
}
}
创建租客类,租房子
package cn.geezer.main;
import cn.geezer.service.HouseAgent;
public class Tenant {
// 租客
public static void main(String[] args) {
HouseAgent agent = new HouseAgent();
float price = agent.rent();
System.out.println("租房的价格为:" + price + "元/月");
}
}
通过以上例子不难看出静态代理的优缺点
优点:实现简单,容易理解
缺点:当目标类和代理类太多的时候,存在以下缺点
1)目标类增加,代理类也需要随着增加
2)修改或增加方法,所有代理类需要修改
因为以上缺点,jdk提供了动态代理的方法来解决
在了解动态代理之前,需要先学习几个类
1)InvocationHandler接口(调用处理器):就一个方法invoke()
invoke():表示代理对象要执行的功能代码,你的代理类要完成的功能就写在invoke()方法中
代理类完成的功能:
1)调用目标类的方法,执行目标方法的功能
2)功能增强,在目标方法调用时,增加功能
方法原型:
public Object invoke(Object proxy, Method method, Object[] args)
参数:
Object proxy:jdk创建的代理对象,无需赋值
Method method:目标类中的方法,jdk提供method对象
Object[] args:目标类中方法的参数,jdk提供
2)Method类:表示方法的,确切的说就是目标类中的方法。
作用:通过Method可以执行某个目标类的方法,method.invoke();
3)Proxy类:核心对象,创建代理对象,之前创建对象都是new类的构造方法()
方法:静态方法newProxyInstance()
作用是:创建代理对象
方法原型:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
参数:
1.classLoader loader类加载器,负责向内存中加载对象,使用反射获取对象的ClassLoader类a,a.getClass().getClassLoader(),目标对象的类加载器
2.Class<?>[] interfaces:接口,目标对象实现的接口,也是反射获取的
3.InvocationHandler h 自己写的代理类要完成的功能
返回值就是代理对象
下面用动态代理的方式来实现租房子的例子
接口和房东代码和上面一样
创建InvocationHandler接口
package cn.geezer.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class HouseInvocationHandler implements InvocationHandler {
RentRoom rentRoom;
public HouseInvocationHandler(RentRoom rentRoom) {
this.rentRoom = rentRoom;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//利用反射来执行目标类方法
Float price = (Float) method.invoke(rentRoom, args);
System.out.println("中介在其中赚差价!");
price = price + 500;
return price;
}
}
租客类
package cn.geezer.main;
import cn.geezer.service.HouseInvocationHandler;
import cn.geezer.service.RentRoom;
import cn.geezer.target.HouseOwner;
import java.lang.reflect.Proxy;
public class Tenant {
public static void main(String[] args) {
HouseOwner owner = new HouseOwner();
HouseInvocationHandler handler = new HouseInvocationHandler(owner);
RentRoom agent = (RentRoom) Proxy.newProxyInstance(owner.getClass().getClassLoader(), owner.getClass().getInterfaces(), handler);
float price = agent.rent();
System.out.println("租房的价格为:" + price + "元/月");
}
}