前置文章: 设计模式的原则
其他设计模式:用心理解设计模式专栏
设计模式相关代码已统一放至 我的 Github
一、定义
结构型模式之一。
Provide a surrogate or placeholder for another object to control acess to ot.
(为其他对象提供一种代理,以控制对这个对象的访问)
二、结构解析
代理模式的一般结构有三种角色:抽象主题、真实主题(被代理者)、代理者。
抽象主题:负责定义真实主题要被代理的业务方法接口。
真实主题:继承抽象主题,实现自己真实的业务方法接口。
代理者:也继承抽象主题,拥有与真实主题(被代理者)相同的要被代理的业务方法接口, 从外观上看代理者与被代理者似乎一样。代理者内部依赖真实主题,在实现抽象主题定义的接口时,增加了一些前置的访问条件,满足条件后原封不动调用真实主题(被代理者)的业务方法。
三、评价
代理模式封装了客户访问真实主题(被代理者)的过程,充当代理作用,保护了真实主题(控制了客户对真实主题内容的访问权限)。由于代理者与真实主题接口相同,客户在访问时,并不知道直接访问的是谁,不知道代理者是否存在。
注意,不要理解跑偏,代理模式的主要作用是访问控制。需要一条龙打杂服务的,请找 外观模式。
事实上,单层的 装饰器模式 (多层可以对装饰进行排列组合)和代理模式难以区分。都可用于增强真实主题的方法。
代理模式中,各角色的职责清晰,符合开闭原则, 易扩展易复用。
代理模式也是 AOP(面向切面编程)的重要实现方式之一。
AOP简单解释:动态地为类的方法(切面上)添加额外的增强逻辑。这些增强逻辑一般与主要功能无关,如日志记录,事件统计、权限验证,异常拦截等。
使用时,可根据需求,抽取主题类的部分方法为抽象接口,然后对这些接口进行代理(后期代理需求)。
四、实现
namespace Proxy
{
//抽象主题
public abstract class Subject
{
//定义和声明真实主题要被代理的业务方法接口
public abstract void DoSth();
}
//真实主题
public class RealSubject : Subject
{
//实现业务方法接口,真实要做的事情。
public override void DoSth(){}
}
//代理者
public class Proxy : Subject
{
//内部依赖真实主题
private Subject subject = new RealSubject();
//代理者拥有与真实主题(被代理者)
public override void DoSth()
{
//此处定义可访问条件,如只有亲友可访问
string who = "zhangsan";
bool canVisit = (who == "kinsfolk" || who == "friend");
if (canVisit)
{
//最终调用真实主题的业务方法
this.subject.DoSth();
}
}
//还可在真实调用前后添加增强逻辑
private void Before() { }
private void After() { }
}
public class Client
{
static public void Main()
{
Proxy proxy = new Proxy();
proxy.DoSth();
}
}
}
五、动态代理
所谓动态代理,即,在运行时为目标接口动态地生成其代理类。(注意是目标接口/不是目标类,这样客户才能无法区分具体调用的是谁。)
我们已经知道,代理模式可以在接口不变、并且不修改原主题类的情况下,对主题的方法添加访问控制逻辑(或方法增强逻辑)。当有大量的代理需求出现时,就要静态地定义很多代理类。
动态生成代理,可以统一地对各代理类进行管理,减少冗余的代码。
在C#中,可以使用 System.Reflection.Emit 动态生成代码。然而在Unity中无法跨平台使用。