【问题标题】:What is the design pattern in this code?这段代码中的设计模式是什么?
【发布时间】:2011-01-16 00:33:15
【问题描述】:

假设我有一个单例类、工厂类、反射类,它接收一些输入,并返回某个接口的具体实现的新实例。这是什么设计?有没有更好的方法来做我想做的事?

这里有一些代码来说明这一点:

using System;
using System.Collections.Generic;

// static factory class
public static class ArticleFactory 
{
    // given an SKU, store the Type object for an IArticle object
    private static Dictionary<string, Type> articleRegistry = new Dictionary<string, Type>();

    // allow public registration of SKU-to-Type object relationships
    public static bool Register(string sku, Type typeInfo)
    {
        if(!articleRegistry.ContainsKey(sku)) 
        {
            articleRegistry.Add(sku, typeInfo);
            return true;
        }
        return false;
    }

    // given a SKU, give me an instance of the related IArticle object
    public static IArticle NewArticle(string sku)
    {
        if(articleRegistry.ContainsKey(sku))
        {
            // use reflection to invoke the default constructor
            return articleRegistry[sku].GetConstructor(Types.EmptyTypes).Invoke(null) as IArticle;
        }
        return null;
    }
}

// example concrete-implementation of an IArticle
public class Jeans : IArticle 
{
    public decimal GetPrice() {  return SomeDecimal(); }
}

// WHERE DO I CALL THIS LINE? 
ArticleFactory.Register("0929-291", typeof(Jeans)); 

// Later on, if another group needs to write the class for Snowboards, 
// how can they self-register their class, without changing any "Main()"
// or "Page_Init()" function?

【问题讨论】:

  • 我相信这就是 Refactleton 模式。 ;-)

标签: c# design-patterns reflection factory


【解决方案1】:

我认为你在这里所做的基本上是依赖注入(或者控制反转是酷孩子所说的)。看看这些链接:

来自维基百科的解释:http://en.wikipedia.org/wiki/Dependency_Injection

两个 DI .Net 框架:

结构图:http://structuremap.sourceforge.net/QuickStart.htm

温莎城堡:http://www.castleproject.org/container/index.html

【讨论】:

  • 注意:DI 和 IoC 是两个非常不同的概念。它们只是碰巧结合在许多 DI 框架中。
  • 依赖注入听起来比控制反转要酷得多;-)
【解决方案2】:

这只是一种在其实现中碰巧使用反射的工厂模式。不过,与使用反射相比,将工厂类的实例直接放入字典中可能会更有效,尽管这可能需要一些样板代码。

【讨论】:

    【解决方案3】:

    看起来您已经确定了这种模式。这是Factory Method Pattern。或者更确切地说,一个有点半生不熟的实现。一个稍微好一点的方法是首先使它成为一个接口:

    public interface IArticleFactory
    {
        IArticle CreateArticle(string sku);
    }
    

    然后在没有任何反射的情况下实现工厂:

    public class MyArticleFactory
    {
        private Dictionary<string, Func<IArticle>> instantiators =
            new Dictionary<string, Func<Iarticle>>();
    
        public MyArticleFactory()
        {
            Register("Jeans", () => new Jeans());
            Register("Shirt", () => new Shirt());
            // etc.
        }
    
        public IArticle CreateArticle(string sku)
        {
            Func<IArticle> instantiator;
            if (creators.TryGetValue(sku, out instantiator))
                return instantiator();
            throw new UnknownSkuException(sku);
        }
    
        protected void Register(string sku, Func<IArticle> instantiator)
        {
            creators.Add(sku, instantiator);
        }
    }
    

    几个重要的区别:

    • 注册不公开,也不应该公开。注册通常要么驻留在某个配置文件中,要么是私有的。

    • 不要求IArticle 具体类型具有默认的无参数构造函数。这可以很容易地用参数化的构造函数注册文章(只要它知道使用什么参数)。

    • 在重复注册时引发异常。我不喜欢简单地返回false 的想法;如果你尝试两次注册同一个工厂方法,那应该被认为是一个错误。

    • 它不是静态的。您可以用不同的工厂替换这个工厂。您可以对其进行单元测试。

    当然,更好的方法是使用无数现有的 .NET 依赖注入/控制框架反转,例如 NinjectAutoFac

    【讨论】:

    • 谢谢 - 虽然所有答案都指向同一个大方向 (IoC),但您让我知道了如何继续。如此摇滚。
    【解决方案4】:

    我不知道它是否有这样的“名称”,但它看起来像是某种手动服务解析器。我可以看到的问题(遗憾的是,从经验来看)是它实际上是不灵活的,因为:

    • 注册只有一个配置
    • 很难进行单元测试

    如果我在新系统中执行此操作,我个人会查看 IoC 容器; IoC 可以处理这种关系,并免费提供更多功能(生命周期、丰富性、额外设置等),并解决许多相关问题。

    顺便说一句,这样做可能更容易:

    return Activator.CreateInstance(articleRegistry[sku]);
    

    【讨论】:

      猜你喜欢
      • 2019-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-10
      • 2023-03-26
      • 1970-01-01
      相关资源
      最近更新 更多