Answers:
抽象工厂是用于依赖注入(DI)的非常核心的设计模式。这是堆栈溢出问题的列表,其中抽象工厂的应用已被接受为解决方案。
据我所知,这些问题代表人们真正关心的问题或问题,因此应该使您从一些现实生活的例子入手:
使用Abstract Factory模式的一个现实示例是提供对两个不同数据源的数据访问。假设您的应用程序支持不同的数据存储。(例如,SQL数据库和XML文件)。您有两个不同的数据访问接口,例如IReadableStore
和和,它们IWritableStore
定义了应用程序期望的通用方法,而与所使用的数据源的类型无关。
应该使用哪种类型的数据源不应更改客户端代码检索其数据访问类的方式。您AbstractDataAccessFactory
知道配置了哪种类型的数据源,并为客户端代码(即或)提供了具体的Factory。这些具体工厂可以创建具体的实现,例如和。SqlDataAccessFactory
XmlDataAccessFactory
SqlReadableStore
SqlWriteableStore
.NET Framework中的DbProviderFactory是此模式的示例。
抽象工厂模式的用途是什么,因为我们可以通过创建具体类本身的对象来完成任务。为什么我们有一个工厂方法来创建Concrete类的对象?
在没有Abstract Factory的情况下,客户需要了解具体类的详细信息。这种紧密的耦合已由Abstract Factory删除。
现在,工厂方法公开了客户必须使用的合同。您可以通过添加实现工厂方法公开的接口的新产品来向工厂添加更多产品。
请参阅以下相关的SE问题,以更好地理解:
意图:
提供一个用于创建相关或相关对象族的接口,而无需指定其具体类。
你能理解意图,结构,清单和经验法则的抽象工厂从这种模式sourcemaking文章。
清单:
抽象工厂非常适合支持多种平台,同时保持您的代码库统一。假设您要在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);
很容易,想象一下您具有与抽象一起工作的代码,则应该创建抽象而不是具体的类。
您应该始终反对抽象,因为您可以更好地修改代码。
这是一个很好的例子:http : //en.wikipedia.org/wiki/Abstract_factory_pattern#C.23
我发现抽象工厂模式被高估了。
首先,通常不会有要实例化的一组相互关联的类型。
其次,在进行依赖注入时,接口提供的间接(抽象)级别通常就足够了。
WindowsGui vs MacGui vs ...的典型示例通常具有WindowsButton,MacButton,WindowsScrollBar,MacScrollbar等,通过使用来宾和/或解释器模式来定义具体的 Button,Scrollbars等,通常更易于实现。实际行为。
我认为在实例化非常复杂,单个工厂过于复杂和丑陋且UI难以理解的地方,有一个抽象工厂模式而不是简单工厂模式的地方。
假设这是一个TYPE_A品牌,而不是一个单一的类。.假设有一个100种相似的Type-A类,您需要从它们中实例化一个对象。想象一下,需要一个详细的复杂信息,才能从许多类似类型的对象的品牌中制造出正确的对象,并且在该对象实体中,您需要确切地知道要调整的参数以及如何调整它们。
在该品牌的特殊工厂,我们将让他们与众不同,并获取要实例化的确切对象以及如何实例化它。我们将根据来自网络的输入(例如,在线商店中可用的颜色)以及来自在后台运行的其他应用程序和服务的输入(用户界面不知道它们的参数)知道这一点。
也许明天我们将有另一类实例化的type_B和type_C。因此,UI将具有“ if else”(如果有的话)来知道用户是否需要“ type_A”,“ type_B”或“ type_C” –但是工厂类将根据类型(来自家庭)确切地确定要构建哪个类,以及如何调整–为其参数设置什么值,或发送给承包商。所有这些-根据UI无法识别的许多参数。对于单个工厂类而言,所有这些都将太多。
当客户端完全不知道要创建哪种类型时,此模式特别有用。例如,假设一个专门销售手机的陈列室可以查询三星生产的智能手机。在这里,我们不知道要创建的对象的确切类型(假定电话的所有信息都以具体对象的形式包装)。但是我们知道我们正在寻找三星制造的智能手机。如果我们的设计具有Abstract工厂实施,则实际上可以利用此信息。
在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;
具体的工厂实例使用静态工厂方法提供,如下所示
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");
}
}