Abstract Factory(抽象工廠)——物件建立型模式
意圖
提供一個建立一系列相關或相互依賴物件的介面,而無需指定它們具體的類。工廠是建立產品的,抽象工廠就是建立抽象產品的。
典型應用場景
當你想對介面的呼叫者遮蔽介面的實現細節,可以通過抽象工廠模式進行封裝實現。典型的應用案例為對於一個支援多種RDMS自由切換的系統,可以通過分層架構配合抽象工廠進行實現。
傳統三層架構
傳統三層架構包括資料訪問層、業務邏輯層、表示層,如下圖:
資料訪問層封裝對資料庫的增、刪、改、查操作。
業務邏輯層封裝各種業務操作。
表示層負責介面邏輯展示與接受使用者輸入。
業務實體負責在各層之間進行資料傳遞。
資料傳遞過程如下圖所示:
假如業務需要根據不同業務資料規模的應用場景可以支援部署在SQLServer上也可以支援部署在Oracle上,那麼以上簡單的架構則難以支撐;再比如可以根據使用者的喜好把系統部署為Web模式也可以部署為WinForm桌面應用模式,則需要更為複雜的架構設計,經過最小化改進,我們把架構做如下改進。
改進的三層架構
改進的三層架構如下圖:
通過擴充套件,資料訪問層由4部分構成
資料物件工廠——Abstract Factory的具體應用,負責根據配置檔案或引數設定建立資料訪問介面例項
資料訪問介面,定義對各資料表的基本資料訪問操作規範:Insert 、Update、Delete、Get
資料訪問實現類(SQLServerDAL),定義實現資料訪問介面的資料訪問類,基於SQLServer實現基本資料操作。
資料訪問實現類(OracleDAL),定義實現資料訪問介面的資料訪問類,基於Oracle實現基本資料操作
業務邏輯層不會直接呼叫資料訪問實現類(SQLServerDAL或OracleDAL),而是通過資料物件工廠(抽象工廠)建立資料訪問介面例項進行資料訪問的實現。
抽象工廠程式碼實現
工程結構
Web.config、App.config中增加一個表示訪問SQLServer還是Oracle的配置項
<configuration>
<appSettings>
<!--
<add key="DBType" value="Accp.OracleDAL"/>
-->
<add key="DBType" value="Accp.SQLServerDAL"/>
</appSettings>
</configuration
資料訪問介面定義
using System;
using System.Collections.Generic;
using System.Text;
namespace Accp.IDAL
{
using Accp.Model;
public interface ITicketService
{
/// <summary>
/// 查詢符合條件的機票資訊
/// </summary>
/// <param name="fromCity">出發城市ID</param>
/// <param name="toCity">到達城市ID</param>
/// <param name="leaveDate">起飛時間</param>
/// <returns>返回符合條件的機票實體集合</returns>
List<Ticket> GetTicketByCondition(int fromCity, int toCity, string leaveDate);
}
}
資料訪問實現類(SQLServer)
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
namespace Accp.SQLServerDAL
{
using Accp.Model;
using Accp.IDAL;
public class ProvinceInfoService : IProvinceInfoService
{
/// <summary>
/// 執行SQL查詢,封裝查詢結果到實體類和集合
/// </summary>
/// <param name="sql">要執行的SQL語句</param>
/// <param name="values">SQL語句中的引數列表</param>
/// <returns>返回封裝好的實體集合</returns>
private List<ProvinceInfo> GetBySql(string sql, SqlParameter[] values)
{
using (SqlDataReader reader = DBHelper.GetReader(DBHelper.CONSTR, sql, values))
{
List<ProvinceInfo> lst = new List<ProvinceInfo>();
ProvinceInfo province = null;
while (reader.Read())
{
province = new ProvinceInfo();
province.ProvinceId = Convert.ToInt32(reader["provinceId"]);
province.ProvinceName = reader["provinceName"] as string;
lst.Add(province);
}
reader.Close();
return lst;
}
}
#region IProvinceInfoService 成員
/// <summary>
/// 根據省份ID,查詢省份資訊
/// </summary>
/// <param name="provinceId">省份ID</param>
/// <returns>返回省份實體資訊</returns>
public ProvinceInfo GetProvinceInfoById(int provinceId)
{
string sql = "select * from ProvinceInfo where provinceId=@provinceId";
SqlParameter[] values ={
new SqlParameter("@provinceId",provinceId)
};
List<ProvinceInfo> lst = this.GetBySql(sql, values);
if (lst != null && lst.Count > 0) return lst[0];
return null;
}
/// <summary>
/// 查詢所有省份
/// </summary>
/// <returns>返回所有省份實體集合</returns>
public List<ProvinceInfo> GetAllProvinceInfo()
{
string sql = "select * from ProvinceInfo";
return this.GetBySql(sql, null);
}
#endregion
}
}
資料訪問實現類(Oracle)
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.OracleClient;
namespace Accp.OracleDAL
{
using Accp.Model;
using Accp.IDAL;
public class TicketService : ITicketService
{
private CityInfoService cityInfoService = new CityInfoService();
/// <summary>
/// 執行SQL查詢,封裝查詢結果到實體類和集合
/// </summary>
/// <param name="sql">要執行的SQL語句</param>
/// <param name="values">SQL語句中的引數列表</param>
/// <returns>返回封裝好的實體集合</returns>
private List<Ticket> GetBySql(string sql, OracleParameter[] values)
{
using (OracleDataReader reader = DBHelper.GetReader(DBHelper.CONSTR, sql, values))
{
List<Ticket> lst = new List<Ticket>();
Ticket ticket = null;
while (reader.Read())
{
ticket = new Ticket();
ticket.TicketId = Convert.ToInt32(reader["ticketId"]);
ticket.FlightOrder = reader["flightOrder"] as string;
ticket.FromCity = this.cityInfoService.GetCityInfoById(Convert.ToInt32(reader["fromCity"]));
ticket.ToCity = this.cityInfoService.GetCityInfoById(Convert.ToInt32(reader["toCity"]));
ticket.Price = Convert.ToDecimal(reader["price"]);
ticket.LeaveDate = Convert.ToDateTime(reader["leaveDate"]);
ticket.RoomType = Convert.ToInt32(reader["roomType"]);
lst.Add(ticket);
}
reader.Close();
return lst;
}
}
#region ITicketService 成員
/// <summary>
/// 查詢符合條件的機票資訊
/// </summary>
/// <param name="fromCity">出發城市ID</param>
/// <param name="toCity">到達城市ID</param>
/// <param name="leaveDate">起飛時間</param>
/// <returns>返回符合條件的機票實體集合</returns>
public List<Ticket> GetTicketByCondition(int fromCity, int toCity, string leaveDate)
{
string sql = "select * from ticket where fromCity=:fromCity and toCity=:toCity and to_char(leaveDate,'yyyy-MM-dd')=:leaveDate";
OracleParameter[] values ={
new OracleParameter("fromCity",fromCity),
new OracleParameter("toCity",toCity),
new OracleParameter("leaveDate",leaveDate)
};
return GetBySql(sql, values);
}
#endregion
}
}
抽象工廠類實現
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Configuration;
namespace Accp.Factory
{
using Accp.IDAL;
public class DBFactory<T>
{
private static readonly string DBType = ConfigurationManager.AppSettings["DBType"];
/// <summary>
/// 建立介面例項的方法
/// </summary>
/// <returns></returns>
public static T CreateService()
{
Type type = typeof(T);
string fullType = DBType + "." + type.Name.Substring(1);
Assembly assembly = Assembly.Load(DBType);
T instance = (T)assembly.CreateInstance(fullType);
return instance;
}
}
}
業務邏輯層通過抽象工廠獲取資料訪問介面例項,進行資料訪問,示例如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
namespace Accp.BLL
{
using Accp.IDAL;
using Accp.Factory;
using Accp.Model;
[DataObject]
public class TicketManager
{
private static ITicketService ticketService = DBFactory<ITicketService>.CreateService();
/// <summary>
/// 查詢符合條件的機票資訊
/// </summary>
/// <param name="fromCity">出發城市ID</param>
/// <param name="toCity">到達城市ID</param>
/// <param name="leaveDate">起飛時間</param>
/// <returns>返回符合條件的機票實體集合</returns>
[DataObjectMethod(DataObjectMethodType.Select)]
public static List<Ticket> GetTicketByCondition(int fromCity, int toCity, string leaveDate)
{
return ticketService.GetTicketByCondition(fromCity, toCity, leaveDate);
}
}
}
表示層程式碼略
總結
本案例中
資料訪問實現類(SQLServerDAL、OracleDAL)為實體產品;
資料訪問介面(IDAL)為抽象產品;
資料物件工廠(DBFactory)為抽象工廠,遮蔽了在業務邏輯層對SQLServerDAL和OracleDAL的具體依賴,通過修改配置檔案中DBType的值就可以實現對不同RDBMS的切換支援;
業務邏輯類(BLL)為客戶;
相關文章
- 設計模式--抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 設計模式-抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 設計模式實戰 - 抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 設計模式實戰 – 抽象工廠模式(Abstract Factory Pattern)設計模式抽象
- 【圖解設計模式系列】The Abstract Factory Pattern: 抽象工廠模式圖解設計模式抽象
- 建立型:工廠模式-工廠方法、抽象工廠模式抽象
- 建立型設計模式——抽象工廠模式設計模式抽象
- JAVA設計模式 3【建立型】理解工廠模式與抽象工廠模式Java設計模式抽象
- 建立型模式:抽象工廠模式抽象
- 【Python設計模式】03 工廠模式:建立建立物件的工廠Python設計模式物件
- 建立型:工廠模式-簡單工廠模式
- 抽象工廠模式抽象模式
- JavaScript建立物件(一)——工廠模式JavaScript物件模式
- 使用C# (.NET Core) 實現抽象工廠設計模式 (Abstract Pattern)C#抽象設計模式
- 簡單工廠模式、工廠模式、抽象工廠模式比較模式抽象
- 簡單工廠模式和抽象工廠模式模式抽象
- java 抽象工廠模式Java抽象模式
- 【Python】抽象工廠模式Python抽象模式
- 06: 抽象工廠模式抽象模式
- python物件導向之抽象工廠設計模式Python物件抽象設計模式
- 設計模式-簡單工廠、工廠方法模式、抽象工廠模式設計模式抽象
- 《設計模式》 - 2. 工廠模式( Factory )設計模式
- 設計模式 —— 抽象工廠模式設計模式抽象
- 設計模式-抽象工廠模式設計模式抽象
- 設計模式——抽象工廠模式設計模式抽象
- 一篇搞定工廠模式【簡單工廠、工廠方法模式、抽象工廠模式】模式抽象
- 簡單工廠模式( Simple Factory Pattern )模式
- 設計模式-建立型-工廠方法設計模式
- 設計模式學習(二)工廠模式——抽象工廠模式設計模式抽象
- C# 設計模式(1)——簡單工廠模式、工廠模式、抽象工廠模式C#設計模式抽象
- 設計模式 - 抽象工廠設計模式抽象
- 04_抽象工廠模式抽象模式
- Java抽象工廠模式案例Java抽象模式
- 設計模式----抽象工廠設計模式抽象
- 設計模式 – 抽象工廠設計模式抽象
- Python 實現工廠模式、抽象工廠,單例模式Python模式抽象單例
- 設計模式--工廠方法模式(Factory Method Pattern)設計模式
- 設計模式之工廠模式!深入解析簡單工廠模式,工廠方法模式和抽象工廠模式設計模式抽象