共计 2922 个字符,预计需要花费 8 分钟才能阅读完成。
概念界定
在解说代理模式之前,咱们须要辨别一下委托、代理、中介三者的概念,因为很多人可能并不分明他们之间的区别,甚至认为没有区别。然而,如果对这三个概念没有清晰的界定,很可能会在学习的过程中一头雾水,可能会感觉代理模式跟谁都很像,跟谁都容易混同。
委托(Delegate)
委托跟代理是绝对的,通常咱们说 ”A 委托 B 办某事 ”,也相当于在说 ”B 代理 A 办某事 ”,因而,委托和代理通常能够认为是等价的,这也是为什么很多时候代理模式也能够叫委托模式了,然而,在 C#中,委托被赋予了新的含意,它是一种援用办法的类型, 相当于 C++
里的函数指针。上面是委托的一个简略实现,但这只是为了阐明委托在 C# 中新的含意,不是本文的重点,看看就好。
public delegate int Calc(int x, int y);
class Program
{static void Main(string[] args)
{Calc calc = new Calc(Add);
int result = calc(1, 2);
Console.WriteLine(result);
calc = Subtract;
result = calc(1, 2);
Console.WriteLine(result);
}
public static int Add(int x, int y)
{return x + y;}
public static int Subtract(int x, int y)
{return x - y;}
}
代理(Proxy)
如下图所示,代理的作用就是代替 D(被代理者)实现某一件事,A、B、C 拜访了代理就等同拜访了 D。看似说了句废话,其实不然,这里最要害的一点就是 A、B、C 原本是能够拜访 D 的,然而因为 D 的懈怠,或者拜访过程比拟艰难甚至碰壁(比方线路被切断),因而才有了代理,有了代理后,A、B、C 就不必再拜访 D 了,代理会全权处理来自 A、B、C 所有申请。见他如见我就是代理,如钦差大臣,产品代理商,代购,租房代理等。
中介(Mediator)
如下图所示,中介是在一组简单的关系中牵线搭桥,使得 A、B、C、D 相互之间的交换变得简略,中介不能齐全代替 A、B、C、D 中的任何一方,牵线搭桥之后,被牵线的单方还是要见面的,如租房中介,婚姻中介等,婚姻中介介绍相亲的单方意识,但你不能要求婚姻中介替你谈恋爱甚至结婚生子,然而代理能够。
咱们之所以区分不清楚,是因为生存中很多时候就没辨别分明,例如,咱们很多时候认为租房中介就是租房代理,而事实并非如此,仅仅是因为很多时候一个机构同时具备了两种角色而已,简略总结一下:
- 委托和中介是等价的,只是主谓方向刚好产生了对调;
- 代理能够全权代理被代理者,被代理者从头至尾都能够不必跟访问者交互,而中介只是牵线,最终被牵线的单方还是要交互的;
- 代理通常解决的是多对一的关系,而中介解决的是多对多的关系,见他如见我是代理,牵线搭桥是中介,好好领会一下其中的区别。
定义
书归正传,代理模式就是为其余对象提供一种代理以管制对这个对象的拜访。
应用场景
Windows 快捷方式,VPN,防火墙,RPC 调用,翻墙等。
目标
-
在不扭转原有代码的根底上,对原有类加以控制,如下加日志和异样捕捉体现的就是一种访问控制:
public interface IUserRepository {User Get(int id); } public class UserRepository : IUserRepository { private static readonly List<User> _users = new List<User> {new User{Id=1,Name="zs"}, new User{Id=2,Name="ls"}, new User{Id=3,Name="ww"} }; public User Get(int id) { return _users .FirstOrDefault(u => u.Id == id); } } public class UserRepositoryProxy : IUserRepository {private readonly IUserRepository _userRepository = new UserRepository(); private readonly ILogger<UserRepositoryProxy> _logger; public UserRepositoryProxy(ILogger<UserRepositoryProxy> logger) {this._logger = logger;} public User Get(int id) { try {_logger.LogDebug("UserRepositoryProxy-Get In:id={0}", id); return _userRepository.Get(id); } catch (Exception ex) {_logger.LogError(ex, "UserRepositoryProxy-Get Error."); throw; } } }
-
拜访因为某种原因不能间接拜访或者间接拜访艰难的第三方组件或中间件,如上面的 HTTP 申请:
public interface IUserProxy {string GetUserById(int id); } public class UserProxy : IUserProxy {public string GetUserById(int id) {using (var client = new HttpClient()) { var result = client .GetAsync($"https://localhost:5001/user?id={id}") .GetAwaiter() .GetResult(); return result.Content .ReadAsStringAsync() .GetAwaiter() .GetResult();} } }
UML 类图
代理模式通常采纳组合的形式实现,因为被代理者往往不心愿被客户端间接拜访,当然,也并不是任何时候都有明确的被代理对象,例如下面的 HTTP 申请就不晓得具体代理的是谁。然而,能够很显著的看出,这里是代理模式,代理的是对网络 API 接口的申请。因而,代理模式重在思维,而并非代码构造,如果某种场景代码构造和其余模式相似,或者和下面的 UML 类图齐全不同也不必感觉奇怪。
和适配器比拟
代理模式和适配器模式看似都是在两个对象之间建设桥梁,使二者能够互相通信,因而他们的代码构造有时候是一样的,然而他们之间有显著的区别:
- 适配器模式的目标是接口转换,使本来不兼容而不能一起工作的类能够一起工作;
- 代理模式的目标是间接拜访和访问控制;
- 适配器模式面向的是不能一起工作的两个类,而代理模式是面向本来能够一起工作的两个类。
总结
随着零碎复杂度的倒退,代理模式更偏差于是一种架构模式,在各种框架中以及与各种中间件交互是是十分常见的,而在咱们本人的代码中反而很少见了,它更多的体现的是一种思维,而非代码实现。绝对于如何实现代理模式,更重要的应该是什么时候什么场景应该应用代理模式,晓得了什么时候什么场景应用,就不会纠结实现进去的像适配器模式还是像装璜模式了,即便像也仅仅是长得像而已,实质是齐全不同的。
源码链接
更多内容,欢送关注公众号: