为什么我们需要抽象工厂设计模式?

时间:2010-02-17 11:28:01

标签: design-patterns abstract-factory

大多数定义都说:

  

抽象工厂提供   用于创建系列的接口   没有指定的相关对象   他们的具体课程

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

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

15 个答案:

答案 0 :(得分:212)

答案 1 :(得分:22)

使用抽象工厂模式的现实例子是提供对两个不同数据源(例如SQL数据库和XML文件)的数据访问。您有两个不同的数据访问类(数据存储的网关)。两者都继承自定义要实现的常用方法的基类(例如,加载,保存,删除)。

应使用哪个数据源不应改变客户端代码检索数据访问类的方式。您的抽象工厂知道应使用哪个数据源并根据请求返回适当的实例。工厂将此实例作为基类类型返回。

答案 2 :(得分:5)

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

答案 3 :(得分:3)

  

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

如果没有抽象工厂,客户需要了解具体类的详细信息。使用抽象工厂删除了这种紧耦合。

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

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

What is the basic difference between the Factory and Abstract Factory Patterns?

<强>意图:

  

提供用于创建相关或从属对象族的接口,而无需指定其具体类。

您可以通过此sourcemaking文章了解 模式的 意图,结构,核对表和 模式。

清单:

  1. 决定平台独立性和创建服务是否是目前的痛苦来源。
  2. 制定平台产品的矩阵。
  3. 定义工厂界面,其中包含每种产品的工厂方法。
  4. 为每个平台定义一个 factory 派生类,该类封装了对new运算符的所有引用。
  5. 客户端应停用对new的所有引用,并使用工厂方法创建产品对象。

答案 4 :(得分:2)

Abstract Factories非常适合支持多个平台,同时保持您的代码库统一。假设您要在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);

答案 5 :(得分:1)

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

答案 6 :(得分:1)

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

你应该总是反对抽象,因为你可以更好地修改代码。

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

答案 7 :(得分:1)

我认为在实例化非常复杂的地方,抽象工厂模式有一个地方而不是简单的工厂模式, 对于单个工厂来说太复杂和丑陋,而且用户界面太难理解......

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

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

也许明天我们会有另一个家庭让我们说type_B和type_C来实例化。 因此UI将有“if else”来知道用户是否想要“type_A”,“type_B”或“type_C” - 但工厂类将确定要从类型(来自系列)构建哪个类,以及如何调整它 - 设置其参数的值,或发送给其承包商。所有这些 - 根据UI不知道的许多参数。 所有这些对于单个工厂类来说太过分了。

答案 8 :(得分:1)

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

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

示例:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

enter image description here

        /* 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 enter image description here

代码解决方案架构 enter image description here

使用以下静态工厂方法提供具体的工厂实例

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

答案 9 :(得分:0)

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

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

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

通过定义具体按钮,滚动条等,WindowsGui与MacGui vs ...的典型示例通常更容易实现WindowsButton,MacButton,WindowsScrollBar,MacScrollbar等。使用访问者和/或口译员模式来提供实际行为。

答案 10 :(得分:0)

要直接回答您的问题,您可以在不使用此类设计模式的情况下离开。

但请记住,现实世界中的大多数项目都在不断发展,您希望提供某种可扩展性,以使您的项目面向未来。

根据我自己的经验,大多数时候,工厂已经实施,随着项目的发展,它会变成更复杂的设计模式,例如抽象工厂。

答案 11 :(得分:0)

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

答案 12 :(得分:0)

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

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

答案 13 :(得分:0)

  

当客户不知道时,这种模式特别有用   究竟要创建什么类型。举个例子,让我们说一个陈列室   专门销售手机获得了智能手机的查询   由三星。在这里,我们不知道要创建的对象的确切类型   (假设手机的所有信息都以a的形式包装   具体对象)。但我们知道我们正在寻找智能手机   这是由三星制造的。这个信息实际上可以是   如果我们的设计具有抽象工厂实现,则使用。

Understanding and Implementing Abstract Factory Pattern in C#

答案 14 :(得分:0)

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

它通常抽象如下:

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

工厂的责任简而言之。

您可以通过this进行详细说明。