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只需要知道
BuyFood
、OrderFood
和GetFood
。其他的BuyFood类都不需要知道,例如什么时候准备(使用延迟加载)、是否买过食物(使用缓存)、最近是否在减肥,要不要买?(权限检查)、店铺是否用户太多不接单了(线程争用检测)等等,都可以交给对应的代理来做。【模式对比】
有人可能会问,装饰器模式也可以做到。那让我们看一下代理模式与装饰器模式的区别。
代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问。
说白了仅仅是在原有业务逻辑的基础上添加原有功能的限制。
装饰器模式(Decorator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
装饰器模式是对原有业务逻辑的动态扩展。
一个是原有功能的访问限制,一个是原有功能的动态扩展。
2.6.7 应用场景:
需要对引用对象进行延迟加载、访问权限控制、筛选过滤等情况。
2.6.8 小结:
在不破坏原有封装性的情况下对功能进行限制,利于后期的维护和扩展。