Lob*_*ity 5 c# generics design-patterns
我正在尝试使用泛型实现身份映射.我的实体地图上有一个抽象类,实体和派生约束.由于我的地图需要能够实例化实体,我的地图也有一个构造函数约束.
但是,为了使映射有用,实体子类不应该能够从客户端代码实例化,这意味着我需要一个内部构造函数而不需要公共构造函数.但这与构造函数约束冲突.
有什么我想念的吗?有没有办法重构这个以获得理想的结果?
下面的代码按原样编译,但理想情况下,Entity的子类的构造函数将是内部的:
public abstract class Entity
{
public int Id { get; protected internal set; }
}
public sealed class Widget : Entity
{
// Client code should not be allowed to instantiate entities.
// But the constraints on EntityMap require that entities have
// a public constructor.
public Widget() { }
}
public sealed class Gadget : Entity
{
public Gadget() { }
}
// The new() constraint is required so that Get() can instantiate Ts.
public class EntityMap<T> where T : Entity, new()
{
private Dictionary<int, T> _entities = new Dictionary<int, T>();
private object _getLock = new object();
public T Get(int id)
{
lock (_getLock)
{
if (!_entities.ContainsKey(id))
_entities.Add(id, new T() { Id = id });
}
return _entities[id];
}
// Client code should not be allowed to instantiate maps.
internal EntityMap() { }
}
// Ideally, the client would only be able to obtain Entity
// references through EntityMaps, which are only accessible
// through the ApplicationMap.
public static class ApplicationMap
{
public static EntityMap<Widget> Widgets = new EntityMap<Widget>();
public static EntityMap<Gadget> Gadgets = new EntityMap<Gadget>();
}
Run Code Online (Sandbox Code Playgroud)
不需要构造函数约束,而是将a传递Func<T>
给map构造函数.这样构造函数可以是内部的,但地图仍然可以有效地调用它:
public class EntityMap<T> where T : Entity
{
private readonly Dictionary<int, T> _entities = new Dictionary<int, T>();
private readonly object _getLock = new object();
private readonly Func<T> _entityGenerator;
public T Get(int id)
{
lock (_getLock)
{
T ret;
if (!_entities.TryGetValue(id, ret))
{
ret = entityGenerator();
newEntity[id] = ret;
ret.Id = id;
}
return ret;
}
}
internal EntityMap(Func<T> entityGenerator)
{
_entityGenerator = entityGenerator;
}
}
Run Code Online (Sandbox Code Playgroud)
然后用以下内容初始化它:
EntityMap<Widget> widgetMap = new EntityMap(() => new Widget());
Run Code Online (Sandbox Code Playgroud)
您可能会Func<int, T>
改为使其成为代理,并使委托负责创建具有正确ID的实体.这样,您可以将您的ID设置为只读,将其作为Entity
构造函数的参数.
(我冒昧地让你的Get
方法更有效率,顺便说一下.)