【问题标题】:Abstract factory pattern instead of generics - how?抽象工厂模式而不是泛型 - 如何?
【发布时间】:2017-09-15 08:04:31
【问题描述】:

我有一个通用接口:

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() 方法必须返回ResultDetailedResultReader.ReadResults() 必须返回DetailedResult

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

【问题讨论】:

  • 您能详细说明一下吗?你有什么问题?
  • 我需要一个工厂,这样我就可以创建不同的IReader 对象-Ireader 的每个具体实现都有特定的方法返回类型。
  • 这一切都取决于你的工厂会是什么样子。如果您希望它完全通用,那么您需要考虑很多问题。但是,如果您想预定义哪种类型将返回什么阅读器,那么您真正需要的是检查IReader&lt;T&gt; GetReader&lt;T&gt;() where T : Result 会更容易。但是,在目前的状态下,这个问题确实很广泛。
  • 很难更清楚地描述它——现在我所展示的都是基于泛型的——但我想摆脱它并拥有一个工厂来为我创建一个特定的 @ 实现987654337@ - DefaultResultReader.ReadResults() 总是返回 ResultDetailedResultReader.ReadResults() 总是返回 DetailedReader

标签: c# generics polymorphism factory-pattern


【解决方案1】:

我没有得到你想要的,但我猜你期待以下:

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();
    }
}

【讨论】:

  • 这增加了一个不必要的类。由于您已经在使用接口,我希望您为工厂本身创建一个接口,这几乎抵消了抽象类的意义。 Abstracy Factory 中的 abstract 不需要使用实际的抽象类 - 拥有它,您一无所获。
【解决方案2】:

如果DefaultResultReader&lt;Result&gt; 总是返回IEnumerable&lt;Result&gt;,而DetailedResultReader&lt;DetailedResult&gt; 总是返回IEnumerable&lt;DetailedResult&gt;,我建议创建类

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();
    }
}

【讨论】:

  • 是的,我可以这样做:)
【解决方案3】:

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

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));  
    }
}

要使用它,您只需在与ResultReaderFactory 相同的程序集中创建实现IReader&lt;T&gt; 的类。然后你就可以忘记那个工厂对象,只要你想调用它就可以了:

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

这将在您启动应用程序时读取所有实现IReader&lt;T&gt; 的类型。然后它将所有这些类(已经实例化)打包到List&lt;object&gt;,以便您以后可以使用它们。不过这确实很慢,因为它使用反射和 Linq 来确定要返回哪个 IReader&lt;T&gt; 实现。

try this online

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多