2

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

在框架中有很多情况,您可以获取结构或类的新实例,而无需自己调用其构造函数。System.Convert 类包含许多像这样工作的静态方法。例如,要将整数转换为布尔值,您可以调用 Convert.ToBoolean 并传入整数。此方法调用的返回值是一个新的布尔值,如果整数非零,则设置为“true”,否则为“false”。Convert 类为您创建具有正确值的布尔值。其他类型转换方法的工作方式类似。Int32 和 Double 上的 Parse 方法返回这些对象的新实例,这些对象设置为仅给定一个字符串的适当值。

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

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

4

4 回答 4

11

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

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

此类通常通过调用来实例化:

WebRequest request = WebRequest.Create(url);

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

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

于 2009-12-08T20:18:06.037 回答
2

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

当然,网络上有很多地方可以找到关于何时使用工厂模式及其好处的更好解释。Reed 给出的示例是最好的示例之一,并且遵循我使用工厂的规则:当我有一个类层次结构或多个实现某个接口的类并且我想构建其中一个对象但接收到一个对象时,我会使用工厂超类/接口而不是对象本身。这样,调用工厂的对象就不必担心实现细节。它知道它期待某个类的对象,这就是它得到的,即使它是一个强制转换。

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

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

于 2009-12-08T20:56:04.353 回答
2

工厂的整个想法似乎不同。这不仅仅是隐藏实现的复杂性,还涉及控制反转(IoC)。

  • 与其创建自己Sender的对象Receiver,不如让MessageFactory对象负责创建它们。
  • 让我们想象一下,最初我们实现了一个TcpMessageFactoryMessageFactory后代)创建TcpSenderTcpReceiver对象。所以现在我们的应用程序使用 TCP。
  • 稍后我们发现 UDP 更快。所以我们实现了UdpSenderand UdpReciever。此外,我们实现了UdpMessageFactoryMessageFactory后代)
  • 现在我们可以允许用户选择要使用的协议。基于此,我们创建我们的工厂对象(要么 要么TcpMessageFactoryUdpMessageFactory并在我们的应用程序中进一步使用它。

在这个例子中MessageFactory.CreateSenderMessageFactory.CreateReciever必须是抽象方法;Sender形成其公共 API(合同)的方法Reciever也必须是抽象的。

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

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

但如您所知,.NET 及其统一的程序集格式使得在不同模块之间传递对象成为可能。此外,反射允许创建一个你根本不知道的类型。所以 .NET 中的工厂很少使用。

于 2009-12-08T20:57:04.010 回答
0

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

我认为这篇文章的总体思路是隐藏实现,而不是为了解释构造函数的变化而必须防止大量的构造函数重载。作为对象的想法不应该知道如何构造它。

在给出的示例中,您不希望将 Int 类与它如何从字符串或双精度值变为 int 来阻塞,因此您创建了自己的工厂,其唯一职责是从 Y 参数创建 X 对象。

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

于 2009-12-08T20:35:12.820 回答