定义:代理模式,为其他对象提供一种代理以控制对这个对象的访问,及通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作
应用场景:1、比如在某对象执行方法后,记录日志;
代理模式可以分为静态代理和动态代理。静态代理就是在代码编译时,硬编码到程序中的代理类;动态代理就是在程序运行是动态创建代理类。
静态代理
这种代理方式需要目标对象和代理对象实现同样的接口。
用户管理的代理实现:
接口类:IUser
public interface IUser { void AddUser(string name); }
目标类:User
public class User : IUser { public void AddUser(string name) { Console.WriteLine("添加用户:{0}",name); } }
代理类:UserProxy
public class UserProxy : IUser { private IUser User; public UserProxy(IUser _user) { User = _user; } public void AddUser(string name) { Console.WriteLine("添加用户前做些什么"); User.AddUser(name); Console.WriteLine("添加用户后做些什么"); } }
测试:
UserProxy userProxy = new UserProxy(new User()); userProxy.AddUser("Alan"); Console.Read();
输出结果:
添加用户前做些什么 添加用户:Alan 添加用户后做些什么
优点:
1、可以在不修改原有对象的前提下扩展目标对象的功能。
缺点:
1、冗余,由于代理对象要与目标对象一致的接口,所以如果多个类型对象需要实现同样的代理逻辑就需要扩展更多的代理类。
2、不易维护,如果接口增加了方法,那么目标对象和代理对象都需要修改。
针对这些缺点,我们来学习一下动态代理。
动态代理
在C#中我们可以使用Castle.DynamicProxy动态的在内存中创建代理对象,从而实现对目标对象的代理功能。
接下来我们在原有接口的基础上增加一个DeleteUser的方法,并且定义一个类UserIntercept实现IIntercept接口,代码如下:
注意要被代理的方法必须是virtual虚方法,因为它会被代理类重写(override)
目标类:User
public class User : IUser { public virtual void AddUser(string name) { Console.WriteLine("添加用户:{0}", name); } public virtual void DeleteUser(string name) { Console.WriteLine("删除用户:{0}", name); } }
拦截器类:UserIntercept
public class UserIntercept : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine("操作用户前"); //执行代理方法 invocation.Proceed(); Console.WriteLine("操作用户后"); } }
客户端调用:
var proxyGenerator = new ProxyGenerator(); var handler = new UserIntercept(); IUser user = proxyGenerator.CreateClassProxy<User>(handler); user.AddUser("Alan");
输出结果:
操作用户前 添加用户:Alan 操作用户后
从以上结果中可以看出,动态代理就是弥补了静态代理存在的缺陷,不管是代理多个不同类型的对象还是多个不同的方法都可以通过动态代理来扩展方法。