ProxyPattern-代理模式
在C#中,代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过创建一个代理对象来控制对其他对象的访问。代理对象充当着客户端和被代理对象之间的中间层,可以在访问对象时添加额外的功能,例如权限验证、延迟加载等。
代理模式有以下几个关键角色:
Subject(主题):定义了代理对象和真实对象的共同接口,客户端通过该接口访问真实对象。
RealSubject(真实主题):是代理模式中被代理的对象。它实现了Subject接口,并定义了真实对象的业务逻辑。
Proxy(代理):实现了Subject接口,并持有一个真实主题的引用。它可以代理客户端的请求,在调用真实主题前后执行额外的逻辑。
namespace ProxyPattern_代理模式
{
/// <summary>
/// 业务接口
/// </summary>
public interface ISubject
{
List<string> GetSomethingLong();
void DoSomethingLong();
}
}
namespace ProxyPattern_代理模式
{
/// <summary>
/// 具体业务
/// </summary>
public class RealSubject: ISubject
{
public RealSubject()
{
Thread.Sleep(2000);
Console.WriteLine("RealSubject被构造。。。");
}
public void DoSomethingLong()
{
Thread.Sleep(1000);
Console.WriteLine("DoSomethingLong");
}
public List<string> GetSomethingLong()
{
Thread.Sleep(1000);
Console.WriteLine("GetSomethingLong");
return new List<string>() { "123", "456", "789" };
}
}
}
namespace ProxyPattern_代理模式
{
internal class Program
{
static void Main(string[] args)
{
{
ISubject subject = new RealSubject();
subject.GetSomethingLong();
subject.DoSomethingLong();
//输出结果
//RealSubject被构造。。。
//GetSomethingLong
//DoSomethingLong
}
}
}
}
当我们需要新增运行日志或者额外代码逻辑时,可以使用代理模式增加此功能,符合开闭原则
namespace ProxyPattern_代理模式
{
public class ProxySubject : ISubject
{
private ISubject _iSubject = new RealSubject();
public void DoSomethingLong()
{
Console.WriteLine("prepare DoSomethingLong");
_iSubject.DoSomethingLong();
}
public List<string> GetSomethingLong()
{
Console.WriteLine("prepare GetSomethingLong");
return _iSubject.GetSomethingLong();
}
}
}
namespace ProxyPattern_代理模式
{
internal class Program
{
static void Main(string[] args)
{
{
ISubject subject = new RealSubject();
subject.GetSomethingLong();
subject.DoSomethingLong();
//输出结果
//RealSubject被构造。。。
//GetSomethingLong
//DoSomethingLong
}
{
ISubject subject = new ProxySubject();
subject.GetSomethingLong();
subject.DoSomethingLong();
//输出结果
//RealSubject被构造。。。
//prepare GetSomethingLong
//GetSomethingLong
//prepare DoSomethingLong
//DoSomethingLong
}
{
}
Console.Read();
}
}
}
异常代理,在代理类中增加try-catch异常处理
namespace ProxyPattern_代理模式
{
public class ProxySubject : ISubject
{
private ISubject _iSubject = new RealSubject();
public void DoSomethingLong()
{
try
{
Console.WriteLine("prepare DoSomethingLong");
_iSubject.DoSomethingLong();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public List<string> GetSomethingLong()
{
try
{
Console.WriteLine("prepare GetSomethingLong");
List<string> result = new List<string>();
result = _iSubject.GetSomethingLong();
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
}
单例代理,将原本不具备单例的类使用代理模式增加单例。在实例化ISubject类时使用静态关键字static
namespace ProxyPattern_代理模式
{
public class ProxySubject : ISubject
{
private static ISubject _iSubject = new RealSubject();
public void DoSomethingLong()
{
try
{
Console.WriteLine("prepare DoSomethingLong");
_iSubject.DoSomethingLong();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public List<string> GetSomethingLong()
{
try
{
Console.WriteLine("prepare GetSomethingLong");
List<string> result = new List<string>();
result = _iSubject.GetSomethingLong();
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
}
缓存代理,第一次请求得到的结果找个地方存起来,下次直接用,以节约时间。封装一个第三方缓存,代理查询时,优先缓存。
namespace ProxyPattern_代理模式
{
public class CustomCache
{
/// <summary>
/// 第三方存储---保证数据不丢失--可以放进来--可以获取---缓存
/// </summary>
private static Dictionary<string, object> CustomCacheDictionary = new Dictionary<string, object>();
public static void Add(string key, object oValue)
{
CustomCacheDictionary.Add(key, oValue);
}
public static T GetT<T>(string key)
{
return (T)CustomCacheDictionary[key];
}
public static bool Exists(string key)
{
return CustomCacheDictionary.ContainsKey(key);
}
}
}
namespace ProxyPattern_代理模式
{
public class ProxySubject : ISubject
{
private static ISubject _iSubject = new RealSubject();
public void DoSomethingLong()
{
try
{
Console.WriteLine("prepare DoSomethingLong");
_iSubject.DoSomethingLong();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public List<string> GetSomethingLong()
{
try
{
Console.WriteLine("prepare GetSomethingLong");
string key = $"{nameof(ProxySubject)}_{nameof(GetSomethingLong)}";
List<string> result = new List<string>();
//在缓存中进行查询
if (!CustomCache.Exists(key))
{
result = _iSubject.GetSomethingLong();
CustomCache.Add(key, result);
}
else
{
result = CustomCache.GetT<List<string>>(key);
}
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
}
延迟代理,在浏览网页时,通常优先加载客户能看的界面,看不到的可以先不加载,待客户滑动后再进行加载,以此达到节约资源和效率优化的目的。
public class ProxySubject : ISubject
{
private static ISubject _iSubject = null;// new RealSubject();
private void Init()
{
_iSubject = new RealSubject();//把一开始就构造对象 延迟到 调用Init才会初始化
}
public void DoSomethingLong()
{
try
{
Console.WriteLine("prepare DoSomethingLong");
//查询实例是否为空
if (_iSubject == null)
{
this.Init();
}
_iSubject.DoSomethingLong();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public List<string> GetSomethingLong()
{
try
{
Console.WriteLine("prepare GetSomethingLong");
//查询实例是否为空
if (_iSubject == null)
{
this.Init();
}
string key = $"{nameof(ProxySubject)}_{nameof(GetSomethingLong)}";
List<string> result = new List<string>();
//在缓存中进行查询
if (!CustomCache.Exists(key))
{
result = _iSubject.GetSomethingLong();
CustomCache.Add(key, result);
}
else
{
result = CustomCache.GetT<List<string>>(key);
}
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
}
权限代理,在执行操作前需要查明操作人是否具有该操作权限时可以使用代理模式增加权限管控
namespace ProxyPattern_代理模式
{
public class ProxySubject : ISubject
{
private static ISubject _iSubject = null;// new RealSubject();
private void Init()
{
_iSubject = new RealSubject();//把一开始就构造对象 延迟到 调用Init才会初始化
}
public void DoSomethingLong()
{
try
{
//权限检查
object user = CallContext.GetData("CurrentUser");
if (user == null)
{
throw new Exception("没有权限访问");
}
Console.WriteLine("prepare DoSomethingLong");
//查询实例是否为空
if (_iSubject == null)
{
this.Init();
}
_iSubject.DoSomethingLong();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public List<string> GetSomethingLong()
{
try
{
//权限检查
object user = CallContext.GetData("CurrentUser");
if (user == null)
{
throw new Exception("没有权限访问");
}
Console.WriteLine("prepare GetSomethingLong");
//查询实例是否为空
if (_iSubject == null)
{
this.Init();
}
string key = $"{nameof(ProxySubject)}_{nameof(GetSomethingLong)}";
List<string> result = new List<string>();
//在缓存中进行查询
if (!CustomCache.Exists(key))
{
result = _iSubject.GetSomethingLong();
CustomCache.Add(key, result);
}
else
{
result = CustomCache.GetT<List<string>>(key);
}
return result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return null;
}
}
}
}
namespace ProxyPattern_代理模式
{
internal class Program
{
static void Main(string[] args)
{
{
//ISubject subject = new RealSubject();
//subject.GetSomethingLong();
//subject.DoSomethingLong();
////输出结果
////RealSubject被构造。。。
////GetSomethingLong
////DoSomethingLong
}
{
//ISubject subject = new ProxySubject();
//subject.GetSomethingLong();
//subject.DoSomethingLong();
////输出结果
////RealSubject被构造。。。
////prepare GetSomethingLong
////GetSomethingLong
////prepare DoSomethingLong
////DoSomethingLong
}
{
ISubject subject = new ProxySubject();
subject.GetSomethingLong();
CallContext.SetData("CurrentUser", "小明");
subject.GetSomethingLong();
//输出结果
//没有权限访问
//prepare GetSomethingLong
//RealSubject被构造。。。
//GetSomethingLong
}
Console.Read();
}
}
}
代理模式在需要控制对某个对象的访问时非常有用。通过代理对象,可以添加额外的逻辑或控制访问权限,而无需修改真实对象的代码。代理模式还可以实现延迟加载,在需要时才真正创建和初始化真实对象,提升系统性能。
代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理,以控制对这个对象的访问。代理模式具有以下优点和缺点:
优点:
-
隐藏真实对象:代理模式可以隐藏真实对象的具体实现细节,客户端只需要与代理对象进行交互,无需直接访问真实对象。这样可以提高系统的安全性和保护真实对象的隐私。
-
控制访问权限:代理模式可以控制对真实对象的访问权限。代理对象可以限制客户端的访问,并在必要时验证客户端的请求,从而增加了对真实对象的访问控制。
-
延迟加载:代理模式可以实现对象的延迟加载。当真实对象的创建和初始化比较耗时时,可以通过代理模式推迟其创建和初始化的时机,节省系统资源,并提高系统的响应速度。
-
增加额外功能:代理模式可以在不改变真实对象的情况下,为其增加额外的功能。代理对象可以在调用真实对象的前后进行一些处理,如记录日志、缓存数据等。
缺点:
-
增加复杂度:引入代理对象会增加系统的复杂度。代理模式需要维护代理对象和真实对象之间的关系,可能增加代码的数量和复杂性。
-
代理对象的存在可能引起性能下降:由于代理模式需要额外的处理和判断,可能会导致系统的性能下降。如果代理对象没有实质性的功能扩展,但却需要进行额外的处理,可能会降低系统的效率。
-
增加网络开销:当代理对象和真实对象不在同一进程或物理节点上时,通过代理访问真实对象可能会引入网络开销,影响系统的性能。
需要根据具体的应用场景和需求来评估使用代理模式的利弊。代理模式适用于需要控制对真实对象的访问权限、延迟加载对象或增加额外功能的情况。而对于简单的对象访问,可能不需要引入代理模式。通过权衡其优点和缺点,可以选择是否使用代理模式。