定义
为其他对象提供一种代理以控制对这个对象的访问。
结构和说明
- Proxy:代理对象,通常具有如下功能。实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象。保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象。可以控制对具体目标对象的访问,并可以负责创建和删除它。
- Subject:目标接口,定义代理和具体目标对象的接口,这样就可以在任何使用具体目标对象的地方使用代理对象。
- RealSubject:具体的目标对象,真正实现目标接口要求的功能。
示例代码
/// <summary>
/// 抽象的目标接口,定义具体的目标对象和代理公用的接口
/// </summary>
public interface Subject
{
/// <summary>
/// 示意方法,一个抽象的请求方法
/// </summary>
void Request();
}
/// <summary>
/// 具体的目标对象,是真正被代理的对象
/// </summary>
public class RealSubject : Subject
{
public void Request()
{
//执行具体的功能处理
}
}
/// <summary>
/// 代理对象
/// </summary>
public class Proxy : Subject
{
//持有被代理的具体的目标对象
private RealSubject _realSubject = null;
/// <summary>
/// 构造方法,传入被代理的具体的目标对象
/// </summary>
/// <param name="realSubject"></param>
public Proxy(RealSubject realSubject)
{
_realSubject = realSubject;
}
public void Request()
{
//在转调具体的目标对象前,可以执行一些功能处理
//转调具体的目标对象的方法
_realSubject.Request();
//转掉具体的目标对象后,可以执行一些功能处理
}
}
例子示例代码
/// <summary>
/// 定义用户数据对象的接口
/// </summary>
public interface UserModelApi
{
void Request();
}
/// <summary>
/// 真正对象
/// </summary>
public class UserModel : UserModelApi
{
public string UserId { get; set; }
public string UserName { get; set; }
//这里去数据库重新获取数据
public void Request()
{
//这里写逻辑,数据库冲洗取值
UserId = "1";
UserName = "2";
}
}
/// <summary>
/// 代理对象,代理用户数据对象
/// </summary>
public class Proxy : UserModelApi
{
private UserModel _realSubject = null;
/// <summary>
/// 构造方法,传入被代理的具体目标对象
/// </summary>
/// <param name="realSubject"></param>
public Proxy(UserModel realSubject)
{
_realSubject = realSubject;
}
//标记是否已经重新装载过数据了
private bool _loaded = false;
public string UserId { get; set; }
public string DepId { get; set; }
public void Request()
{
_loaded = true;
_realSubject.Request();
}
}
例子:如果只是访问用户编号和用户姓名的数据,不需要重新查询数据库。只有当访问这两个数据以外数据时,才需要重新查询数据库已获得完整的数据。
认识代理模式
代理模式是通过创建一个代理对象,用这个代理对象去代表真实的对象,客户端得到这个代理对象后,对客户端并没有什么影响,就跟得到了真实对象一样来使用。
当客户端操作这个代理对象的时候,实际上功能最终还是会由真实的对象来完成,只不过是通过代理操作的,也就是客户端操作代理,代理操作真正的对象。
正是因为有代理对象夹在客户端和被代理的真实对象中间,相当于一个中转,那么在中转的时候就有很多花招可以玩,比如,判断一下权限,如果没有足够的权限那就不给你中转了,等等。
保护代理
保护代理是一种控制对原始对象访问的代理,多用于对象应该有不同得访问权限的时候。保护代理会检查调用者是否具有请求所必须的访问权限,如果没有相应的权限,那么就不会调用目标对象,从而实现对目标对象的保护。
示例需求
现在有一个订单系统,要求是:一旦订单被创建,只有订单的创建人才可以修改订单中的数据,其他人则不能修改。
代码示例
/// <summary>
/// 订单对象的接口定义
/// </summary>
public interface OrderApi
{
/// <summary>
/// 获取产品名称
/// </summary>
/// <returns></returns>
string GetProductName();
/// <summary>
/// 设置产品名称
/// </summary>
/// <param name="productName"></param>
/// <param name="user"></param>
void SetProductName(string productName, string user);
/// <summary>
/// 获取订单订购的数量
/// </summary>
/// <returns></returns>
int GetOrderNum();
/// <summary>
/// 设置订单订购的数量
/// </summary>
/// <param name="orderNum"></param>
/// <param name="user"></param>
void SetOrderNum(int orderNum, string user);
/// <summary>
/// 获取创建订单的人员
/// </summary>
/// <returns></returns>
string GetOrderUser();
/// <summary>
/// 设置创建订单的人员
/// </summary>
/// <param name="orderUser"></param>
/// <param name="user"></param>
void SetOrderUser(string orderUser, string user);
}
/// <summary>
/// 订单对象
/// </summary>
public class Order : OrderApi
{
//产品名称
private string _productName;
//订单采购数量
private int _orderNum;
//创建人
private string _orderUser;
public Order(string productName,int orderNum,string orderUser)
{
_productName = productName;
_orderNum = orderNum;
_orderUser = orderUser;
}
public string GetProductName()
{
return _productName;
}
public void SetProductName(string productName, string user)
{
_productName = productName;
}
public int GetOrderNum()
{
return _orderNum;
}
public void SetOrderNum(int orderNum, string user)
{
_orderNum = orderNum;
}
public string GetOrderUser()
{
return _orderUser;
}
public void SetOrderUser(string orderUser, string user)
{
_orderUser = orderUser;
}
}
/// <summary>
/// 订单的代理对象
/// </summary>
public class OrderProxy : OrderApi
{
//被代理的具体的目标对象
private Order order = null;
public OrderProxy(Order realSubject)
{
order = realSubject;
}
public string GetProductName()
{
throw new NotImplementedException();
}
public void SetProductName(string productName, string user)
{
//控制访问权限,只有订单创建人才能修改(其他类似)
if(user==GetOrderUser())
order.SetProductName(productName,user);
else
{
Console.WriteLine($"对不起{user},您无权限修改订单名称!");
}
}
public int GetOrderNum()
{
throw new NotImplementedException();
}
public void SetOrderNum(int orderNum, string user)
{
throw new NotImplementedException();
}
public string GetOrderUser()
{
throw new NotImplementedException();
}
public void SetOrderUser(string orderUser, string user)
{
throw new NotImplementedException();
}
}
思考代理模式
代理模式的本质:控制对象的访问。
何时选用代理模式
- 需要为一个对象在不同的地址空间提供局部代表的时候,可以使用远程代理
- 需要按照需要创建开销很大的对象的时候,可以使用虚代理。
- 需要控制对原始对象的访问的时候,可以使用保护代理。
- 需要在访问对象执行一些附加操作的时候,可以使用智能指引代理。