〇、簡介
1、什么是抽象工廠模式?
一句話解釋:
??提供一個接口,以創(chuàng)建一系列相關或相互依賴的抽象對象,而無需指定它們具體的類。(將一系列抽象類裝進接口,一次接口實現(xiàn),就必須實例化這一系列抽象類)
抽象工廠模式(Abstract Factory Pattern)是一種創(chuàng)建型模式。它用于創(chuàng)建一組相關對象的家族。強調(diào)的是一組對象之間的協(xié)作關系,而不是單個對象之間的依賴關系。抽象工廠類負責創(chuàng)建整個家族的對象的生命周期,并隱藏與實現(xiàn)有關的邏輯。
?一個比喻:(科目與課代表)
??語文和數(shù)學的課代表和副課代表,都按照抽象方法標準選好了,接下來同樣的通過實現(xiàn)抽象類和接口標準,來選出兩名物理課代表。當然,已經(jīng)選出來的其他課代表,和本次選舉無關聯(lián)。
2、優(yōu)缺點和使用場景
優(yōu)點:
- 可以降低系統(tǒng)中各個對象之間的耦合度。
- 隔離了具體類的生產(chǎn),使得客戶并不需要知道什么被創(chuàng)建。
- 增加新的具體工廠和產(chǎn)品族很方便,無須修改已有系統(tǒng),符合“開閉原則”。
缺點:
- 在增加新的產(chǎn)品方面比較困難,需要修改抽象工廠的接口,這樣會導致所有的具體工廠也需要做出相應的修改。
- 抽象程度高,可能會導致一些底層實現(xiàn)細節(jié)難以控制。
總之,抽象工廠模式能夠有效地封裝對象創(chuàng)建,但是擴展產(chǎn)品較為困難。它在軟件開發(fā)中被廣泛使用,特別是在跨平臺軟件開發(fā)中經(jīng)常用到,使用時要注意系統(tǒng)對象的特點合理使用。
適用場景:
- 一個系統(tǒng)要獨立于它的產(chǎn)品的創(chuàng)建、組合和表示。
- 一個系統(tǒng)要有多個產(chǎn)品系列中的一個來配置。
- 要強調(diào)一系列相關的產(chǎn)品對象的設計,以便進行聯(lián)合使用。
- 提供一個產(chǎn)品類庫,但只想顯示它們的接口而不是實現(xiàn)。
實際使用場景舉例:
- 游戲開發(fā):游戲中可能需要多種角色、武器、敵人等元素,它們之間可能存在關聯(lián)性或依賴性,可以使用抽象工廠方法來快速構(gòu)建游戲元素。
- 數(shù)據(jù)庫訪問組件設計:不同數(shù)據(jù)庫的連接、查詢和數(shù)據(jù)存儲方式可能存在差異,可以使用抽象工廠方法來創(chuàng)建不同數(shù)據(jù)庫的訪問組件、驅(qū)動和映射器。
- 操作系統(tǒng)界面設計:不同操作系統(tǒng)的界面設計具有不同的特點,可以使用抽象工廠方法來創(chuàng)建不同操作系統(tǒng)下的控件。
總之,使用抽象工廠模式,都需要保證對象家族之間高內(nèi)聚、松耦合,使得系統(tǒng)的設計和實現(xiàn)更加靈活和可擴展。
一、抽象工廠模式簡單實現(xiàn)與擴展
通過兩個抽象類 ProductA/ProductBBBB,實現(xiàn)四個具體產(chǎn)品類;在通過接口 IAbstractFactory,實現(xiàn)兩個具體工廠的產(chǎn)品族 ConcreteFactory1/ConcreteFactory2。最后通過 Client 類注入工廠類的同時,創(chuàng)建產(chǎn)品的不同產(chǎn)品的實例,使客戶端不用了解產(chǎn)品如何實例化,可以直接引用。
// 抽象產(chǎn)品類。
public abstract class ProductA
{
public abstract void OperationA();
}
public abstract class ProductBBBB
{
public abstract void OperationBBBB();
}
// 具體產(chǎn)品類,其中 ProductA1、ProductA2、ProductB1 和 ProductB2 分別代表不同的產(chǎn)品。
public class ProductA1 : ProductA
{
public override void OperationA()
{
Console.WriteLine("ProductA1's operation.");
}
}
public class ProductA2 : ProductA
{
public override void OperationA()
{
Console.WriteLine("ProductA2's operation.");
}
}
public class ProductBBBB1 : ProductBBBB
{
public override void OperationBBBB()
{
Console.WriteLine("ProductBBBB1's operation.");
}
}
public class ProductBBBB2 : ProductBBBB
{
public override void OperationBBBB()
{
Console.WriteLine("ProductBBBB2's operation.");
}
}
// 抽象工廠接口,定義了各種不同產(chǎn)品族的生產(chǎn)方法。
public interface IAbstractFactory
{
ProductA CreateProductA();
ProductBBBB CreateProductBBBB();
}
// 每個具體工廠都能夠生產(chǎn)特定的產(chǎn)品族。
public class ConcreteFactory1 : IAbstractFactory
{
public ProductA CreateProductA()
{
return new ProductA1();
}
public ProductBBBB CreateProductBBBB()
{
return new ProductBBBB1();
}
}
public class ConcreteFactory2 : IAbstractFactory
{
public ProductA CreateProductA()
{
return new ProductA2();
}
public ProductBBBB CreateProductBBBB()
{
return new ProductBBBB2();
}
}
// 客戶端代碼使用抽象工廠來創(chuàng)建各種不同產(chǎn)品族的產(chǎn)品,而無需關心它們的實際實現(xiàn)。
public class Client
{
private readonly ProductA _productA;
private readonly ProductBBBB _productBBBB;
public Client(IAbstractFactory factory)
{
_productA = factory.CreateProductA();
_productBBBB = factory.CreateProductBBBB();
}
public void Run()
{
_productA.OperationA();
_productBBBB.OperationBBBB();
}
}
// 測試
static void Main(string[] args)
{
Client client = new Client(new ConcreteFactory1());
client.Run();
Client client2 = new Client(new ConcreteFactory2());
client2.Run();
// 輸出:
// ProductA1's operation.
// ProductBBBB1's operation.
// ProductA2's operation.
// ProductBBBB2's operation.
}
下面我們嘗試擴展出來一個新的產(chǎn)品 3:
// 具體產(chǎn)品類
public class ProductA3 : ProductA
{
public override void OperationA()
{
Console.WriteLine("ProductA3's operation.");
}
}
public class ProductBBBB3 : ProductBBBB
{
public override void OperationBBBB()
{
Console.WriteLine("ProductBBBB3's operation.");
}
}
// 具體工廠都能夠生產(chǎn)特定的產(chǎn)品族
public class ConcreteFactory3 : IAbstractFactory
{
public ProductA CreateProductA()
{
return new ProductA3();
}
public ProductBBBB CreateProductBBBB()
{
return new ProductBBBB3();
}
}
?測試:
static void Main(string[] args)
{
Client client = new Client(new ConcreteFactory1());
client.Run();
Client client2 = new Client(new ConcreteFactory2());
client2.Run();
Client client3 = new Client(new ConcreteFactory3());
client3.Run();
}
??
二、抽象工廠模式的結(jié)構(gòu)
根據(jù)上一章節(jié)的示例代碼,簡單畫一個 UML 圖,如下:
- AbstractFactory:聲明一個創(chuàng)建抽象產(chǎn)品對象的操作接口。
- ConcreteFactory:實現(xiàn)創(chuàng)建具體產(chǎn)品對象的操作。
- AbstractProduct:為一類產(chǎn)品對象聲明一個接口。
- ConcreteProduct:定義一個將被相應的具體工廠創(chuàng)建的產(chǎn)品對象。實現(xiàn)了 IAbstractProduct 接口。
- Client:僅使用由 AbstractFactory 和 AbstractProduct 類聲明的接口。
通常在運行時創(chuàng)建一個 ConcreteFactory 類的實例,此實例具有 AbstractFactory? 中全部定義的實現(xiàn)。當客戶端需要創(chuàng)建不同的產(chǎn)品對象時,可以通過實現(xiàn)抽象工廠來創(chuàng)建具體工廠。
AbstractFactory? 將產(chǎn)品對象的創(chuàng)建延遲到它的 ConcreteFactory 子類。
三、抽象工廠模式在 .net 框架中的實際應用
例如 DbProviderFactory,這個類位于 System.Data.Common.dll 程序集中,該類扮演抽象工廠模式中抽象工廠的角色,源碼如下:
// System.Data.Common, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Data.Common.DbProviderFactory
using System.Data.Common;
public abstract class DbProviderFactory
{
private bool? _canCreateDataAdapter;
private bool? _canCreateCommandBuilder;
public virtual bool CanCreateDataSourceEnumerator => false;
public virtual bool CanCreateDataAdapter
{
get
{
if (!_canCreateDataAdapter.HasValue)
{
using DbDataAdapter dbDataAdapter = CreateDataAdapter();
_canCreateDataAdapter = dbDataAdapter != null;
}
return _canCreateDataAdapter.Value;
}
}
public virtual bool CanCreateCommandBuilder
{
get
{
if (!_canCreateCommandBuilder.HasValue)
{
using DbCommandBuilder dbCommandBuilder = CreateCommandBuilder();
_canCreateCommandBuilder = dbCommandBuilder != null;
}
return _canCreateCommandBuilder.Value;
}
}
public virtual DbCommand? CreateCommand()
{
return null;
}
public virtual DbCommandBuilder? CreateCommandBuilder()
{
return null;
}
public virtual DbConnection? CreateConnection()
{
return null;
}
public virtual DbConnectionStringBuilder? CreateConnectionStringBuilder()
{
return null;
}
public virtual DbDataAdapter? CreateDataAdapter()
{
return null;
}
public virtual DbParameter? CreateParameter()
{
return null;
}
public virtual DbDataSourceEnumerator? CreateDataSourceEnumerator()
{
return null;
}
}
下面是 SqlClientFactory.cs,繼承了抽象類 DbProviderFactory,需要注意的是,此為引用程序集,即只包含元數(shù)據(jù),不含可執(zhí)行代碼。如何通過工廠模式訪問 SQLServer 數(shù)據(jù)庫,可以參考官網(wǎng)示例: 獲取 DbProviderFactory
點擊查看 SqlClientFactory.cs
?// System.Data.SqlClient, Version=4.6.1.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Data.SqlClient.SqlClientFactory
using System.Data.Common;
using System.Data.SqlClient;
/// <summary>Represents a set of methods for creating instances of the <see cref="N:System.Data.SqlClient" /> provider's implementation of the data source classes.</summary>
public sealed class SqlClientFactory : DbProviderFactory
{
/// <summary>Gets an instance of the <see cref="T:System.Data.SqlClient.SqlClientFactory" />. This can be used to retrieve strongly typed data objects.</summary>
public static readonly SqlClientFactory Instance;
internal SqlClientFactory()
{
}
/// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbCommand" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbCommand" />.</returns>
public override DbCommand CreateCommand()
{
throw null;
}
/// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbCommandBuilder" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbCommandBuilder" />.</returns>
public override DbCommandBuilder CreateCommandBuilder()
{
throw null;
}
/// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbConnection" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbConnection" />.</returns>
public override DbConnection CreateConnection()
{
throw null;
}
/// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbConnectionStringBuilder" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbConnectionStringBuilder" />.</returns>
public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{
throw null;
}
/// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbDataAdapter" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbDataAdapter" />.</returns>
public override DbDataAdapter CreateDataAdapter()
{
throw null;
}
/// <summary>Returns a strongly typed <see cref="T:System.Data.Common.DbParameter" /> instance.</summary>
/// <returns>A new strongly typed instance of <see cref="T:System.Data.Common.DbParameter" />.</returns>
public override DbParameter CreateParameter()
{
throw null;
}
}
下面再看一下 Oracle 工廠的實現(xiàn),完全獨立于其他數(shù)據(jù)庫的工廠:文章來源:http://www.zghlxwxcb.cn/news/detail-464812.html
點擊查看 OracleClientFactory.cs
#region 程序集 Oracle.ManagedDataAccess, Version=4.122.21.1, Culture=neutral, PublicKeyToken=89b483f429c47342
// C:\Users\zheng\.nuget\packages\oracle.manageddataaccess\21.10.0\lib\net462\Oracle.ManagedDataAccess.dll
// Decompiled with ICSharpCode.Decompiler 7.1.0.6543
#endregion
using System;
using System.Data.Common;
using System.Security;
using System.Security.Permissions;
using OracleInternal.Common;
namespace Oracle.ManagedDataAccess.Client
{
public sealed class OracleClientFactory : DbProviderFactory
{
public static readonly OracleClientFactory Instance = new OracleClientFactory();
public override bool CanCreateDataSourceEnumerator => true;
public override DbCommand CreateCommand()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommand);
}
try
{
return new OracleCommand();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommand, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommand);
}
}
}
public override DbCommandBuilder CreateCommandBuilder()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommandBuilder);
}
try
{
return new OracleCommandBuilder();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommandBuilder, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateCommandBuilder);
}
}
}
public override DbConnection CreateConnection()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnection);
}
try
{
return new OracleConnection();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnection, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnection);
}
}
}
public override DbConnectionStringBuilder CreateConnectionStringBuilder()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnectionStringBuilder);
}
try
{
return new OracleConnectionStringBuilder();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnectionStringBuilder, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateConnectionStringBuilder);
}
}
}
public override DbDataAdapter CreateDataAdapter()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataAdapter);
}
try
{
return new OracleDataAdapter();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataAdapter, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataAdapter);
}
}
}
public override DbDataSourceEnumerator CreateDataSourceEnumerator()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataSourceEnumerator);
}
try
{
return new OracleDataSourceEnumerator();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataSourceEnumerator, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateDataSourceEnumerator);
}
}
}
public override DbParameter CreateParameter()
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateParameter);
}
try
{
return new OracleParameter();
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateParameter, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreateParameter);
}
}
}
public override CodeAccessPermission CreatePermission(PermissionState state)
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Entry, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreatePermission);
}
try
{
return new OraclePermission(state);
}
catch (Exception ex)
{
OracleException.HandleError(OracleTraceLevel.Public, OracleTraceTag.Error, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreatePermission, ex);
throw;
}
finally
{
if (ProviderConfig.m_bTraceLevelPublic)
{
Trace.Write(OracleTraceLevel.Public, OracleTraceTag.Exit, OracleTraceClassName.OracleClientFactory, OracleTraceFuncName.CreatePermission);
}
}
}
}
}
當然,諸如 Mysql、DB2 等類同。由此可見,當后續(xù)新增數(shù)據(jù)庫時,只需對 DbProviderFactory 抽象工廠進行繼承即可,對已實現(xiàn)的數(shù)據(jù)工廠毫無影響。文章來源地址http://www.zghlxwxcb.cn/news/detail-464812.html
到了這里,關于Abstract Factory Pattern 抽象工廠模式簡介與 C# 示例【創(chuàng)建型】【設計模式來了】的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!