43

我已经使用工厂方法创建模式有一段时间了。我最近才被告知:

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

不是我的“技术”负责人的工厂方法创建模式,没有告诉我原因或给我她的解释。我恳请解释,她告诉我她没有时间。我被告知只需重命名它。如果我错了,那么我无疑会接受我多年来一直错误地实施这一点。这是您将如何实现工厂方法创建模式的方式吗?提前致谢。

4

20 回答 20

31

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

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

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

从概念上讲,还要注意,这种实现虽然提供了封装,但不会解耦/延迟任何决策。

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

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

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

于 2009-05-01T14:40:53.707 回答
29

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

工厂方法模式

工厂模式的本质是“定义一个用于创建对象的接口,但让子类决定实例化哪个类。工厂方法让一个类将实例化推迟到子类。”

这正是你正在做的。

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

于 2009-04-30T13:32:34.503 回答
14

是的,这是工厂模式。我唯一的评论是,对于您没有专门处理的枚举值,您会默默地失败。这可能是意料之中的,但我喜欢在这样的语句末尾添加以下内容

default:
  throw new InvalidOperationException("Invalid Enum Value");
于 2009-04-30T13:34:00.023 回答
12

您的代码片段在Head First Design Patterns中被称为“简单工厂”(第 117 页)。工厂方法模式
的主要区别是ConcreteCreator(比较右上角的图表),在您的情况下这是一个简单的类。在“真实模式”中,工厂类是带有抽象工厂类的抽象类。因此,还有一个抽象级别。但是,对于许多用例,您的简单工厂就足够了。

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

于 2009-09-13T23:35:38.983 回答
8

您的线索是正确的 (抱歉格式化,但这个答案需要一些它才能在说明线索是白痴的主线之间看到):GOF 书和 Head First 都不是工厂方法。

高飞:

“定义一个用于创建对象的接口,但让子类决定要实例化哪个类。工厂方法让类将实例化推迟到子类。”</p>

在您的示例中,它不是决定.

这些年来,您是否错误地实施了它?不,您只是没有实现工厂模式,但有时被称为“简单工厂模式”,它可能已经很好地完成了这项工作。

于 2009-12-07T11:36:50.320 回答
8

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

于 2009-04-30T13:37:51.637 回答
5

我很惊讶这么多人说这是工厂模式。(所以很可能我想错了,所以请告诉我。)

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

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

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

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

最后,我认为重点在于松散耦合。虽然“简单”工厂将产品的构建与客户松散地耦合在一起,但它并没有将工厂解耦。工厂模式也解耦了工厂。

话又说回来,现在还早,我还没有喝咖啡,而且我有一个讨厌的习惯,即发布绝对可怕的回复,错过了问题的全部要点。

于 2009-05-01T13:05:47.807 回答
5

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

于 2009-04-30T13:34:07.030 回答
4

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

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

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

(C++ 大师 Herb Sutter 在这里有一个有趣的描述,但它相当 C++-heavy。)

于 2009-04-30T14:23:46.783 回答
4

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

于 2009-04-30T14:31:25.860 回答
4

好吧,维基百科说这是一种工厂方法:

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.
        }
    }
}
于 2009-04-30T13:35:25.980 回答
2

IScheduleItem它确实是一个“工厂”,因为您有一个基于某种逻辑返回特定实例的方法;但是,考虑到您使用的是 switch 语句,它可能不是最好的实现或最可维护的。

于 2009-04-30T13:34:53.673 回答
0

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

Wikipedia 将您的模式列为示例这一事实表明它是正确的工厂模式。这些模式被定义为为通用解决方案提供通用语言,因此很明显,如果 Wikipedia 将其作为示例显示,它就是通用语言的一部分。关于抽象意义上的“工厂模式”是什么的学术辩论忽略了模式的重点。

于 2009-04-30T14:02:50.330 回答
0

马上夺回权力!只需从措辞中删除“类型”即可。ScheduleFactory FTW。等等,这是“Schedules”还是“ScheduleItems”的工厂?如果是 scheduleitems,那么工厂应该被称为“ScheduleItemFactory”。表现力!!!

于 2009-04-30T14:23:49.187 回答
0

是的,这就是工厂模式。你的技术主管错了。

于 2009-04-30T13:34:30.333 回答
0

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

我也很失望她不会花时间解释事情。之前在团队中担任过技术主管,花时间解释你的决定是很重要的。

于 2009-04-30T13:36:00.800 回答
0

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

于 2009-04-30T13:36:09.520 回答
0

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

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

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

于 2009-05-01T14:20:34.037 回答
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;
    }
}
于 2010-10-29T04:47:39.213 回答
-1

那是教科书的工厂模式。

一些文本称其为简单工厂模式,但我从未见过任何标准来说明“简单”的含义。

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

但是,为什么要与您的技术负责人争夺命名方法。重新命名,继续你的生活。

于 2009-04-30T15:11:14.347 回答