上集講到, 小光利用裝飾者模式調校好了飲品加料(糖, 冰, 蜂蜜...)的流程. 今後不再怕客戶的各類要求了. 各式飲品也成了小光熱乾麪店的一大特點.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, 這就是咱們今天要說的代理模式.有了代理模式, 尤爲是遠程代理, 小光發現有時候本身均可以不用親臨店了呢, 有了更多的時間出去考察新店地址了...哈哈.