• 代理模式


    1.代理模式是什么

    1.百度百科

    **
      代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用.**

    2.维基百科

    **
      A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy, extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked. For the client, usage of a proxy object is similar to using the real object, because both implement the same interface.
    **

    3.LZ理解

      想要访问一个对象,但是不适合直接访问,需要有一个中间对象代为转发。中间对象可以增加或者删除目标对象的功能和业务,从而达到拓展或者保护目标对象的目的。其核心是对原有对象进行替换,强调的是个体。 这一点区别于中介模式和观察者模式。

    4.代理角色

    抽象角色:通过接口或抽象类声明真实角色实现的业务方法。(需要提供的业务有哪些)

    代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。(目标对象原本业务)

    真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。(代理后的对外提供的业务)

    2.代理模式解决了什么问题。

    1.访问控制

    用户不能直接访问目标对象,但是又必须和目标对象互动。代理模式可以协调调用者和被调用者。

    2.修改、拓展、替换功能

    客户端可以针对抽象主题角色进行编程,增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性。

    3.代理模式的用法

    1.静态代理

    下面我们来看一个静态代理的例子:火车站售票处

    火车站售票处的基本职能(抽象角色)

    /**
     * 售票处接口
     */
    public interface TicketOffice {
    
    	/**
    	 * 查票
    	 */
    	public void checkTicket();
    	/**
    	 * 售票
    	 */
    	public void tickets();
    
    }
    

    火车站售票处(真实角色)

    /**
     * 火车站售票处
     */
    public class TrainTicketOffice implements TicketOffice {
    
    	@Override
    	public void checkTicket() {
    		System.out.println("查询票务。");
    	}
    
    	@Override
    	public void tickets() {
    		System.out.println("售票。");
    	}
    
    }
    

    手机app里的售票处(代理角色)

    
    /**
     * 代理火车站售票处
     */
    public class PoxyTranTicketOffice implements TicketOffice {
    
    	private TrainTicketOffice trainTicketOffice = new TrainTicketOffice();
    
    	@Override
    	public void checkTicket() {
    		beforeCheckTicket();
    		trainTicketOffice.checkTicket();
    		afterCheckTicket();
    
    	}
    
    	private void beforeCheckTicket() {
    		System.out.println("查询等待期间广告。。。");
    	}
    
    	private void afterCheckTicket() {
    		System.out.println("查询结束后推荐。");
    	}
    
    	@Override
    	public void tickets() {
    		beforeTickets();
    		trainTicketOffice.tickets();
    		afterTickets();
    	}
    
    	private void beforeTickets() {
    		System.out.println("推荐便宜票。");
    
    	}
    
    	private void afterTickets() {
    		System.out.println("推荐保险购买、酒店预订等。");
    
    	}
    }
    

    客户去购票

    public class Customer {
    
    	public static void main(String[] args) {
    		//顾客前往售票处
    		TicketOffice poxyTranTicketOffice = new PoxyTranTicketOffice();
    		//查票
    		poxyTranTicketOffice.checkTicket();
    		//购票
    		poxyTranTicketOffice.tickets();
    
    	}
    }
    

    以上的例子中手机app的售票处代理了原始火车站售票处的职能并且对该职能进行了扩展。


    另外,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际场景中,如果该app想要代理飞机票、轮船票甚至景点门票。那么每一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。

    2.动态代理

    动态代理的实现方式一般有三种一种是jdk自带方式,CGlib动态代理包。


    我们就先使用jdk方式实现动态代理。


    售票处定义了售票处职能(抽象角色)

    /**
     * 售票处接口
     */
    public interface TicketOffice {
    
    	/**
    	 * 售票
    	 */
    	public void tickets();
    
    }
    

    定义了火车售票处(真实角色)

    /**
     * 火车站售票处
     */
    public class TrainTicketOffice implements TicketOffice {
    
    	@Override
    	public void tickets() {
    		System.out.println("售票。");
    	}
    
    }
    

    定义另一个飞机售票处(真实角色)

    /**
     * 代理飞机票
     */
    public class AirplaneTicketOffice implements TicketOffice {
    
    	@Override
    	public void tickets() {
    		System.out.println("出售飞机票");
    	}
    
    }
    

    定义一个动态的代理类(代理角色)

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    /**
     * 动态代理类
     */
    public class ProxyHandler implements InvocationHandler {
    	private Object proxied;
    	//代理对象(真实角色)
    	public ProxyHandler(Object proxied) {
    		this.proxied = proxied;
    	}
    
    	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    		before();
    		Object object = method.invoke(proxied, args);
    		after();
    		return object;
    	}
    
    	private void before() {
    		System.out.println("价格比较.");
    	}
    
    	private void after() {
    		System.out.println("推荐保险、预订酒店信息。");
    	}
    
    }
    
    

    客户端

    public class Customer {
    
    	public static void main(String args[]) {
        //我们传入火车售票处就能代理火车售票处
    		TrainTicketOffice trainTicketOffice = new TrainTicketOffice();
        //我们传入飞机售票处就能代理飞机售票处
    		//AirplaneTicketOffice airplaneTicketOffice = new AirplaneTicketOffice();
    		TicketOffice proxySubject = (TicketOffice) Proxy.newProxyInstance(TicketOffice.class.getClassLoader(),
    				new Class[] { TicketOffice.class }, new ProxyHandler(trainTicketOffice));
    
    		proxySubject.tickets();
    
    	}
    }
    

    由客户端选择需要那种模式的代理。但是这么写也有问题,就是永远无法解决接口代理的问题。


    CGlib来实现动态代理


    未完待续(需要其他设计模式的知识.)

    4.代理模式的问题

    1.使用JDK自带的代理真实角色必须实现某些接口.

    2.代理类会显式调用被代理类,增加了一层封装会明显增加业务的处理时间。

    3.代理类会增加一些额外的业务处理,使项目的结构不够清晰简单。

    5,总结

      代理模式在生活中随处可见。比如本例中的售票、找律师打官司等都是代理模式的体现。
    代理模式在代码中随处可见。比如spring的AOP各种各样的连接池。JDK也得反射包也专门为其准备了一个实现方式,可见代理模式的重要。 代理模式看似简单,实际使用起来需要严格区分使用场景不能和中介者模式和观察者模式搞混。正如本文开头所说代理模式最核心的是对原有对象进行替换,强调的是个体

  • 相关阅读:
    CentOS优化
    C++ 与OpenCV 学习笔记
    常用ubuntu命令
    对极几何笔记
    DBoW2 词袋模型笔记
    OKVIS(一)初始化流程及代码结构
    二进制描述子 BRIEF(ORB), BRISK, FREAK
    VIO 初始化小结
    VINS(十)FeatureManager(未完待续)
    VINS(九)Ceres Solver优化(未完待续)
  • 原文地址:https://www.cnblogs.com/yanlong300/p/8028152.html
Copyright © 2020-2023  润新知