这是Factory Method创建模式吗?

时间:2009-04-30 13:30:44

标签: c# design-patterns factory-pattern creation static-factory

我一直在使用工厂方法创建模式一段时间。我刚刚被告知这个:

public static class ScheduleTypeFactory
{
    public static IScheduleItem GetScheduleItem(ScheduleTypeEnum scheduleType)
    {
        IScheduleItem scheduleItem = null;

        switch (scheduleType)
        {
            case ScheduleTypeEnum.CableOnDemandScheduleTypeID:
                {
                    scheduleItem = new VODScheduleItem();
                    break;
                }
            case ScheduleTypeEnum.BroadbandScheduleTypeID:
                {
                    scheduleItem = new VODScheduleItem();
                    break;
                }
            case ScheduleTypeEnum.LinearCableScheduleTypeID:
                {
                    scheduleItem = new LinearScheduleItem();
                    break;
                }
            case ScheduleTypeEnum.MobileLinearScheduleTypeID:
                {
                    scheduleItem = new LinearScheduleItem();
                    break;
                }
        }

        return scheduleItem;
    }
}

不是我的“技术”主管的工厂方法创建模式,而没有告诉我为什么或给我她的解释。我很友好地要求解释,她告诉我她没有时间。我被告知要重命名它。如果我错了,那么毫无疑问我会接受我已经错误地实施了多年。这是你如何实现工厂方法创建模式?提前谢谢。

20 个答案:

答案 0 :(得分:31)

我同意将该方法称为“工厂方法”,尽管该设计并非严格意义上的“工厂方法模式”。
这是一个关键点(来自维基百科):

  

... Factory方法允许类将实例化推迟到子类。“

由于您的类是静态的并且方法是静态的(因此是非虚拟的),因此不存在“延迟”。

从概念上讲,另请注意,此实现虽然提供了封装,但并未解除/延迟任何决策。

话虽如此,同样的维基百科文章确实将此架构呈现为“工厂方法模式”的变体

摘要摘要:在我看来,这个代码段不是“工厂方法OO设计模式”的正确的实现,因为它不满足“类延迟实例化到子类”。虽然,我个人可以自由地将此解决方案称为“工厂方法”。

要使其成为真正的工厂方法模式,您需要允许子类重写该方法。即工厂类(ScheduleTypeFactory)需要是可扩展的(即非静态的),而GetScheduleItem需要是虚拟的。

答案 1 :(得分:29)

当然看起来像我的工厂模式。我认为你的实施没有任何问题。

来自Factory method pattern

  

工厂模式的本质是   “定义用于创建的界面   一个对象,但是让子类   决定实例化哪个类。该   工厂方法让课程推迟   实例化到子类。“

这正是你在做的事情。

作为旁注:一个好的经验法则是,每当有人告诉你某事并且不能或不愿意为他们的陈述提供理由时,他们很有可能完全没有资格作出陈述。

答案 2 :(得分:14)

是的,这是工厂模式。我唯一的评论是你无法为你没有专门处理的枚举值而无声地失败。这可能是预期的,但我喜欢将以下内容添加到像

这样的语句的末尾
default:
  throw new InvalidOperationException("Invalid Enum Value");

答案 3 :(得分:12)

您的代码片段是Head First Design Patterns中称为“简单工厂”的代码片段(第117页) 与Factory Method Pattern的主要区别在于 ConcreteCreator (比较右上角的图表),这是一个简单的类。
在“真实模式”中,工厂类是抽象的工厂类。所以,还有一个抽象层次。但是,对于许多用例,简单工厂就足够了。

简单工厂 Simple Factory http://yuml.me/7221a4c9 工厂方法模式 Factory Method Pattern http://yuml.me/3d22eb4e

答案 4 :(得分:8)

你的领导是正确的(对不起格式化,但这个答案需要一些,以便在主线之间看到表明领先是白痴):GOF都没有book and Head First这是一种工厂方法。

GoF:

  

“定义用于创建的界面   对象,但让子类决定   要实例化的类。厂   方法让一个类推迟   实例化到子类。“

在您的示例中,不是决定的子类。

这些年来你有没有错误地实现它?不,你刚刚没有实现工厂模式,但有时也称为“简单工厂模式”,可能已经完成了这项工作。

答案 5 :(得分:8)

我认为它传统上被称为简单的工厂模式,以区别于“真正的”Abstract Factory模式。可能是因为您没有遵守某种内部命名惯例。她真的应该解释一下自己。

答案 6 :(得分:5)

对我来说看起来像一个(基本)工厂......在许多工厂中,实现更复杂(可能涉及在运行时解析的类型),但这不是(AFAIK)的要求。我要添加的唯一其他批评是将案例结合起来,如果你不认识那种类型,就做一些更具戏剧性的事情......

答案 7 :(得分:5)

我很惊讶这么多人说这是工厂模式。 (所以很可能我认为这是错的,所以请让我知道。)

在我看来,你所拥有的只是设计的一部分。如果您从客户端调用它,它被称为“简单”工厂,但它并不是真正的设计模式。 (别误会我的意思,我一直这样做。)

工厂设计模式将声明您的工厂继承/实现抽象工厂/工厂接口。

然后,在需要使用工厂(客户端)的类中,将工厂类型设置为抽象/接口,创建具体工厂: 即 - > IFactory factory = new ConcreteFactory();

然后具体工厂将创建您的IScheduleItem(将其留给工厂以实际创建具体类型)。

最后,我认为重点是疏松耦合。虽然一个“简单”的工厂松散地将产品的结构与客户结合在一起,但它并没有使工厂脱钩。工厂模式也使工厂脱钩。

然后,它还早,我没有喝咖啡,而且我有一种讨厌的习惯,即发布绝对可怕的回答,错过了问题的全部内容。

答案 8 :(得分:4)

这是工厂模式,但它不一定是最易维护的变体。 更易于维护的变体会在ScheduleTypeEnum值与IScheduleItem的实际具体子类型之间维护某种全局映射 - 这样,您可以替换switch语句查找地图。

为什么它更易于维护?因为子类作者可以在他们派生类的站点上向地图添加对,而不是GetScheduleItem()工厂功能本身。因此,后者永远不需要更新;它不断更新。

在C ++中,您可以使用全局std::map执行此操作 - 对于每个具体的子类,子类的作者添加一个虚拟全局变量,该变量实际上只是在其构造函数中注册类(通过添加到映射) ,在程序启动时运行。我确信在C#中有一种方便的方法可以做同样的事情。

(C ++大师Herb Sutter有entertaining description here,但它相当C ++重。)

答案 9 :(得分:4)

对我来说看起来像工厂模式。告诉你的技术主管,你没有时间解释她错的原因。

答案 10 :(得分:4)

嗯,维基百科说it is是一种工厂方法:

public class ImageReaderFactory 
{
    public static ImageReader getImageReader( InputStream is ) 
    {
        int imageType = figureOutImageType( is );

        switch( imageType ) 
        {
            case ImageReaderFactory.GIF:
                return new GifReader( is );
            case ImageReaderFactory.JPEG:
                return new JpegReader( is );
            // etc.
        }
    }
}

答案 11 :(得分:2)

它确实是一个“工厂”,因为你有一个方法可以根据某种逻辑返回IScheduleItem的特定实例;但是,鉴于您使用的是switch语句,它可能不是最佳实现或最易维护的。

答案 12 :(得分:0)

技术主管可能会想到的是,Factory模式是替换同一对象中的构造函数,而不是返回子类,或者可能只返回超类中的子类,而不是来自不相关的对象。这是错的,但这可能是想法。

维基百科列出您的模式作为一个例子表明它是正确的工厂模式。定义模式是为了提供通用解决方案的通用语言,所以很明显,如果维基百科以此为例,它就是通用语言的一部分。关于“工厂模式”在某种抽象意义上的含义的学术争论忽略了模式的重点。

答案 13 :(得分:0)

立即取回电源!只需从措辞中删除“类型”即可。 ScheduleFactory FTW。等等,这是'Scheduleles'或'ScheduleItems'的工厂吗?如果它是scheduleitems,那么工厂应该被称为'ScheduleItemFactory'。富有表现力!!!

答案 14 :(得分:0)

这是工厂方法模式,至少根据维基百科: http://en.wikipedia.org/wiki/Factory_method_pattern

答案 15 :(得分:0)

对我来说看起来像一个基本的工厂模式。我很想知道为什么你的技术主管不认为这是一种模式。

我也很失望她不会花时间解释事情。在团队成为技术领导之前,花点时间来解释你的决定是很有意义的。

答案 16 :(得分:0)

我从模式和练习课中学到的工厂模式的最简单的解释是,如果你依赖另一个类来创建你的类的实例,那么你就是在使用工厂模式。

当然,通常你想通过使你的类抽象或接口来添加一个间接层。

这是非常简化的视图,但无论哪种方式,您都在使用工厂模式。

答案 17 :(得分:0)

是的,那是工厂模式好的。你的技术领先是错误的。

答案 18 :(得分:0)

您的技术人员正确地重命名该方法:

public static IScheduleItem GetScheduleItem(ScheduleTypeEnum scheduleType)

该方法的作用不是为了获得某些东西,而是创建的东西。  你如何决定应该创建哪个scheduleType?似乎逻辑应该  封装不是类型的开关。

为什么班上的静态呢?你在哪里使用它?

public class ScheduleTypeFactory
{
    public static IScheduleItem createScheduleFrom(ScheduleTypeEnum scheduleType)
    {

        switch (scheduleType)
        {
            case ScheduleTypeEnum.CableOnDemandScheduleTypeID:
            case ScheduleTypeEnum.BroadbandScheduleTypeID:
                 return new VODScheduleItem();
             case ScheduleTypeEnum.LinearCableScheduleTypeID:
             case ScheduleTypeEnum.MobileLinearScheduleTypeID:
                    return new LinearScheduleItem();
        }

       raise InvalidSchedule;
    }
}

答案 19 :(得分:-1)

这是一本教科书工厂模式。

有些文章称它为简单工厂模型,但我从未见过“简单”意味着什么标准。

在我的实践中,工厂模式是对应于所需界面的具体类的任何智能创建。

但是为什么要在命名方法上与你的技术领先。重命名,继续你的生活。