抽象工厂模式而不是泛型 - 如何?

时间:2017-09-15 08:04:32

标签: c# generics polymorphism factory-pattern

我有一个通用界面:

public interface IReader<T> where T: Result
{
   IEnumerable<T> ReadResults();
}

其中Result是基类,并扩展为DetailedResult

public class Result
{
    // ...
}

public class DetailedResult : Result
{
    // ... ...
}

现在我有两个IReader的具体类型,每个实现返回不同的类型,特定于读者类型:

public class DefaultResultReader<Result> : IReader<Result>
{
    IEnumerable<Result> ReadResults();
}

public class DetailedResultReader<DetailedResult> : IReader<DetailedResult>
{
    IEnumerable<DetailedResult> ReadResults();
}

上面介绍的结构使用泛型。如果可能的话我想摆脱它,并且有一些工厂可以为我创建IReader的具体实现 - DefaultResultReader.ReadResults()方法必须返回Result而{{1}必须返回DetailedResultReader.ReadResults()

我的问题是抽象工厂应该如何寻找这个结构 - 如何设计它以便我可以按要求创建特定的DetailedResult对象?

3 个答案:

答案 0 :(得分:2)

如果DefaultResultReader<Result>将始终返回IEnumerable<Result>,并且DetailedResultReader<DetailedResult>将始终返回IEnumerable<DetailedResult>,我建议您制作课程

public class DefaultResultReader : IReader<Result>
{
    IEnumerable<Result> ReadResults();
}

public class DetailedResultReader : IReader<DetailedResult>
{
    IEnumerable<DetailedResult> ReadResults();
}

然后你有了抽象工厂类

public class ReaderFactory
{
    public IReader<Result> CreateDefaultResultReader()
    {
        return new DefaultResultReader();
    }

    public IReader<DetailedResult> CreateDetailedResultReader()
    {
        return new DetailedResultReader();
    }
}

答案 1 :(得分:2)

我没有得到你想要的东西,但我想你期待以下内容:

public interface IReader<T> where T : Result
{
    IEnumerable<T> ReadResults();
}

public class Result
{
}

public class DetailedResult : Result
{
    // ... ...
}

public class DefaultResultReader : IReader<Result>
{
    public IEnumerable<Result> ReadResults()
    {
        return null;
    }
}

public class DetailedResultReader : IReader<DetailedResult>
{
    public IEnumerable<DetailedResult> ReadResults()
    {
        return null;
    }
}

public abstract class ResultReaderAbsractFactory
{
    public abstract IReader<Result> CreareDefaultResultReader();
    public abstract IReader<DetailedResult> CreareDetailedResultReader();
}

public class ConcreteResultRaderFactory : ResultReaderAbsractFactory
{
    public override IReader<Result> CreareDefaultResultReader()
    {
        return new DefaultResultReader();
    }

    public override IReader<DetailedResult> CreareDetailedResultReader()
    {
        return new DetailedResultReader();
    }
}

答案 2 :(得分:1)

如果您想使其完全通用,则意味着即使您创建新的阅读器类型,也不必扩展此类。你可以简单地做这样的事情:

public static class ResultReaderFactory
{
    public static IEnumerable<T> ReadResults<T>() where T : Result
    {
        IReader<T> reader = GetReader<T>();
        if(reader != null)
        {
            return reader.ReadResults();   
        }
        return null;
    }

    public static IReader<T> GetReader<T>() where T : Result
    {
        // get the first reader implementation from the list
        // that matches the generic definition
        IReader<T> reader = _instances
                            .FirstOrDefault(
                                r => r.GetType()
                                    .GetInterfaces()
                                    .Any(
                                        i => i == typeof(IReader<T>)
                                    )
                            ) as IReader<T>;
        return reader;
    }

    // placeholder for all objects that implement IReader
    static IEnumerable<object> _instances;

    static ResultReaderFactory()
    {
        // register all instances of classes,
        // that implements IReader interface
        _instances = typeof(ResultReaderFactory)
                     .Assembly
                     .GetTypes()
                     .Where(
                         t => t.GetInterfaces()
                             .Any(
                                 i => i.Name
                                     .StartsWith("IReader`1")
                             )
                     )
                     .Select(t => Activator.CreateInstance(t));  
    }
}

要使用此功能,您只需在IReader<T>所在的同一个程序集中创建实现ResultReaderFactory的类。然后你可以忘记那个工厂对象,只需随时调用它:

ResultReaderFactory.GetReader<DetailedResult>();
// or assuming you've created class ExtremalyDetailedResult
// and ExtremalyDetailedResultReader
ResultReaderFactory.GetReader<ExtremalyDetailedResult>();

每当您启动应用程序时,这将读取实现IReader<T>的所有类型。然后它会将所有这些类(已经实例化)打包到List<object>中,以便稍后使用它们。这确实很慢,因为它使用反射和Linq来确定返回哪个IReader<T>实现。

try this online