我有一个对象,它只在构造(快速)时使用准系统数据初始化自己,并在首次访问时将其自身加载为真实(慢)。我的想法是,我在启动时创建了很多这些准系统对象并将它们散列到地图中,然后在第一次单独访问时完全加载每个对象。问题是我无法保证客户端将如何与此对象进行交互,可能会调用多个公共方法。
是否有良好的模式来支持这种情况?显而易见的(以及我当前的)解决方案是使用内部bool跟踪状态,在每个可能调用的函数中检查该bool,并以此方式加载。但这需要在所有公共函数中复制该行为的代码,并且容易出错。
我可以想象一个单一的入口点方法,然后基于客户端请求类型等来区分行为,但在我开始考虑沿着这条道路走之前我想看看是否有一个普遍接受的方法/我可能不知道的模式。我在C#中这样做,但我们非常感激。
答案 0 :(得分:1)
如果我理解您想要实现的目标,那么您正在寻找代理设计模式,更具体地说,是一个虚拟代理。
请参阅http://www.dofactory.com/net/proxy-design-pattern
一个小例子可能是:
public abstract class IObjectProvider
{
public abstract IObjectProvider Object{get;}
public abstract void doStuff();
}
public class RealObject : IObjectProvider
{
public RealObject()
{
//Do very complicated and time taking stuff;
}
public override IObjectProvider Object
{
get { return this; }
}
public override void doStuff()
{
//do this stuff that these objects normally do
}
}
public class ObjectProxy : IObjectProvider
{
private IObjectProvider objectInstance = null;
public override IObjectProvider Object
{
get
{
if (objectInstance == null)
objectInstance = new RealObject();
return objectInstance;
}
}
public override void doStuff()
{
if(objectInstance!=null)
objectInstance.doStuff();
}
}
public class SkeletonClass
{
public IObjectProvider Proxy1 = new ObjectProxy();
public IObjectProvider Proxy2 = new ObjectProxy();
}
static void Main(String[] args)
{
//Objects Not Loaded
SkeletonClass skeleton = new SkeletonClass();
//Proxy1 loads object1 on demand
skeleton.Proxy1.Object.doStuff();
//Proxy2 not loaded object2 until someone needs it
}
答案 1 :(得分:1)
这是动态代理方法的一个例子。
using System;
using System.Diagnostics;
using Castle.DynamicProxy; //Remember to include a reference, too. It's nugettable package is Castle.Core
namespace ConsoleApp
{
public class ActualClass
{
//Have static instances of two below for performance
private static ProxyGenerator pg = new ProxyGenerator();
private static ActualClassInterceptor interceptor = new ActualClassInterceptor();
//This is how we get ActualClass items that are wrapped in the Dynamic Proxy
public static ActualClass getActualClassInstance()
{
ActualClass instance = new ActualClass();
return pg.CreateClassProxyWithTarget<ActualClass>(instance, interceptor);
}
//Tracking whether init has been called
private bool initialized = false;
//Will be used as evidence of true initialization, i.e. no longer null
private int? someValue = null;
public void Initialize()
{
if (!initialized)
{
//do some initialization here.
someValue = -1; //Will only get set to non-null if we've run this line.
initialized = true;
}
}
//Any methods you want to intercept need to be virtual!
public virtual int replaceValue(int value)
{
//below will blow up, if someValue has not been set to -1 via Initialize();
int oldValue = someValue.Value;
someValue = value;
return oldValue;
}
//block off constructor from public to enforce use of getActualClassInstance
protected ActualClass() { }
}
public class ActualClassInterceptor : ActualClass, IInterceptor
{
public void Intercept(IInvocation invocation)
{
//Call initialize before proceeding to call the intercepted method
//Worth noting that this is the only place we actually call Initialize()
((ActualClass)invocation.InvocationTarget).Initialize();
invocation.Proceed();
}
}
class Program
{
static void Main(string[] args)
{
ActualClass instance1 = ActualClass.getActualClassInstance();
ActualClass instance2 = ActualClass.getActualClassInstance();
int x1 = instance1.replaceValue(41);
int x2 = instance2.replaceValue(42);
int y1 = instance1.replaceValue(82);
Debug.Assert(y1 == 41);
int y2 = instance2.replaceValue(84);
Debug.Assert(y2 == 42);
var read = Console.ReadKey();
}
}
}