设计模式之代理模式

设计模式之代理模式

  • 初识代理模式

    定义:为其他对象提供一种代理以控制这个对象的访问。

    结构和说明
    这里写图片描述

    Proxy 代理对象

    • 实现与具体对象一样的接口,这样就可以使用代理来代理具体的目标对象
    • 保存一个指向具体目标对象的引用,可以在需要的是后使用调用具体的目标对象。
    • 控制对具体目标的访问,并可能 负责创建和删除它。

    Subject

    • 目标接口,定义代理和具体目标对象的接口,这样就可以在任何使用具体目标对象的地方使用代理对象。

    RealSubject

    • 具体目标对象,真正实现目标接口要求的动能。
//目标统一接口
public inferace subject {
    public void request();
}

//具体目标对象
public class RealSubject implements Subject{
    public void request(){
    //功能处理
    }
}
public class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(ResalSubject realSubject) {
        this.realSubject = realSubject;
    }
    public void request(){
        realSubject.request();
    }
}

  • 理解代理模式

    代理模式是通过创建一个代理对象,用这个代理对象去代表真实的对象,客户端得到这个对象过后,对客户端没什么影响,犹如得到真实的对象一样来使用。
    实例一:大数据量逻辑数据查询。

/**
 * @description : 定义用户对象的接口
 **/
public interface UserModelApi {
   String getUserId();
   void setUserId(String userId);

   String getName();
   void setName (String name);

   String getDepId();
   void setDepId (String depId);

   String getSex();
   void setSex (String sex);
}

public class UserModel implements UserModelApi{
    private String userId;
    private String name;
    private String depId;
    private String sex;
    //getter,setter 略
}


public class UserProxy implements UserModelApi {

    private boolean load = false;
    private UserModel userModel;

    public UserProxy(UserModel userModel) {
        this.userModel = userModel;
    }

    @Override
    public String getUserId() {
        return userModel.getUserId();
    }
    @Override
    public void setUserId(String userId) {
        userModel.setUserId(userId);
    }

    @Override
    public String getName() {
        return userModel.getName();
    }
    @Override
    public void setName(String name) {
        userModel.setName(name);
    }

    @Override
    public String getDepId() {
        if (!this.load) {
            reload();
            this.load = true;
        }
        return userModel.getDepId();
    }

    @Override
    public void setDepId(String depId) {
        userModel.setDepId(depId);
    }
    @Override
    public String getSex() {
        if (!this.load) {
            reload();
            this.load = true;
        }
        return userModel.getSex();
    }

    @Override
    public void setSex(String sex) {
        userModel.setSex(sex);
    }

    private void reload(){
        /***
         * Connection conn = null;
         * conn = this.getConnection();
         * String sql = 'Select * from tb_user1 where userId = ?'
         * PreparedStatement ps = conn.prepareStatement(sql);
         * ps.setString(1,userModel.getUserId());
         * ResultSet rs = ps.executeQuery();
         * if (rs.next()) {
         *  userModel.setDepId(rs.getString("depId"));
         *  userModel.setSex(rs.getString("sex"));
         * }
         * rs.close();
         * ps.close();
         */
    }
}

public class UserManager  {

    public Collection<UserModelApi> getUserByDepId( String depId) throws Exception {
        Collection<UserModelApi> col = new ArrayList<>();
        Connection connection = null;
        String sql = "select u.userId,u.name from tb_user u,tb_dep d where u.depId = d.depId like ?";
        PreparedStatement preparedStatement = null;
        preparedStatement.setString(1,depId + "%");
        ResultSet resultSet = preparedStatement.executeQuery();
        while (resultSet.next()) {
            //代理对象而不直接使用userModel
            UserProxy userProxy = new UserProxy(new UserModel());
            userProxy.setUserId(resultSet.getString("userId"));
            userProxy.setName(resultSet.getString("name"));
            col.add(userProxy);
        }
        return col;
    }
}

public class Client {
    public static void main (String []args) {
        UserManager userManager = new UserManager();
        try {
            Collection<UserModelApi> collections = userManager.getUserByDepId("01011");
            //只显示客户名称不需要重新查询
            for (UserModelApi api : collections) {
            }
            //显示用户编号和其他属性 需要重新查询

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 以时间换取空间
     * 1+N次查询问题
     *
     * Lazy Load (Hibernate)实现机制是动态代理。过程类似上述过程
     */
}

保护代理

保护代理是一种控制原始对象访问的代理。多用于对象应该有不同的访问权限时候,保护代理会检查调用者是否有访问的权限,没有权限就不会调用目标对象。

实例二 :订单系统,要求一旦订单被创建,只有订单的创建人才可以修改,其他人不能修改。

//订单OrderApi 接口
public interface OrderApi {

    String getOrderName();
    void setOrderName(String user,String orderName);

    int getOrderNum ();
    void setOrderNum (String user,int orderNum);

    String getOrderUser();
    void setOrderUser(String user,String orderUser);

}
//订单实体对象
public class Order implements OrderApi{

    private String orderName;

    private int orderNum;

    private String orderUser;

    public Order(String orderName, int orderNum, String orderUser) {
        this.orderName = orderName;
        this.orderNum = orderNum;
        this.orderUser = orderUser;
    }

    @Override
    public String getOrderName() {
        return orderName;
    }

    public void setOrderName(String user,String orderName) {
        this.orderName = orderName;
    }

    @Override
    public int getOrderNum() {
        return orderNum;
    }

    public void setOrderNum(String user,int orderNum) {
        this.orderNum = orderNum;
    }

    @Override
    public String getOrderUser() {
        return orderUser;
    }

    public void setOrderUser(String user,String orderUser) {
        this.orderUser = orderUser;
    }
}

/**
 * 保护代理 (控制访问)
 *
 * @author carro
 **/
public class OrderProxy implements OrderApi {
    private Order order;

    public OrderProxy(Order order) {
        this.order = order;
    }
    @Override
    public String getOrderName() {
        return order.getOrderName();
    }

    @Override
    public void setOrderName(String user, String orderName) {
        if (user != null && this.order.getOrderUser().equalsIgnoreCase(user)) {
            order.setOrderName(user,orderName);
        } else {
            //TODO:throw exception
        }
    }
    @Override
    public int getOrderNum() {
        return order.getOrderNum();
    }

    @Override
    public void setOrderNum(String user, int orderNum) {
        if (user != null && this.order.getOrderUser().equalsIgnoreCase(user)) {
            order.setOrderNum(user,orderNum);
        } else {
            //TODO:throw exception
        }
    }
    @Override
    public String getOrderUser() {
        return order.getOrderUser();
    }

    @Override
    public void setOrderUser(String user, String orderUser) {
        if (user != null && this.order.getOrderUser().equalsIgnoreCase(user)) {
            order.setOrderUser(user,orderUser);
        } else {
            //TODO:throw exception
        }
    }
}

public class Client {
    public static void main(String[]args){
        OrderApi orderApi = new OrderProxy(
            new Order("设计模式",100,"战三"));
        //修改失败
        orderApi.setOrderNum("立体",123);
        //修改C成功
        orderApi.setOrderNum("战三",123);
    }
}

  • Java中的代理

    Java静态代理(虚代理模式): 如果Subject 接口变化,那么代理类和具体的目标实现都要变化,不是很灵活。

    Java动态代理 :实现机制 反射和动态生成Class
    JDK动态代理所用到的代理类在程序调用到代理类对象时才由JVM真正创建,JVM根据传进来的 业务实现类对象 以及 方法名 ,动态地创建了一个代理类的class文件并被字节码引擎执行,然后通过该代理类对象进行方法调用。我们需要做的,只需指定代理类的预处理、调用后操作即可。

    JDK动态代理的代理对象在创建时,需要使用业务实现类所实现的接口作为参数(因为在后面代理方法时需要根据接口内的方法名进行调用)。如果业务实现类是没有实现接口而是直接定义业务方法的话,就无法使用JDK动态代理了。并且,如果业务实现类中新增了接口中没有的方法,这些方法是无法被代理的(因为无法被调用)。

    实例三:java jdk 中动态代理使用(以上述订单为例)

public interface OrderApi {

    String getOrderName();
    void setOrderName(String user, String orderName);

    int getOrderNum();
    void setOrderNum(String user, int orderNum);

    String getOrderUser();
    void setOrderUser(String user, String orderUser);
}

public class Order implements OrderApi {

    private String orderName;

    private int orderNum;

    private String orderUser;

    public Order(String orderName, int orderNum, String orderUser) {
        this.orderName = orderName;
        this.orderNum = orderNum;
        this.orderUser = orderUser;
    }

    @Override
    public String getOrderName() {
        return orderName;
    }
    public void setOrderName(String user,String orderName) {
        this.orderName = orderName;
    }

    @Override
    public int getOrderNum() {
        return orderNum;
    }
    public void setOrderNum(String user,int orderNum) {
        this.orderNum = orderNum;
    }

    @Override
    public String getOrderUser() {
        return orderUser;
    }
    public void setOrderUser(String user,String orderUser) {
        this.orderUser = orderUser;
    }
}

/**
 * 动态代理 使用jdk InvocationHandler
 * @author carro
 **/
public class DynamicProxy implements InvocationHandler{

    //定义是接口
    private OrderApi order = null;

    public OrderApi getProxyInterface(Order order) {
        this.order = order;
       //通过反射机制,创建一个代理类对象实例并返回。用户进行方法调用时使用
       //创建代理对象时,需要传递该业务类的类加载器(用来获取业务实现类的元数据,在包装方法是调用真正的业务方法)、接口、handler实现类
        OrderApi orderApi = (OrderApi) Proxy.newProxyInstance(
            order.getClass().getClassLoader(),
            order.getClass().getInterfaces(),
            this
        );
        return orderApi;
    }

    /** 
     * 包装调用方法:进行预处理、调用后处理 
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().startsWith("set")) {
            if (order.getOrderUser() != null && order.getOrderUser().equals(args[1])){
                return method.invoke(order,args);
            } else{
                throw new Exception(".......");
            }
        } else{
            return method.invoke(order,args);
        }
    }
}

public class Client {
    public static void main(String[]args){
        Order order = new Order("设计模式",123,"xuks");
        DynamicProxy dynamicProxy = new DynamicProxy();
        OrderApi orderApi = dynamicProxy.getProxyInterface(order);
        orderApi.setOrderName("历史","学习");
    }
}
  • 代理模式优缺点
    虚代理:根据需求来创建大对象,只有到必须创建对象的时候,虚代理才会创建对象,从而加快了程序运行和节省资源;
    保护代理可以在在访问一个对前后,执行很多附加的操作;可以通过代理来给目标对象增加功能。
    智能指引:引用计数等。

  • 代理模式本质
    控制对象访问

  • 使用场景
    需要创建开销很大的对象的时候 使用 虚代理
    需要控制对象访问权限的时候使用保护代理
    需要在访问对象的执行一些附加操作的时候可以使用代理模式。

  • 思考使用 继承方式实现代理?


扩展cglib 动态代理

cglib是针对类来实现代理的,原理是对指定的业务类生成一个子类,并覆盖其中业务方法实现代理。因为采用的是继承,所以不能对final修饰的类进行代理。

/**
 * 动态代理 使用cglib MethodInterceptor
 * @author carro
 **/
public class DynamicCGLibProxy implements MethodInterceptor{
    //业务类对象,供代理方法中进行真正的业务方法调用
    private OrderApi order;

    public OrderApi getProxyInstance(Order order) {
        this.order = order;//给业务对象赋值
        Enhancer enhancer = new Enhancer(); //创建加强器,用来创建动态代理类   
        enhancer.setSuperclass(this.target.getClass());  //为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
        //设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
        enhancer.setCallback(this);
        // 创建动态代理类对象并返回
        return enhancer.create();
    }

    /** 
     * // 实现回调方法 
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {
        if (method.getName().startsWith("set")) {
            if (order.getOrderUser() != null && order.getOrderUser().equals(args[1])){
                return proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法;
            } else{
                throw new Exception(".......");
            }
        } else{
            return proxy.invokeSuper(obj, args); //调用业务类(父类中)的方法;
        }
    }
}

public class Client {
    public static void main(String[]args){
        Order order = new Order("设计模式",123,"xuks");
        DynamicProxy dynamicProxy = new DynamicCGLibProxy();
        OrderApi orderApi = dynamicProxy.getProxyInstance(order);
        orderApi.setOrderName("历史","学习");
    }
}   
  • 过程
    1.首先定义业务类,无需实现接口(实现接口也可以);
    2.实现 MethodInterceptor方法代理接口,创建代理类 ;
    3.创建业务类和代理类对象,然后通过 代理类对象.getInstance(业务类对象) 返回一个动态代理类对象(它是业务类的子类,可以用业务类引用指向它)。最后通过动态代理类对象进行方法调用;

  • 比较

    静态代理是通过在代码中显式定义一个业务实现类一个代理,在代理类中对同名的业务方法进行包装,用户通过代理类调用被包装过的业务方法;

    JDK动态代理是通过接口中的方法名,在动态生成的代理类中调用业务实现类的同名方法;

    CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值