设计模式之代理模式(Proxy Design Pattern)

代理模式(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();
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值