前言
假设现在有这样一个场景, 高中时小明喜欢小红,因为害羞等不好意思向隔壁班的小红表达爱意,于是就请小华代表他去向小红送礼物。常规做法可能就是一个送礼物的类,一个女孩类,但这样导致的结果就是要么是小明送给小红,要么是小华送给小红。 但现在场景是小明委托小华送礼物给小红,他们之间存在一定的间接联系
代理模式定义
代理模式是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。
代理模式结构图和实现
结构图
- Subject:定义了Proxy和RealSubject共用的接口,这样就可以在任何使用RealSubject的地方使用Proxy
- RealSubject:定义Proxy代表的真实实体
- Proxy:保存一个引用,使得代理可以访问实体,并提供一个与Subject相同的接口,这样代理就可以用来替代实体
代码实现
从结构图不难看出,我们首先要定义一个送礼物的接口,让代理和真实"追求者"都去实现这个接口
interface IGaveGift
{
void GiveLolly();
void GiveChocolate();
void GiveFlower();
}
定义"追求者",继承自代理接口IGaveGift
public class Purist : IGaveGift
{
private Girl _girl;
public Purist(Girl girl)
{
_girl = girl;
}
public void GiveChocolate()
{
Console.WriteLine($"送了一盒巧克力给{_girl.Name}");
}
public void GiveFlower()
{
Console.WriteLine($"送了99朵玫瑰花给{_girl.Name}");
}
public void GiveLolly()
{
Console.WriteLine($"送了一支棒棒糖给{_girl.Name}");
}
}
定义代理,也需要去继承送礼物的接口,并且实现
public class Proxy : IGaveGift
{
private Purist xiaoming;
public Proxy(Girl girl)
{
xiaoming = new Purist(girl);
}
public void GiveChocolate()
{
xiaoming.GiveChocolate();
}
public void GiveFlower()
{
xiaoming.GiveFlower();
}
public void GiveLolly()
{
xiaoming.GiveLolly();
}
}
但这里不同的时,代理并不是直接去实现这个接口,而是通过实例化追求者,再用追求者去调用送礼物的方法
最后在客户端使用,代码如下:
static void Main(string[] args)
{
Girl xiaohong = new Girl() { Name = "小红" };
Proxy xiaohua = new Proxy(xiaohong);
xiaohua.GiveChocolate();
xiaohua.GiveFlower();
xiaohua.GiveLolly();
Console.WriteLine("Press Any Key to end!");
Console.ReadKey();
}
代理模式优缺点
优点
- 你可以在客户端毫无察觉的情况下控制服务对象。
- 如果客户端对服务对象的生命周期没有特殊要求, 你可以对生命周期进行管理。
- 即使服务对象还未准备好或不存在, 代理也可以正常工作。
- 开闭原则。 你可以在不对服务或客户端做出修改的情况下创建新代理。
缺点
- 代码可能会变得复杂, 因为需要新建许多类。
- 服务响应可能会延迟,因为可能经过多次"流转"
代理模式使用场景
代理将自己伪装成数据库对象, 可在客户端或实际数据库对象不知情的情况下处理延迟初始化和缓存查询结果的工作。
信用卡是银行账户的代理, 银行账户则是一大捆现金的代理。 它们都实现了同样的接口, 均可用于进行支付。