zoukankan      html  css  js  c++  java
  • 设计模式之代理模式

    一、什么是代理模式(Porxy)

      概念:代理模式就是为其他对象提供一种代理以控制对这个对象的访问。

      现实生活中也有很多行为吻合代理模式。比如店外卖,客户在APP上下单后,店长会接单。这个时候店长可以选择自己去送这份外卖,也可以委托送餐员代理店长去送这份外卖。当然店长是可以自己送,但店长送了外卖店就没人看着了,而让送餐员代理送外卖就不会这样了。这里很显然店长是对象本尊(Subject),送餐员是代理对象(Proxy ),代理对象中有店长给的订单信息,比如送到哪里,几点之前要送到,这就说明代理对象中需要包含本尊。下面根据实际代码来说明代理模式和非代理的具体实现。

    二、模式对比

    1、非代理模式

    非代理模式即店长自己送,无须委托送餐员代理送。即直接创建本尊对象并访问本尊方法,没有中间的代理对象。

    本尊代码

    public class ShopKeeper {
    
        //客户信息
        private Consumer consumer;
        
        public ShopKeeper(Consumer consumer){
            this.consumer = consumer;
        }
        
        //外卖订单信息
        public void send(){
            System.out.println(consumer.getConName() + "的订单,店长自己送,送到胶东路520弄,11:30之前送达...");
        }
        
    }

    客户代码

    public class Consumer {
    
        private String conName;
        
        public Consumer(String conName){
            this.conName = conName;
        }
    
        public String getConName() {
            return conName;
        }
    }

    客户端测试代码

    public class Show {
    
        public static void main(String[] args) {
            Consumer consumer = new Consumer("Tom");
            ShopKeeper shopKeeper = new ShopKeeper(consumer);
            shopKeeper.send();
        }
        
    }

    这样店长和客户的代码就耦合在一起,不利于后期维护升级。再者店长和客户本来就不需要相互包含,他们之间是无状态的。像很多pub/sub的中间件,比如dubbo,activeMQ等等,他们都是基于消息的发布的订阅机制,生产者和消费者之间没有必要有状态交互,你消费者挂了我生产者还是继续生产消息,互不影响,其实很多技术都是想通的,这里和代理模式就和类似。下面来看看代理模式是怎么处理的。

    2、代理模式

    提供了一个共有的送外卖接口

    public interface Send {
    
        void sendName();
        void sendTime();
        void sendAddress();
        
    }

    店长本尊对象,实现了共有的送外卖接口。

    /**
     * 店长对象(本尊)需要实现Send接口
     * @author user
     */
    public class ShopKeeper implements Send{
    
        private Consumer consumer;
        
        public ShopKeeper(Consumer consumer){
            this.consumer = consumer;
        }
        
        @Override
        public void sendName() {
            System.out.print(consumer.getConName() + "的订单,");
        }
        
        @Override
        public void sendTime() {
            System.out.print("12:00之前送达,");
        }
    
        @Override
        public void sendAddress() {
            System.out.print("送到长岛路520弄,由代理对象配送...");
        }

    新增了代理对象,代理对象需要包含本尊,并且也要实现送外卖(Send)接口

    /**
     * 代理对象也需要实现Send接口
     * @author user
     *
     */
    public class ProxySend implements Send{
    
        private ShopKeeper shopKeeper;
        
        public ProxySend(Consumer consumer){
            this.shopKeeper = new ShopKeeper(consumer);
        }
        
        @Override
        public void sendName() {
            shopKeeper.sendName();
        }
    
        @Override
        public void sendTime() {
            shopKeeper.sendTime();
        }
    
        @Override
        public void sendAddress() {
            shopKeeper.sendAddress();
        }
    
    }

    客户对象没有变化

    public class Consumer{
        
        private String conName;
    
        public String getConName() {
            return conName;
        }
    
        public void setConName(String conName) {
            this.conName = conName;
        }
    }

    客户端测试代码

    public class Show {
    
        public static void main(String[] args) {
            
            Consumer consumer = new Consumer();
            consumer.setConName("外卖张");
            ProxySend proxy = new ProxySend(consumer);
            proxy.sendName();
            proxy.sendTime();
            proxy.sendAddress();
            
        }
        
    }

    看输出

    外卖张的订单,12:00之前送达,送到长岛路520弄...

    这样代理对象就帮本尊完成了任务,可以看到客户端的代码变化很大,客户端根本不知道本尊的存在,因为在客户端代码中至始至终都没有看到本尊对象的创建,连实例都没有,这其实就是代理对象的作用之一,隐藏本尊。

    3、代理模式基本结构

    Subject类,定义了RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy,这里使用抽象类

    public abstract class Subject {
    
        public abstract void request(); 
        
    }

    RealSubject类,定义了Proxy所代表的真是实体

    public class RealSubject extends Subject {
    
        @Override
        public void request() {
            System.out.println("真实的请求");
        }
    
    }

    Proxy类,保存了一个引用使得代理对象可以访问实体对象,并提供一个与Subject的接口相同的接口,这样代理就可以用来代理实体。

    public class Proxy extends Subject{
    
        RealSubject realSubject;
        
        @Override
        public void request() {
            if (realSubject == null) {
                realSubject = new RealSubject();
            }
            realSubject.request();
        }
    
    }

    客户端代码

    public class Show {
    
        public static void main(String[] args) {
            Proxy proxy = new Proxy();
            proxy.request();
        }
        
    }

    测试结果

    真实的请求

    4、UML图

    三、总结

    代理模式一般用在一下几种场合。1、远程代理,也就是为了一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象存在于不同地址空间的事实。2、虚拟代理,是根据需要创建开销很大的对象。通过它来存放实例化需要很长时间的真实对象。3、安全代理,用来控制真实对象访问是的权限。4、智能指引,是指当前调用真实的对象时,代理处理另外一些事情。所以代理模式还算比较常用的。

    作者:当代唐寅 琐碎事情不多,烦心的事没有,日子过得简单。听听歌,看看电影,打打球。我养了植物,时不时的会出去走走,太阳跟雨都喜欢。
    本文版权归作者和博客园共有,欢迎转载。
  • 相关阅读:
    dtoj4697. 格
    dtoj3317. 人类基因(human)
    Codeforces Round #661 (Div. 3)
    Codeforces Round #667 (Div. 3).md
    Codeforces Round #674 (Div. 3)
    Codeforces Round #693 (Div. 3)
    Educational Codeforces Round 102 (Rated for Div. 2)(A-E)
    Codeforces Round #695 (Div. 2)
    2020 ICPC 上海(8/13)
    kuangbin带你飞 专题十五 数位DP
  • 原文地址:https://www.cnblogs.com/mxlandxt/p/6892914.html
Copyright © 2011-2022 走看看