.NET Framework中的构造函数与工厂版

时间:2009-12-08 20:10:21

标签: .net design-patterns factory-pattern

下面是一篇关于.net框架模式使用的文章。我不确定我是否理解下面摘录中的粗体部分。是否暗示如果更改创建对象的细节,您(可能)更改构造函数参数?

  

您在框架中有很多案例   可以获取结构或类的新实例   没有自己调用它的构造函数。该   System.Convert类包含一个静态主机   像这样工作的方法。转换整数   例如,你可以调用一个布尔值   Convert.ToBoolean并传入整数。该   此方法调用的返回值是一个新的布尔值   如果整数不为零,则设置为“true”   否则“假”。 Convert类创建   具有正确值的布尔值。其他类型   转换方法类似。解析   Int32和Double上的方法返回新实例   那些对象设置为适当的值   只给一个字符串。

     

这种创建新对象实例的策略是   称为工厂模式。而不是调用   对象的构造函数,你可以问对象   工厂为您创建实例。那样,   工厂类可以隐藏复杂性   对象创建(比如如何解析Double   一个字符串)。如果你想改变细节   创建对象,你只需要改变   工厂本身; 你不必每次都改变   构造函数所在代码中的单个位置   调用。

来自:http://msdn.microsoft.com/en-us/magazine/cc188707.aspx

4 个答案:

答案 0 :(得分:11)

我实际上认为他们提供的例子不一定是很好的例子。

当您构建类时,Factory模式在.NET中变得更有用。例如,查看WebRequest class

这个类通常通过调用:

来实例化
WebRequest request = WebRequest.Create(url);

WebRequest.Create方法使用Factory模式。根据URL的类型,它将创建WebRequest的不同类型(子类)。例如,如果您传递http://个网址,则实际上会创建HttpWebRequest个实例 - ftp://网址会创建FtpWebRequest

通过在此处使用Factory模式,可以在以后添加更多URL类型而无需更改客户端上的任何代码 - 您只需传入不同的URL(作为字符串),然后获取新对象。

答案 1 :(得分:2)

工厂的整个想法似乎有所不同。这不仅仅是隐藏实现的复杂性,而是关于控制的反转(IoC)。

  • 不要创建自己的SenderReceiver个对象,而是让MessageFactory对象负责创建它们。
  • 让我们假设最初我们实现了TcpMessageFactoryMessageFactory后代)创建TcpSenderTcpReceiver个对象。所以现在我们的应用程序适用于TCP。
  • 稍后我们发现UDP更快。我们实施了UdpSenderUdpReciever。此外,我们还实施了UdpMessageFactoryMessageFactory后代)
  • 现在我们可以允许用户选择要使用的协议。基于此,我们创建工厂对象(TcpMessageFactoryUdpMessageFactory)并在我们的应用程序中进一步使用它。

在此示例中,MessageFactory.CreateSenderMessageFactory.CreateReciever必须是抽象方法; Sender&的方法Reciever形成他们的公共API(合同)也必须是抽象的。

Btw,最初工厂主要用于创建对象:想象C ++库(DLL)必须允许为主.exe创建一组自己的类型。在不同模块之间传递实例几乎是不可能的,因为它们的结构取决于特定的编译器。但是可以通过接口。所以这样的DLL应该:

  • 导出返回工厂界面的函数,例如IDllTypeFactory
  • 实现它的对象必须在调用其IDllTypeXxx方法时返回CreateXxx个对象。这些IDllTypeXxx实际上是由我们最初计划导出的类型实现的。

但是如您所知,.NET采用统一的汇编格式,可以在不同模块之间传递对象。而且,反射允许创建一个你根本不知道的类型。因此,很少使用.NET中的工厂。

答案 2 :(得分:1)

工厂模式是我在我的程序中使用最多的模式。在某些情况下它可能非常有用,但使用它时一定要小心。 如果您的工厂看起来像构造函数重载,那么它可能应该是构造函数重载。 MSDN文章给出的示例并不好。事实上,我很久以来一直认为像Int,String等对象不会考虑彼此的重载,因为它们是结构而不是类,并且通常情况下, struct constructors不应该抛出异常(例如,如果你可以将“hello world”提供给int)就会发生异常。但我认为。

当然,网络上有很多地方可以找到更好的解释,说明何时使用工厂模式及其好处。 Reed给出的示例是最好的并遵循我使用Factories的规则:当我有一个类层次结构或许多实现某个接口的类时,我使用工厂,我想构建其中一个对象但是接收一个对象超类/接口而不是对象本身。这样,调用工厂的对象不必担心实现细节。它知道它正在期待一个特定类的对象,即使它是演员也是如此。

在我正在构建的当前应用程序(程序生成器)中,我需要解析数据表SQL定义。我使用家庭酿造解析器来做到这一点。每次解析器遇到变量(“IDENTIFIER VARIABLE-TYPE”)时,我都会调用一个工厂并将字符串传递给它。然后工厂检查变量类型子串并返回 SqlVariable ,实际上可能是 IntegerSqlVariable CharSqlVariable

主解析器对象不知道它得到了什么变量。它将SqlVariable推送到列表并读取下一行。当然,我可以有一个类来处理所有变量类型;我个人选择不这样做。

答案 3 :(得分:0)

是的,您可以使用构造函数重载来更改构造函数,而不必更改源代码中的每个区域,但如果您不是非常小心,这将很快导致数量庞大的构造函数。

我认为本文的一般概念是隐藏实现,而不是必须阻止大量构造函数重载以便考虑构造函数的更改。作为对象的想法不应该知道它是如何构建的。

在给出的示例中,您不希望阻塞Int类如何从字符串或double变为int,因此您创建Factory,其唯一的职责是从Y参数创建X对象。

我肯定会建议将Head First Design Patterns一书作为学习设计模式的好介绍。这些示例是基于Java的,但无论您使用何种语言,它们背后的逻辑都适用。