博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
大龙帮忙去谈判---代理模式
阅读量:6432 次
发布时间:2019-06-23

本文共 8010 字,大约阅读时间需要 26 分钟。

前情提要

讲到, 小光利用调校好了饮品加料(糖, 冰, 蜂蜜...)的流程. 从此再也不怕客户的各种要求了. 各式饮品也成了小光热干面店的一大特色.

当然, 饮品的试喝也不是无期限了. 试喝期快结束了, 小光跟表妹商量了下, 结合顾客们的反馈, 他们选定了其中三家, 到底使用哪家还需要跟商家再谈判下决定.

所有示例源码已经上传到Github,

小光的烦恼

临近和供应商的谈判期了, 小光有点发怵了. 以往都是跟计算机打交道, 与人交道少, 何况还是商场...虽然自己是采购方, 不免还是有点虚.

先来看看要签单的小光:

// 照例抽象了一个Person接口:public interface Person {    /**     * 签单     * @param price     */    void signing(int price);}// 心底发虚的小光:public class XiaoGuang implements Person {    @Override    public void signing(int price) {        System.out.println("小光以" + price + "每箱的价格签单.");    }}复制代码

大龙出场

于是, 小光找来了做建材生意的堂哥大龙, 让大龙帮忙去谈判. 大龙欣然接受, 带着小光的底线就去了.

// 大龙public class DaLong implements Person {    private Person person;    public DaLong(Person person) {        this.person = person;    }    @Override    public void signing(int price) {        System.out.println("对方报价:" + price);        if (price < 100) {            this.person.signing(price);        }        else {            negotiate(price);        }    }    public void negotiate(int price) {        System.out.println("不接受, 要求降价" + (price - 80));    }}复制代码

大龙也继承自Person, 有签单的职责. 但是除了signing, 大龙还肩负谈判(negotiate)的职责. 在签单上也有一些限制(小光给他的底线是100每箱). 当然, 谈下来了, 签字还是需要小光签的.

谈判开始

大龙虽然比小光大不了几岁, 但可以说是商场老手了. 拿到小光的底线后, 他自己在这个基础上再砍了20, 然后去跟饮品供应商谈判了.

public class Demo {    public static void main(String[] args) {        DaLong daLong = new DaLong(new XiaoGuang());        // 第一轮, 对方报价120.        daLong.signing(120);        // 第二轮, 对方报价100.        daLong.signing(100);        // 第三轮, 对方报价90.        daLong.signing(90);    }}复制代码

酒桌上, 拉锯三轮, 拿下:

// output对方报价:120不接受, 要求降价40对方报价:100不接受, 要求降价20对方报价:90小光以90每箱的价格签单.复制代码

果然还是大龙技高一筹啊, 以比小光预期更少的价格成交.

小光也是从中学习到不少技巧...拜服大龙哥.

故事之后

照例, 故事之后, 我们用UML类图来梳理下上述的关系:

相比于之前的关系, 这个相对简单, 就两个角色, 小光和大龙, 都实现了Person接口. 关键点在于:

  • 大龙是直接和供应商打交道的, 但是实际的决策和行为(签单)是由小光来做的.
  • 也就是说大龙是小光的代理.

这就是我们所要说的代理模式:

为其他对象(小光)提供一个代理(大龙)以控制对这个对象的访问.

在我们这个例子, 由于小光怯场, 不方便直接和供应商谈判, 故而派出了代理大龙来直面供应商.

扩展阅读一

细心的同学可能有发现, 这个例子的模式貌似和有点类似啊. 这里大龙也相当于给小光装饰上了新的职责(谈判negotiate):

public void negotiate(int price) {    System.out.println("不接受, 要求降价" + (price - 80));}复制代码

那么代理模式相比与装饰模式有什么区别呢?

让我们再带上重点符来重温下二者:

  • 代理模式旨在为一个对象提供一个代理, 来控制对这个对象的访问.
  • 装饰模式旨在为一个对象动态添加职责, 增加这个对象的行为/属性.

二者虽然都会有代理类/装饰类实际调用被代理对象/被装饰对象的行为. 然而代理模式重在控制, 而装饰模式重在添加.

例如本例中, 大龙代理了小光的签单(signing)行为, 但不仅仅是像装饰模式那样, 加上某些行为/属性后就交给小光处理的. 大龙还加了控制:

public void signing(int price) {   System.out.println("对方报价:" + price);   if (price < 100) {       this.person.signing(price);   }   // 如果对方报价大于等于100的时候, 大龙并没有让小光处理.   else {       negotiate(price);   }}复制代码

如果对方报价大于等于100的时候, 大龙并没有让小光处理. 也就是说大龙是有控制权的.

扩展阅读二

上面说到大龙是有控制权的, 也就是说, 这种代理实际上是一种控制代理, 也可以称之为保护代理.

代理模式除了这种控制访问/保护性的, 常常用到的场景还有:

  • 远程代理: 为一个在不同的地址空间的对象提供局部代表, 从而可以隐藏这个被代理对象存在于不同地址空间的事实. 这个代表有点类似于大使, 故而也可以称之为"大使模式".
  • 智能引用代理: 在代理中对被代理对象的每个操作做些额外操作, 例如记录每次被代理对象被引用, 被调用的次数等. 有点像引用计数的感觉.

扩展阅读三

说到远程代理, 就有必要聊聊Android中著名的AIDL了. 熟悉AIDL的同学, 应该比较清晰了解了, AIDL就是一个典型的远程代理模式的运用.

创建一个简单的AIDL文件:

// IRemoteService.aidlpackage com.anly.samples;// Declare any non-default types here with import statementsinterface IRemoteService {    /**     * Demonstrates some basic types that you can use as parameters     * and return values in AIDL.     */    void signing(int price);}复制代码

生成的文件IRemoteService.java文件如下:

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: /Users/mingjun/Dev/my_github/AndroidLessonSamples/app/src/main/aidl/com/anly/samples/IRemoteService.aidl */package com.anly.samples;// Declare any non-default types here with import statementspublic interface IRemoteService extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.anly.samples.IRemoteService {        private static final java.lang.String DESCRIPTOR = "com.anly.samples.IRemoteService";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.anly.samples.IRemoteService interface,         * generating a proxy if needed.         */        public static com.anly.samples.IRemoteService asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.anly.samples.IRemoteService))) {                return ((com.anly.samples.IRemoteService) iin);            }            return new com.anly.samples.IRemoteService.Stub.Proxy(obj);        }        @Override        public android.os.IBinder asBinder() {            return this;        }        @Override        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {            switch (code) {                case INTERFACE_TRANSACTION: {                    reply.writeString(DESCRIPTOR);                    return true;                }                case TRANSACTION_signing: {                    data.enforceInterface(DESCRIPTOR);                    int _arg0;                    _arg0 = data.readInt();                    int _result = this.signing(_arg0);                    reply.writeNoException();                    reply.writeInt(_result);                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.anly.samples.IRemoteService {            private android.os.IBinder mRemote;            Proxy(android.os.IBinder remote) {                mRemote = remote;            }            @Override            public android.os.IBinder asBinder() {                return mRemote;            }            public java.lang.String getInterfaceDescriptor() {                return DESCRIPTOR;            }            @Override            public int signing(int price) throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                int _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    _data.writeInt(price);                    mRemote.transact(Stub.TRANSACTION_signing, _data, _reply, 0);                    _reply.readException();                    _result = _reply.readInt();                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }        }        static final int TRANSACTION_signing = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);    }    public int signing(int price) throws android.os.RemoteException;}复制代码

AIDL自动生成的java文件格式比较乱, 格式化了一下.

有几个关键点:

  1. IRemoteService是一个接口, 有signing方法
  2. IRemoteService中有一个静态抽象内部类Stub, 实现了IRemoteService接口.(集成了Binder再次就不讨论了)
  3. Stub中有一个asInterface方法, 返回一个IRemoteService, 实际上是Proxy.
  4. Stub中有一个私有的内部类Proxy.
  5. 这个内部类的机制是为了增加内聚, 一个AIDL生成的文件理论上是一个业务服务体系, 故而放在一起.

我们实现下Proxy和Stub, 然后用UML图来梳理下:

客户端AidlSampleActivity:

// 绑定服务的ServiceConnection中获取Proxy:public void onServiceConnected(ComponentName name, IBinder service) {  mRemoteService = IRemoteService.Stub.asInterface(service);  isBound = true;  if (mRemoteService != null) {      try {          mCurrentPrice = mRemoteService.signing(mCurrentPrice);          mResult.setText("Result:" + mCurrentPrice);      } catch (RemoteException e) {          e.printStackTrace();      }  }}复制代码

服务RemoteService继承Stub生成的IBinder:

private IRemoteService.Stub mBinder = new IRemoteService.Stub() {   @Override   public int signing(int price) throws RemoteException {       int signingPrice = price - 10;       Log.d("mingjun", "signing: " + signingPrice);       return signingPrice;   }};复制代码

为了更清晰表达这是一个远程代理, 我们将RemoteService开辟在了其他进程中:

复制代码

本文不深入AIDL的应用和原理, 具体客户端(AidlSampleActivity)和服务(RemoteService)的代码就不贴了, .


OK, 这就是我们今天要说的代理模式.

有了代理模式, 尤其是远程代理, 小光发现有时候自己都可以不用亲临店了呢, 有了更多的时间出去考察新店地址了...哈哈.

转载地址:http://lmxga.baihongyu.com/

你可能感兴趣的文章
16 Errors and Exceptions
查看>>
机器视觉-halcon学习笔记6
查看>>
Oracle 之 AIO (异步io)
查看>>
iOS埋点统计
查看>>
建造者模式、组合模式和装饰者模式
查看>>
Effective C++ 之让自己熟悉Boost
查看>>
指针函数与函数指针理解
查看>>
UIbottun使用详解
查看>>
字符集研究之多字节字符集和unicode字符集
查看>>
writing-mode 属性:改变文本横纵方向
查看>>
java基础_break和contiune用法
查看>>
面试-java反射
查看>>
各种改改改(未完成)
查看>>
清理ambari安装的hadoop集群
查看>>
冒泡排序
查看>>
IDE安装完成无法打开,报错Fail load JVM DLL 问题与解决方案
查看>>
【05】循序渐进学 docker:系统资源和网络
查看>>
Infopath 在保存表单后,打印表单
查看>>
熟悉常用的HDFS操作
查看>>
远景面试算法题——FolderSize
查看>>