代理模式(Proxy Design Pattern)是在不改变原始类(或叫被代理类)输入输出的前提下,通过引入代理类来给原始类附加功能。这个附加功能对于调用者是无感知的。调用者不能直接接触到原始类,而是通过代理类来调用原始类的功能。代理模式是八种结构型模式之一。
从设计原则来分析代理模式的作用:
接口隔离原则:代理类可以只代理原始类部分功能,隔离调用者不需要的功能。
开闭原则:可以在代理类增加附加功能,原始类则不需要修改。
单一职责原则:原始类专注他的职责,代理类专注附加功能。避免与原始类职责无关的附加功能与原始类进行耦合。
下面通过一个例子来看代理模式的作用。
假如你有一辆爱车。爱车需要上牌、年检。
interface ICar {
//上牌
public void registration(String licensePlate);
//年检
public void inspectAnnually(Integer year);
}
class Car {
private String licensePlate;
private Integer inspectYear;
public void registration(String licensePlate) {
this.licensePlate = licensePlate;
}
public void inspectAnnually(Integer year){
this.inspectYear = year
}
}
/**
* 检测接口
*/
public interface Inspectionable {
public void inspectAnnually(Integer year);
}
/**
* 上牌接口
*/
public interface Registrationable {
//上牌
public void registration(String licensePlate);
}
/**
* 抽象车主
*/
public interface IOwner extends Registrationable,Inspectionable{
public ICar getMycar();
}
/**
* 车主
*/
public class Owner implements IOwner {
private ICar mycar;
public Owner(ICar car) {
mycar = car;
}
public ICar getMycar() {
return mycar;
}
@Override
public void registration(String licensePlate) {
//开车去车管所
//排队验车
//排队登记选牌
//排队制牌
//上牌
mycar.registration(licensePlate);
//开车回家
}
@Override
public void inspectAnnually(Integer year) {
//开车去检测中心
//交费
//排队检测
mycar.inspectAnnually(year);
//开车回家
}
}
/**
* 车管所
*/
public class Dmv {
//注册登记车辆
public void vehicleRegistration(Registrationable owner){
owner.registration("赣AOOOOO");
}
}
/**
* 车辆检测中心
*/
public class VehicleInspectionCenter {
public void vehicle(Inspectionable owner){
owner.inspectAnnually(2021);
}
}
public class Demo {
public static void main(String[] args) {
IOwner owner = new Owner(new Car());
Dmv dmv = new Dmv();
dmv.vehicleRegistration(owner);
VehicleInspectionCenter center = new VehicleInspectionCenter();
center.vehicle(owner);
}
}
上面这个例子没有使用代理,可以看到车主在为爱车上牌、年检的时候,需要做很多事,这些事车主并不专业,车主要的是车子注册上牌年检可以合法上路。对于怎么注册上牌、年检完全可以让更加专业的代理去做。现在车主把这些工作委托给了代理人,代理办理这些工作。
interface ICar {
//上牌
public void registration(String licensePlate);
//年检
public void inspectAnnually(Integer year);
}
class Car {
private String licensePlate;
private Integer inspectYear;
public void registration(String licensePlate) {
this.licensePlate = licensePlate;
}
public void inspectAnnually(Integer year){
this.inspectYear = year
}
}
/**
* 检测接口
*/
public interface Inspectionable {
public void inspectAnnually(Integer year);
}
/**
* 上牌接口
*/
public interface Registrationable {
//上牌
public void registration(String licensePlate);
}
/**
* 抽象车主
*/
public interface IOwner extends Registrationable {
public ICar getMycar();
}
/**
* 车主
*/
public class Owner implements IOwner {
private ICar mycar;
public Owner(ICar car) {
mycar = car;
}
public ICar getMycar() {
return mycar;
}
@Override
public void registration(String licensePlate) {
mycar.registration(licensePlate);
}
}
/**
* 车辆车检代理
*/
public class InspectionProxy implements Inspectionable{
private ICar proxyCar;
public InspectionProxy(ICar car){
proxyCar = car;
}
@Override
public void inspectAnnually(Integer year) {
//开车去检测中心
//交费
//排队检测
proxyCar.inspectAnnually(year);
//开车回家
}
}
/**
* 车辆注册登记上牌代理
*/
public class RegistrationProxy implements Registrationable{
private IOwner owner;
public RegistrationProxy(IOwner owner){
this.owner = owner;
}
@Override
public void registration(String licensePlate) {
//开车去车管所
//排队验车
//排队登记选牌
//排队制牌
//上牌
owner.registration(licensePlate);
//开车回家
}
}
/**
* 车管所
*/
public class Dmv {
//注册登记车辆
public void vehicleRegistration(Registrationable owner){
owner.registration("赣AOOOOO");
}
}
/**
* 车辆检测中心
*/
public class VehicleInspectionCenter {
public void inspect(Inspectionable owner){
owner.inspectAnnually(2021);
}
}
public class Demo {
public static void main(String[] args) {
IOwner owner = new Owner(new Car());
Dmv dmv = new Dmv();
dmv.vehicleRegistration(new RegistrationProxy(owner));
VehicleInspectionCenter center = new VehicleInspectionCenter();
center.inspect(new InspectionProxy(owner.getMycar()));
}
}
引入代理之后,可以看到车主把注册上牌、年检工作,分别委托给了注册上牌代理、年检代理。车主、代理的职责单一,满足了单一职责原则。代理根据自己的职责实现不同的接口,满足接口隔离原则。当车主以后还需要代办其他功能时,只需要委托给其他代理类,原有的功能并不需要修改,满足开闭原则。
如果有很多类都需要代理,而且他们代理需要附加的功能都一样,显然一个个写代理类成本太大了。比如一个系统中有很多服务要对数据库进行CRUD操作,每次操作都要对数据链接和事务进行管理。如果每个服务都写一个代理类显然不现实。这个时候动态代理就派上用场了。下面用动态代理模式来实现数据的链接和事务进行管理。
public class Baby {
private String name = "珠宝";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public interface IDao {
public void save(Baby baby);
}
public class Dao implements IDao {
@Override
public void save(Baby baby) {
System.out.println("baby = " + baby.getName());
}
}
public interface IService {
public void save(Baby baby);
}
public class Service implements IService{
private IDao dao = new Dao();
@Override
public void save(Baby baby) {
//开启数据库连接,移到了动态代理
//开启事务,移到了动态代理
dao.save(baby);
//关闭事务,移到了动态代理
//关闭数据库链接,移到了动态代理
}
}
public class Controller {
private IService service;
public void save(){
service.save(new Baby());
}
public void setService(IService service) {
this.service = service;
}
}
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("开启数据库连接");
System.out.println("开启事务");
Object result = method.invoke(object, args);
System.out.println("关闭事务");
System.out.println("关闭数据库链接");
return result;
}
}
public class DynamicProxy {
public Object createProxy(Object proxyObject){
return Proxy.newProxyInstance(
proxyObject.getClass().getClassLoader(),
proxyObject.getClass().getInterfaces(),
new DynamicProxyHandler(proxyObject)
);
}
}
public class Demo {
public static void main(String[] args) {
Controller controller = new Controller();
IService service = (IService)DynamicProxy.createProxy(new Service());
controller.setService(service);
controller.save();
}
}
//执行结果
开启数据库连接
开启事务
baby = 珠宝
关闭事务
关闭数据库链接
上面的动态代理利用的java语言的反射机制,这种动态代理有一个缺点,是基于接口的代理。如果Service没有实现IService接口,就无法生成动态代理。
如果基于被代理类实现动态代理,可以使用CGLIB第三方类库实现
public class CglibProxy implements MethodInterceptor{
public Object createProxy(Object proxyObject){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(proxyObject.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("开启数据库连接");
System.out.println("开启事务");
Object result = methodProxy.invoke(object, args);
System.out.println("关闭事务");
System.out.println("关闭数据库链接");
return result;
}
}
public class Demo {
public static void main(String[] args) {
Controller controller = new Controller();
CglibProxy cglibProxy = new CglibProxy();
Service service = cglibProxy.getInstance(new Service());
controller.setService(service);
controller.save();
}
}