136

大多数定义说:

抽象工厂为创建相关对象族提供了一个接口,而无需指定它们的具体类

抽象工厂模式有什么用,因为我们可以通过创建具体类本身的对象来完成任务。为什么我们有一个创建具体类对象的工厂方法?

请提供我必须实现 abstractFactory 模式的任何现实生活示例?

4

15 回答 15

26

使用抽象工厂模式的一个真实示例是提供对两个不同数据源的数据访问。假设您的应用程序支持不同的数据存储。(例如,一个 SQL 数据库和一个 XML 文件)。您有两个不同的数据访问接口,例如一个IReadableStoreIWritableStore定义您的应用程序期望的通用方法,而不管使用的数据源类型如何。

应使用哪种类型的数据源不应改变客户端代码检索其数据访问类的方式。您AbstractDataAccessFactory知道配置了哪种类型的数据源,并为客户端代码提供了具体的工厂,即SqlDataAccessFactoryXmlDataAccessFactory. 这些具体工厂可以创建具体的实现,例如SqlReadableStoreSqlWriteableStore

.NET Framework 中的DbProviderFactory就是这种模式的一个示例。

于 2010-02-17T11:50:04.810 回答
5

如果我理解正确 - 问题是,为什么我们同时拥有工厂方法和抽象工厂模式。当不同的多态类具有不同的实例化过程时,您需要抽象工厂。并且您希望某些模块创建实例并使用它们,而无需了解对象初始化的任何细节。例如 - 你想创建 Java 对象来做一些计算。但是其中一些是应用程序的一部分,而其他的字节码应该从数据库中读取。另一方面——为什么我们需要工厂方法?同意,抽象工厂与它重叠。但在某些情况下 - 编写的代码要少得多,类和接口更少,使系统更容易理解。

于 2010-02-17T11:49:05.007 回答
4

抽象工厂非常适合支持多个平台,同时保持代码库的统一。假设您有一个想要在 Windows、Linux 和 OSX 上运行的大型 Qt 或 GTK+ 或 .NET/Mono 程序。但是您有一个功能在每个平台上以不同的方式实现(可能通过 kernel32 API 或 POSIX 功能)。

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

使用这个抽象工厂,您的 UI 不需要了解有关当前平台的任何信息。

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);
于 2013-07-17T15:33:12.427 回答
4

抽象工厂模式有什么用,因为我们可以通过创建具体类本身的对象来完成任务。为什么我们有一个创建具体类对象的工厂方法?

在没有抽象工厂的情况下,客户需要知道具体类的细节。这种紧密耦合已与Abstract Factory移除。

现在工厂方法公开了一个客户必须使用的合同。您可以通过添加新产品来向您的工厂添加更多产品,这些产品实现了工厂方法公开的接口。

请参阅这些相关的 SE 问题以更好地理解:

工厂模式和抽象工厂模式之间的基本区别是什么?

意图:

提供用于创建相关或依赖对象系列的接口,而无需指定它们的具体类。

您可以从这篇源代码文章中了解抽象工厂模式的意图、结构、清单和经验法则。

清单:

  1. 确定平台独立性和创建服务是否是当前的痛点。
  2. 绘制出平台产品的矩阵。
  3. 定义一个由每个产品的工厂方法组成的工厂接口。
  4. 为每个平台定义一个工厂派生类,该类封装了对 new 运算符的所有引用。
  5. 客户端应该取消对 new 的所有引用,并使用工厂方法创建产品对象。
于 2016-06-14T16:59:12.937 回答
2

很容易,想象你有一个与抽象一起工作的代码,你应该创建抽象而不是具体的类。

您应该始终反对抽象,因为您可以更好地修改代码。

这是一个很好的例子: http ://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23

于 2010-02-17T11:51:30.450 回答
2

实际示例在 System.Data.Common 命名空间中提供,该命名空间具有抽象基类,包括 DbConnection、DbCommand 和 DbDataAdapter,并由 .NET Framework 数据提供者共享,例如 System.Data.SqlClient 和 System.Data.OracleClient使开发人员能够编写不依赖于特定数据提供者的通用数据访问代码。

DbProviderFactories 类提供用于创建 DbProviderFactory 实例的静态方法。然后,该实例根据提供者信息和运行时提供的连接字符串返回正确的强类型对象。

例子:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

在此处输入图像描述

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

示例 2 在此处输入图像描述

代码解决方案架构 在此处输入图像描述

使用静态工厂方法提供具体工厂实例,如下所示

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}
于 2020-02-14T21:22:21.933 回答
1

我发现抽象工厂模式被高估了。

首先,您想要实例化一组相互关联的类型并不经常发生。

其次,接口提供的间接(抽象)级别通常在使用依赖注入时就足够了。

WindowsGui vs MacGui vs ...的典型示例,您将拥有一个 WindowsButton、MacButton、WindowsScrollBar、MacScrollbar 等,通常通过使用访问者和/或解释器模式定义具体的按钮、滚动条等更容易实现实际行为。

于 2010-02-17T12:21:31.263 回答
1

如果你看一下设计模式,几乎所有的设计模式都可以变得多余。但是什么模式意味着解决类似问题的常用方法。设计模式为您提供了一组类似类型的设计问题的设计级别方法或解决方案。使用设计模式可以帮助您解决问题,从而更快地交付。

于 2010-02-17T11:40:30.080 回答
1

我认为在您的实例化非常复杂、对于单个工厂而言过于复杂和丑陋并且对于 UI 无法理解的情况而言过于复杂的地方,存在抽象工厂模式而不是简单工厂模式的地方。

假设这是一个 TYPE_A 品牌,而不是单个类。假设有 100 种相似的 Type-A 类,您需要从中实例化一个对象。想象一下,为了从许多相似类型的对象中制作正确的对象,需要详细的复杂信息,并且在这个对象实体中,您需要准确地知道要调整哪些参数以及如何调整它们。

在该品牌的特殊工厂中,我们将让他们区分并获得要实例化的确切对象以及如何实例化它。我们会知道,根据来自网络的输入(假设在线商店有什么颜色),以及来自后台运行的其他应用程序和服务(UI 不知道的参数)。

也许明天我们会有另一个系列,比如说 type_B 和 type_C 来实例化。因此,UI 将通过“if else”来了解用户是否想要“type_A”、“type_B”或“type_C”——但工厂类将准确地决定要构建类型(来自家族)中的哪个类,并且如何调整它——为它的参数设置什么值,或者发送给它的承包商。所有这一切 - 根据 UI 不知道的许多参数。对于单个工厂类来说,所有这些都太过分了。

于 2017-12-03T16:57:29.247 回答
1

当客户端不确切知道要创建什么类型时,此模式特别有用。例如,假设专门销售手机的 Showroom 查询三星制造的智能手机。在这里,我们不知道要创建的对象的确切类型(假设电话的所有信息都以具体对象的形式包装)。但我们确实知道我们正在寻找三星制造的智能手机。如果我们的设计具有抽象工厂实现,则实际上可以使用此信息。

在 C# 中理解和实现抽象工厂模式

于 2017-10-13T16:03:43.080 回答
1

抽象工厂或任何工厂,它们的存在是为了解决相同的问题,即“对象创建的抽象”。

它通常抽象出以下内容:

  1. if条件来决定实例化哪个对象。
  2. new运算符,对象的实例化。

简而言之,工厂的责任就是这样。

你可以通过这个来获得详细的解释。

于 2020-08-28T03:33:18.703 回答
0

这都是关于依赖关系的。如果您不关心紧密耦合和依赖关系,那么您不需要抽象工厂。但是,一旦您编写了需要维护的应用程序,它就会很重要。

于 2015-03-04T07:05:51.987 回答
0

要直接回答您的问题,您可能无需使用这种设计模式就可以逃脱。

但是请记住,现实世界中的大多数项目都在发展,您希望提供某种可扩展性以使您的项目能够适应未来。

根据我自己的经验,大多数情况下,工厂都会被实现,随着项目的发展,它会变成更复杂的设计模式,例如抽象工厂。

于 2010-02-17T13:47:59.237 回答
0

假设您创建了一个.jar,而其他人使用您的 jar 并希望在您的代码中使用一个新的具体对象。如果您不使用抽象工厂,那么她必须修改您的代码或覆盖您的代码。但是如果您使用的是抽象工厂,那么她可以提供一个工厂并传递给您的代码,一切都很好。

精炼版:考虑下面的场景:别人写了一个框架。该框架使用抽象工厂和一些具体工厂在运行时创建大量对象。因此,您可以轻松地将自己的工厂注册到现有框架并创建自己的对象。由于抽象工厂模式,该框架对修改是封闭的,并且仍然易于扩展。

于 2015-11-17T06:34:19.847 回答