【问题标题】:Is the StaticFactory in codecampserver a well known pattern?codecampserver 中的 StaticFactory 是众所周知的模式吗?
【发布时间】:2010-04-12 17:03:19
【问题描述】:

【问题讨论】:

  • 我会在 CreateFoo<T>() 方法中使用开关而不是 if 链。

标签: c# generics abstract-factory


【解决方案1】:

编辑:请注意,此答案是在编辑完全更改问题之前给出的。因此,它现在指的是最初陈述的问题中仅存在的事物。请原谅所有“悬空指针”。 :-)


简答:

使用您发布的代码,我看不到转换为 IFoo<T> 的替代方法。如果你不这样做,编译器会发出警告(至少在我的机器上)。

更详细的答案:

你的代码真的必须这样吗?更具体地说,您首先需要相关演员吗?

我假设你会或多或少这样调用你的工厂方法:

var stringFoo = FooFactory.CreateFoo<string>();

您必须显式提供模板参数(在这种情况下为string),因为它不能从任何方法参数派生(在这种情况下,因为实际上根本没有任何参数)。显然,工厂方法会返回一个IFoo&lt;string&gt;

现在,由于您必须在运行时明确指定类型,您也可以这样写:

var stringFoo = StringFoo.Create();

因此在StringFoo 中有一个工厂方法,就像这样,无条件地做显而易见的事情:

public class StringFoo : IFoo<string>
{
    ...

    public static StringFoo Create()  // or alternatively, return an IFoo<string>
    {
        return new StringFoo();
    }
}

通过将此模式也应用于其他IFoo&lt;T&gt; 实现,这将为您节省if 链或switch 块内FooFactory.CreateFoo&lt;T&gt;,使您的代码更容易,并摆脱了强制转换的必要性(您担心)。

不要误会我的意思,我知道支持多个对象类型的工厂方法在某些情况下很有用;但在你的情况下,它似乎带来的麻烦多于它的价值。


附注:您可能会发现某些 IoC 容器的一个方面很有趣。它们通常需要配置,这包括为抽象接口注册具体类型(即实现类)的过程;例如(这里使用Autofac):

var builder = new ContainerBuilder();
builder.RegisterType<StringFoo>().As<IFoo<string>>();

然后,你可以请求一个抽象类型的对象实例:

using (var container = builder.Build())
{
    var stringFoo = container.Resolve<IFoo<string>>();
    ...
}

Resolve 方法是有趣的部分。您为它提供一个抽象类型,并使用注册的类型,它将返回一个StringFoo 类型的具体对象。看看它,如果它对你来说听起来不是矫枉过正! :-)

【讨论】:

  • @Merritt,不用担心。毕竟,我们不都是来学习的吗?我不介意写下所有这些,因为我觉得我也可以从写作/解释中获益良多。
【解决方案2】:

你能描述一下你用这个机制解决的问题吗?很可能有更清晰的方法来处理它。

编辑

是的,代码有异味。您已经为任何类型留出了空间,除非您随后将其限制为单一类型,并生成运行时异常。在这种情况下为什么要有类型参数?

【讨论】:

  • 不,我不是。我不理解提供通用接口但最终只创建一种特定具体类型的抽象工厂的用处。您所描述的是您尚未描述的问题的解决方案。告诉我们那个问题是什么,而不是你先入为主的想法来解决它,我们将能够更好地帮助你。
  • 真空中的技术通常会导致寻找问题的解决方案。如果不定义该机制所解决的情况,您就没有可以做出价值判断的标准。如果您的问题更多的是确定这种方法是否是解决 some 问题的可行解决方案,那就不同了。我个人不认为通用工厂不是通用的,并且在使用时会导致运行时异常。这就像制造一辆除非你去超市才会启动的汽车。
【解决方案3】:

你可以试试这样的……

public static class FooFactory
{
    private static readonly Dictionary<Type, Type> FooTypesLookup;

    static FooFactory()
    {
        FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes()
                          let fooInterface =
                            type.GetInterfaces().FirstOrDefault(
                                x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>))
                          where fooInterface != null
                          let firstTypeArgument = fooInterface.GetGenericArguments().First()
                          select new { Type = type, TypeArgument = firstTypeArgument })
            .ToDictionary(x => x.TypeArgument, x => x.Type);
    }

    public static IFoo<T> CreateFoo<T>()
    {
        var genericArgumentType = typeof(T);
        Type closedFooType;
        return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType)
                ? (IFoo<T>) Activator.CreateInstance(closedFooType)
                : null;
    }
}

或者更好的是,引入您最喜欢的 IoC 容器(Windsor、结构映射等)并在其中注册所有实现 IFoo 的类型,然后在需要时解析它们以代替 Activator.CreateInstance 调用。

【讨论】:

  • 我的目标是不使用 Activator.CreateInstance()。
猜你喜欢
  • 2010-12-27
  • 2011-02-07
  • 1970-01-01
  • 2010-10-13
  • 2023-02-21
  • 2021-10-25
  • 2020-11-29
  • 2011-01-07
  • 1970-01-01
相关资源
最近更新 更多