C#泛型和抽象工厂模式 - 或某种类似的做法

时间:2010-07-15 22:08:56

标签: c# generics factory-pattern

我正在尝试为我的应用程序编写一种可扩展的数据层其中一个“存储库”是我的抽象存储类的内存实现

public abstract class Store<TEntity, TIdentifier> : IStore<TEntity, TIdentifier>
        where TEntity : StorableEntity<TIdentifier>        
{
  //abstract methods here

  public abstract TIdentifier GetUniqueIdentifier();
}

“StorableEntity”抽象类是:

public abstract class StorableEntity<TIdentifier>
{
    public TIdentifier ID { get; set; }
}

我有一个名为“InMemoryStore”的具体商店类,如下所示:

public class InMemoryStore<T, U> : Store<T, U>
    where T : StorableEntity<U>
{
    protected static Dictionary<U, T> store = new Dictionary<U, T>();

    public override U GetUniqueIdentifier()
    {
    // call relevant "generator" here - SOMETHING LIKE THIS??
    // var generator = GetGeneratorSomehow(U);
    // return generator.Create();
    }
}

现在,这里的“U”类型可以是string,int,Guid等...... (大多数时候它可能是int)

我的想法是创建像IUIDGenerator这样的东西:

public interface IUIDGenerator<T>
{
    T Create(ICollection<T> collection);
}

在上面的“InMemoryStore”中,我将创建一个IUIDGenerator的实例,传入商店dictionarys密钥集合,并调用“Create”方法返回所需类型的唯一标识符。

例如,我可以有一个像这样的IntUIDGenerator类(它将作为一种增量数字生成器,基于字典键中已有的数字)

public class IntUIDGenerator : IUIDGenerator<int>
{
    public int Create(ICollection<int> collection)
    {
        var result = collection.Max() + 1;
        if (collection.Contains(result))
            return result;

        throw new NotUniqueException();
    }
}

实际问题: 我需要做的是,在InMemoryStore中,识别U的类型(标识符的类型),并能够动态选择IUIDGenerator所需的具体实现 - 我该怎么做?

我想过有一种类工厂模式 - 将所有可用的UIDGenerator加载到字典中......但它们都可以有不同的类型?

有更好的解决方法吗?

此外,我知道我的问题的标题可能有点偏离 - 如果有人有更好的建议,请随时发表评论,我会改变它。

4 个答案:

答案 0 :(得分:2)

您可以使用IoC框架,例如Unity,Castle,Ninject等。然后,您可以使用以下内容配置容器:

_container = new UnityContainer();
_container.RegisterType<IUIDGenerator<int>, IntUIDGenerator);
_container.RegisterType<IUIDGenerator<Guid>, GuidUIDGenerator);

然后在你的课堂上你会得到以下内容:

public override U GetUniqueIdentifier()
{
    var generator = _container.Resolve<IUIDGenerator<U>>();
    return generator.Create();
}

答案 1 :(得分:0)

我认为你必须使用至少一个演员表。如果您将所有生成器存储在地图中,如

Map<Type, object> generators;

你可以使用

class InMemoryStore<T,U> {
  public override U GetUniqueIdentifier() {
    var generator = generators[typeof(U)] as IUIDGenerator<U>;
    return generator.Create(collection);
  }
}

当然,我省略了所有类型的验证码:)(比如检查,如果类型U的生成器在地图中等...)

答案 2 :(得分:0)

简答:使用dependency injection,让你的DI容器为你处理。

答案 3 :(得分:0)

您可以为生成器添加其他泛型类型参数,例如

public class InMemoryStore<T, U, V> : Store<T, U>
    where T : StorableEntity<U>
    where V : IUIDGenerator<U>, new() {

    public override U GetUniqueIdentifier()
    {
        return (V)(Activator.CreateInstance<V>()).Create();
    }
}