2.6.1 模式意圖:
在系統中有時需要對某對象創建時機進行約束;內容添加過濾行為;對象間接引用,想滿足以上種種情況,但又不想破壞其原有功能結構,這時可以使用代理模式以替身方式來達到目的。
2.6.2 模式概念:
它屬于結構型模式,為對象提供一個代理,并由代理對象控制原對象的訪問。
2.6.3 模式元素:
- 元素抽象(IBuyFood)
- 元素細節(BuyFood)
- 元素代理(BuyFoodProxy)
2.6.4 代碼示例:
A.購買接口
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public interface IBuyFood
{
void OrderFood();
bool GetFood();
}
B.常規購買
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
public class BuyFood : IBuyFood
{
private bool isOrderSuccessful = false;
public BuyFood()
{
Debug.Log("買東西時各種準備");
Thread.Sleep(1000);
}
public bool GetFood()
{
if (isOrderSuccessful)
{
Debug.Log("買食物成功");
return true;
}
else
{
Debug.Log("買食物失敗");
return false;
}
}
public void OrderFood()
{
isOrderSuccessful = true;
}
}
C.代理購買
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Custom.Log;
public class BuyFoodProxy : IBuyFood
{
protected readonly object syncRoot = new object();
private BuyFood buyFood = null;
protected BuyFood GetbuyFood
{
get
{
//雙if加Lock鎖也可以不加
if (buyFood == null)
{
lock (syncRoot)
{
if (buyFood == null)
{
Debug.Log("代理準備中。。。。");
buyFood = new BuyFood();
}
}
}
return buyFood;
}
}
/// <summary>
/// 下訂單
/// </summary>
public void OrderFood()
{
GetbuyFood.OrderFood();
Debug.Log("代理已經接單,等待派送");
}
/// <summary>
/// 派送的過程
/// </summary>
/// <returns></returns>
public bool GetFood()
{
if (GetbuyFood.GetFood())
{
Debug.Log("代理派送食物成功");
return true;
}
else
{
Debug.LogWarning("代理派送食物失敗");
return false;
}
}
}
示例調用
void Start()
{
IBuyFood buyFood = new BuyFood();
this.Log("思考是否買吃的???");
this.Log("確定買吃的!!!");
buyFood.OrderFood();
buyFood.GetFood();
Debug.Log(new string('*', 20));
buyFood = new BuyFoodProxy();
this.Log("思考是否買吃的???");
this.Log("確定買吃的!!!");
buyFood.OrderFood();
buyFood.GetFood();
}
打印如下
2.6.5 寫法對比:
略
2.6.6 模式分析:
使用代理后貌似和不用沒有區別,但仔細看打印信息,
買東西時各種準備
與思考是否買吃的
的位置已經發生了改變,使用代理模式把買東西時各種準備
延遲了,在真正需要的時候才進行初始化,這種延遲的初始化在代理中經常使用。
根據單一職責原則我們知道,BuyFood只需要知道
BuyFood
、OrderFood
和GetFood
。其他的BuyFood類都不需要知道,例如什么時候準備(使用延遲加載)、是否買過食物(使用緩存)、最近是否在減肥,要不要買?(權限檢查)、店鋪是否用戶太多不接單了(線程爭用檢測)等等,都可以交給對應的代理來做。
【模式對比】
有人可能會問,裝飾器模式也可以做到。那讓我們看一下代理模式與裝飾器模式的區別。
代理模式(Proxy),為其他對象提供一種代理以控制對這個對象的訪問。
說白了僅僅是在原有業務邏輯的基礎上添加原有功能的限制。
裝飾器模式(Decorator),動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。
裝飾器模式是對原有業務邏輯的動態擴展。
一個是原有功能的訪問限制,一個是原有功能的動態擴展。
2.6.7 應用場景:
需要對引用對象進行延遲加載、訪問權限控制、篩選過濾等情況。
2.6.8 小結:
在不破壞原有封裝性的情況下對功能進行限制,利于后期的維護和擴展。