上集讲到, 小光利用装饰者模式调校好了饮品加料(糖, 冰, 蜂蜜...)的流程. 今后不再怕客户的各类要求了. 各式饮品也成了小光热干面店的一大特点.java
固然, 饮品的试喝也不是无期限了. 试喝期快结束了, 小光跟表妹商量了下, 结合顾客们的反馈, 他们选定了其中三家, 到底使用哪家还须要跟商家再谈判下决定.android
全部示例源码已经上传到Github, 戳这里git
临近和供应商的谈判期了, 小光有点发怵了. 以往都是跟计算机打交道, 与人交道少, 况且仍是商场...虽然本身是采购方, 难免仍是有点虚.github
先来看看要签单的小光:api
// 照例抽象了一个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 + "每箱的价格签单.");
}
}复制代码
因而, 小光找来了作建材生意的堂哥大龙, 让大龙帮忙去谈判. 大龙欣然接受, 带着小光的底线就去了.app
// 大龙
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每箱). 固然, 谈下来了, 签字仍是须要小光签的.ide
大龙虽然比小光大不了几岁, 但能够说是商场老手了. 拿到小光的底线后, 他本身在这个基础上再砍了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);
}
}复制代码
酒桌上, 拉锯三轮, 拿下:this
// output
对方报价:120
不接受, 要求降价40
对方报价:100
不接受, 要求降价20
对方报价:90
小光以90每箱的价格签单.复制代码
果真仍是大龙技高一筹啊, 以比小光预期更少的价格成交.
小光也是从中学习到很多技巧...拜服大龙哥.spa
照例, 故事以后, 咱们用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.aidl
package com.anly.samples;
// Declare any non-default types here with import statements
interface 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 statements
public 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文件格式比较乱, 格式化了一下.
有几个关键点:
- IRemoteService是一个接口, 有signing方法
- IRemoteService中有一个静态抽象内部类Stub, 实现了IRemoteService接口.(集成了Binder再次就不讨论了)
- Stub中有一个asInterface方法, 返回一个IRemoteService, 其实是Proxy.
- Stub中有一个私有的内部类Proxy.
- 这个内部类的机制是为了增长内聚, 一个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开辟在了其余进程中:
<service android:name=".aidl.RemoteService" android:process="com.anly.other"/>复制代码
本文不深刻AIDL的应用和原理, 具体客户端(AidlSampleActivity)和服务(RemoteService)的代码就不贴了, 完整代码点这里.
OK, 这就是咱们今天要说的代理模式.有了代理模式, 尤为是远程代理, 小光发现有时候本身均可以不用亲临店了呢, 有了更多的时间出去考察新店地址了...哈哈.