2.6設計模式之代理模式(Proxy)

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只需要知道BuyFoodOrderFoodGetFood。其他的BuyFood類都不需要知道,例如什么時候準備(使用延遲加載)、是否買過食物(使用緩存)、最近是否在減肥,要不要買?(權限檢查)、店鋪是否用戶太多不接單了(線程爭用檢測)等等,都可以交給對應的代理來做。

【模式對比】
有人可能會問,裝飾器模式也可以做到。那讓我們看一下代理模式與裝飾器模式的區別。
代理模式(Proxy),為其他對象提供一種代理以控制對這個對象的訪問。
說白了僅僅是在原有業務邏輯的基礎上添加原有功能的限制。
裝飾器模式(Decorator),動態地給一個對象添加一些額外的職責,就增加功能來說,裝飾模式比生成子類更為靈活。
裝飾器模式是對原有業務邏輯的動態擴展。
一個是原有功能的訪問限制,一個是原有功能的動態擴展

2.6.7 應用場景:

需要對引用對象進行延遲加載、訪問權限控制、篩選過濾等情況。

2.6.8 小結:

在不破壞原有封裝性的情況下對功能進行限制,利于后期的維護和擴展。


更多設計模式詳見:設計模式全家桶

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 設計模式概述 在學習面向對象七大設計原則時需要注意以下幾點:a) 高內聚、低耦合和單一職能的“沖突”實際上,這兩者...
    彥幀閱讀 3,796評論 0 14
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,581評論 25 708
  • 用兩張圖告訴你,為什么你的 App 會卡頓? - Android - 掘金 Cover 有什么料? 從這篇文章中你...
    hw1212閱讀 12,975評論 2 59
  • 從今天開始認真地分析我的身體,我的大腦,我的思想,我的心臟。尋找幸福感。 昨晚遲遲不能入睡,早上依...
    侃侃伐鳧兮閱讀 147評論 0 0
  • 上邪! 我欲與君相知, 長命無絕衰。 山無陵,江水為竭, 冬雷震震夏雨雪, 天地合, 乃敢與君絕!
    我在天空等你閱讀 296評論 0 0