代理模式的简单理解与使用

代理模式

代理模式中存在代理者和被代理者,代理者和被代理者都具有相同的功能,并且代理者执行功能时会附加一些额外的操作

如:手机工厂和代理商都具有卖东西的功能,手机代理商除了帮工厂卖手机外,还能在卖手机前打广告推销,卖手机后还可以进行售后服务。

代理模式的优点:

  • 符合开闭原则,不用修改被代理者任何的代码,就能扩展新的功能

  • 项目的扩展和维护比较方便

1、静态代理

角色分析:

  • 抽象角色:一般使用接口或抽象类解决
  • 真实角色:被代理的角色
  • 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作
  • 客户:访问代理对象的人

这里使用一个租房中介的案例:

  • 抽象角色(接口):租房

    //租房
    public interface Rent {
        void rent();
    }
    
  • 真实角色:房东

    //房东
    public class Host implements Rent{
    
        public void rent() {
            System.out.println("房东要出租房");
        }
    }
    
  • 代理角色:中介所(通常包含附属的一些其他方法)

    //代理类
    public class Agent implements Rent{
    
        //组合由于继承
        private Host host;
    
        public void setHost(Host host) {
            this.host = host;
        }
    
        public void rent(){
            host.rent();
            this.sign();
            this.fare();
        }
    
        //签合同
        public void sign(){
            System.out.println("中介签合同");
        }
    
        //中介费
        public void fare(){
            System.out.println("收取中介费");
        }
    }
    
  • 客户端访问代理角色:

    public class Client {
    
        public static void main(String[] args) {
            Host host = new Host();
    
            Agent agent = new Agent();
            agent.setHost(host);
            
            agent.rent();
        }
    
    }
    

静态代理模式的好处:

  • 可以使真实角色的操作更加纯粹,不用关注一些公共的业务
  • 公共业务就交给了代理角色,实现了业务的分工
  • 公共业务发生拓展的时候,方便集中管理

缺点:

  • 静态代理只能适合一种业务,如果有新的业务,就必须创建新的接口和新的代理

  • 每个真实角色就会产生一个代理角色,代码量会翻倍;

AOP(面向切面编程)的实现原理就是代理模式:

1.对于切面织入的实现就是对业务接口创建了一个代理类,

2.代理类中组合了业务接口的实现类,

3.代理类在原先实现类的方法上添加了一些附属方法,

4.客户端访问时即能使用代理类的业务(包括初始业务以及拓展业务)。

这样就实现了对切面的织入,不需要改变原有代码而拓展了新的业务,符合开闭原则;

2、动态代理

  • 动态代理的实现基于反射机制

  • 角色和静态代理相同

  • 动态代理的代理类是动态生成的,而不是直接写好的

  • 动态代理分为两大类:基于接口的动态代理;基于类的动态代理

    • 基于接口:JDK动态代理
    • 基于类:cglib
    • java字节码实现:javasist

需要了解两个类:

  • Proxy:代理

    • Proxy提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
  • InvocationHandler接口:调用处理程序

    • InvocationHandler是由代理实例的调用处理程序实现的接口。

      每个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke方法。

动态代理的特点:(在静态代理的基础上)

  • 一个动态代理类代理的是一个接口,一般就是对应一类业务
  • 一个动态代理类可以代理多个类,只要这些类实现了同一接口即可

java代码实现

  • 需要被代理的接口:

    public interface UserService {
        void add();
    
        void delete();
    
        void update();
    
        void query();
    }
    
  • 真实角色(实现类):

    public class UserServiceImpl implements UserService {
    
        public void add() {
            System.out.println("add");
        }
    
        public void delete() {
            System.out.println("delete");
        }
    
        public void update() {
            System.out.println("update");
        }
    
        public void query() {
            System.out.println("query");
        }
    }
    
  • 生成代理对象的调试处理类:

    //这个类用于自动生成代理类
    public class ProxyInvocationHandler implements InvocationHandler {
    
        //被代理的接口
        private Object target;
    
        public void setUserService(UserService userService) {
            this.target = userService;
        }
    
        //生成得到代理类
        public Object getProxy(){
            return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
        }
    
        //处理代理实例,返回结果
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //通过反射得到调用的方法名
            log(method.getName());
            //调用方法
            return method.invoke(target,args);
        }
    
        //代理类的一些附属方法
        public void log(String s){
            System.out.println("调用了"+s+"方法");
        }
    }
    
  • 客户端:

    public class Client {
    
        public static void main(String[] args) {
            //真实类
            UserServiceImpl userService = new UserServiceImpl();
    
            //动态生成代理角色的处理类
            ProxyInvocationHandler pih = new ProxyInvocationHandler();
            //设置要代理的对象
            pih.setUserService(userService);
            //生成代理实例
            UserService proxy = (UserService) pih.getProxy();
    		
            // **当调用被代理角色的方法时,会通过反射机制调用代理类中的invoke方法
            proxy.query();
    
        }
    }
    
  • 运行结果:

    调用了query方法
    query
    

重点:代理对象必须是接口,以及proxy返回的也是接口的代理实例!!

posted @ 2020-08-12 15:15  想拥有两颗❤  阅读(390)  评论(0编辑  收藏  举报