代理模式1

GoF代理模式

1.对代理模式的理解

         

 

 目标对象和代理对象都具有 相同的行为,把该行为抽象为接口,目标对象和代理对象都 实现该接口。

 对于生活场景二:老杜认为 另外收取费用--增加代码 是功能的增强。 我认为这不是,应该认为 

自己找房子能力不强,找得慢,时间长,所以通过代理人(房屋中介),增强这方面的能力,它们找房快。

西游记场景中:八戒 是 客户端。 八戒 认为自己  所看到的 代理人(悟空幻化的高小姐)和 目标对象(高小姐)两人是同一个对象。

代理模式是GoF 的23种模式之一,属于结构型设计模式。
代理模式的作用:为其他对象  提供  一种代理  以控制这个对象的访问。 
在某些情况下, 一个客户 不想或不能 直接引用一个对象,此时可以通过 一个称之为 “代理” 的第三者来实现间接引用。     代理对象  在客户端和目标对象之间  起到中介的作用, 并且可以 通过代理对象 去掉 客户不应该看到的内容 或 添加客户需要的额外服务。
通过 引入一个新的对象 来实现 对真实对象的操作 或者  将新的对象作为真实对象的一个替身,这种实现机制即为代理模式,通过引入代理对象间接访问一个对象,这就是代理模式的模式动机。

代理模式中的角色:
代理类(代理主题)
目标类(真实主题)
代理类和目标类的公共接口(抽象主题):客户端 在使用代理类时, 就感觉自己像是在使用 目标类,客户端察觉不到 自己实际上 使用的是 代理类,而不是 目标类。所以代理类和目标类要有共同的行为,也就是实现共同的接口。

代理模式的类图:

 2.静态代理

前序:

有一个接口,和一个对应的实现类。           后面有了新需求:测量实现类中的所有方法的耗时

package com.proxy.service;

public interface OrderService {//代理 和目标 的公共接口
//    生成订单
    void generate() throws InterruptedException;

//    修改订单
    void modify() throws InterruptedException;

//    查看订单详情
    void detail() throws InterruptedException;
}
/*
* 项目经理提出一个新需求:要统计所有业务接口中每一个业务方法的耗时。
* 解决方案1:采用硬编码。在每一个业务接口中的每一个业务方法中直接添加统计耗时的程序。
* 该方案缺点:1.违背OCP原则。 2.代码没有得到复用(相同的代码写了很多遍)
*
* 解决方案2:编写业务类的子类,让子类继承业务类,对每个业务方法进行重写。
* 该方案缺点:1.虽不违背OCP。但会导致耦合度很高。因为使用了继承关系,继承关系是一种耦合度非常高的关系,不建议使用。
*           2.代码没有得到复用(相同的代码写了很多遍)
*
* 解决方案3:代理模式(静态代理)
* 该方案的优点:1.解决了OCP问题;2.采用代理模式的has a,可以降低耦合度。
* 静态代理的缺点:类爆炸。因为每个接口都得写一个代理类,类急剧膨胀,不好维护。
* 如何解决类爆炸问题:使用动态代理。
* 动态代理也是代理模式,只不过添加了字节码生成技术,可以在内存中动态地生成一个class的字节码,这个字节码就是代理类
* */
* */

public class OrderServiceImpl implements OrderService{//目标对象
    @Override
    public void generate() throws InterruptedException {//目标方法
        //        模拟生成订单的耗时
        Thread.sleep(123);
        System.out.println("a订单已生成");
    }

    @Override
    public void modify() throws InterruptedException {//目标方法
        //        模拟修改订单的耗时
        Thread.sleep(123);
        System.out.println("a订单已修改");
    }

    @Override
    public void detail() throws InterruptedException {//目标方法
        //        模拟查询订单的耗时
        Thread.sleep(123);
        System.out.println("a正在查看订单详情");
    }
}

静态代理中的代理对象

package com.proxy.service;


//代理对象(代理对象和目标对象要具有相同的行为,就要实现同一个或同一些接口。)
  //客户端在使用代理对象的时候就像在使用目标对象一样。
public class OrderServiceProxy implements OrderService{

    //将目标对象作为代理对象中的一个属性。这种关系叫关联关系。比继承关系的耦合度低。
    //代理对象中 含有 目标对象的引用。 ----关联关系:has a
    //注意:这里要写一个公共接口类型。因为公共接口耦合度更低。
    //若用OrderServiceImpl osimpl;会使得代理与目标的耦合度更高。而用公共接口类型,可使代理与目标解耦合。
    private OrderService target;//这就是目标对象。 目标对象一定是实现了OrderService接口的,所以可用接口变量来管理目标对象

    //创建代理对象的时候,传一个目标对象给代理对象(因为多态,执行方法时是看实际管理的对象)
    public OrderServiceProxy(OrderService target) {
        this.target = target;
    }

    @Override
    public void generate() throws InterruptedException {//代理方法
        //增加
        long begin = System.currentTimeMillis();
        //调用目标对象的方法
        target.generate();
        long end = System.currentTimeMillis();
        System.out.println("耗时"+(end-begin)+"毫秒");
    }

    @Override
    public void modify() throws InterruptedException {//代理方法
        //增加
        long begin = System.currentTimeMillis();
        //调用目标对象的方法
        target.modify();
        long end = System.currentTimeMillis();
        System.out.println("耗时"+(end-begin)+"毫秒");
    }

    @Override
    public void detail() throws InterruptedException {//代理方法
        //增加
        long begin = System.currentTimeMillis();
        //调用目标对象的方法
        target.detail();
        long end = System.currentTimeMillis();
        System.out.println("耗时"+(end-begin)+"毫秒");
    }
}

测试程序:

//        创建目标对象(因为要传目标对象进代理对象中进行调用)
        OrderService target = new OrderServiceImpl();
//        创建代理对象
        OrderService proxy = new OrderServiceProxy(target);
//        调用代理对象的代理方法
        proxy.generate();
        proxy.detail();
        proxy.modify();

知识点补充:

类和类之间的关系:共6种。其中两种:泛化关系      关联关系

泛化关系:继承  is a

        Cat is a  Animal

public class Animal{}

public class Cat extends  Animal{};


关联关系: has a

        张安 has a 苹果

public class Person{

         private Apple apple;

}

public class Apple{}


相比来说:泛化关系的耦合度 高于 关联关系。优先选择 使用 关联关系。

3.动态代理:

在程序运行阶段,在内存中动态生成代理类,被称为动态代理,目的是为了减少代理类的数量。解决代码复用的问题。

在内存当中动态生成类的技术常见的包括:

        JDK动态代理技术:只能代理接口。

        CGLIB动态代理技术:CGLIB(Code Generation Library)是一个开源项目。

        Javassist动态代理技术

 3.1JDK动态代理

        处理过程的思想与静态代理是一样的。

        

//        创建目标对象(因为要传目标对象进代理对象中进行调用)
    OrderService target = new OrderServiceImpl();
//        创建代理对象
        关键是如何动态地建立出一个代理对象
//        调用代理对象的代理方法
//        创建代理对象
    /*
    * 1.newProxyInstance 翻译为:新建代理对象。即通过该方法可创建代理对象。
    * 本质上,Proxy.newProxyInstance()方法的执行,做了两件事:
    *   第一件:在内存中动态地生成了一个代理类的字节码class;
    *   第二件:new 了一个对象。通过内存中生成的代理类的字节码,实例化代理对象。

    * 2.关于Proxy.newProxyInstance()方法的三个重要参数,参数的含义,及作用?
    *   第一个参数:ClassLoader loader 类加载器
    *   在内存中生成的字节码也是class文件,要执行也得先加载到内存当中。加载类需要类加载器,所以这里需要指定类加载器。
    *   且JDK要求,目标类的类加载器 必须 和 代理类的类加载器使用同一个。
    *
    *   第二个参数:Class<?>[] interfaces
    *   代理类和目标类要实现同一个接口或同一些接口。
    *   在内存中生成代理类时,代理类需指定实现哪些接口。
    *
    *   第三个参数:InvocationHandler h
    *   InvocationHandler 被译为:调用处理器。是一个接口。
    *   在调用处理器接口中编写的就是:增强代码。
    *   因为 具体 要增加什么代码,JDK动态处理技术是猜不到的。没有那么神。
    *   既然是接口,就要写接口的实现类。
    *
    *       可能会有疑问?
    *          自己还要动手写调用处理器接口的实现类,这不会类爆炸吗?不会
    *           因为这种调用处理器写一次就好
    *
    * */
    Object proxyObj = Proxy.newProxyInstance(target.getClass().getClassLoader(),
                                             target.getClass().getInterfaces(),调用处理器);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值