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;
        }
    }
    /// 
    /// 下订单
    /// 
    public void OrderFood()
    {
        GetbuyFood.OrderFood();
        Debug.Log("代理已经接单,等待派送");
    }
    /// 
    /// 派送的过程
    /// 
    /// 
    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 小结:

在不破坏原有封装性的情况下对功能进行限制,利于后期的维护和扩展。


更多设计模式详见:设计模式全家桶

发表评论