Abstract Factory(抽象工厂)——对象创建型模式

Abstract Factory(抽象工厂)——对象创建型模式

  • 意图
  • 典型应用场景
    • 传统三层架构
    • 改进的三层架构
    • 抽象工厂代码实现
  • 总结

意图

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。工厂是创建产品的,抽象工厂就是创建抽象产品的。

典型应用场景

当你想对接口的调用者屏蔽接口的实现细节,可以通过抽象工厂模式进行封装实现。典型的应用案例为对于一个支持多种RDMS自由切换的系统,可以通过分层架构配合抽象工厂进行实现。

传统三层架构

传统三层架构包括数据访问层、业务逻辑层、表示层,如下图:
Abstract Factory(抽象工厂)——对象创建型模式_第1张图片

数据访问层封装对数据库的增、删、改、查操作。
业务逻辑层封装各种业务操作。
表示层负责界面逻辑展示与接受用户输入。
业务实体负责在各层之间进行数据传递。

数据传递过程如下图所示:
Abstract Factory(抽象工厂)——对象创建型模式_第2张图片
假如业务需要根据不同业务数据规模的应用场景可以支持部署在SQLServer上也可以支持部署在Oracle上,那么以上简单的架构则难以支撑;再比如可以根据用户的喜好把系统部署为Web模式也可以部署为WinForm桌面应用模式,则需要更为复杂的架构设计,经过最小化改进,我们把架构做如下改进。

改进的三层架构

改进的三层架构如下图:
Abstract Factory(抽象工厂)——对象创建型模式_第3张图片
通过扩展,数据访问层由4部分构成

数据对象工厂——Abstract Factory的具体应用,负责根据配置文件或参数设置创建数据访问接口实例
数据访问接口,定义对各数据表的基本数据访问操作规范:Insert 、Update、Delete、Get
数据访问实现类(SQLServerDAL),定义实现数据访问接口的数据访问类,基于SQLServer实现基本数据操作。
数据访问实现类(OracleDAL),定义实现数据访问接口的数据访问类,基于Oracle实现基本数据操作

业务逻辑层不会直接调用数据访问实现类(SQLServerDAL或OracleDAL),而是通过数据对象工厂(抽象工厂)创建数据访问接口实例进行数据访问的实现。

抽象工厂代码实现

工程结构
Abstract Factory(抽象工厂)——对象创建型模式_第4张图片
Web.config、App.config中增加一个表示访问SQLServer还是Oracle的配置项

<configuration>
	<appSettings>
    
    <add key="DBType" value="Accp.SQLServerDAL"/>
	appSettings>

数据访问接口定义

using System;
using System.Collections.Generic;
using System.Text;

namespace Accp.IDAL
{
    using Accp.Model;
    public interface ITicketService
    {
        /// 
        /// 查询符合条件的机票信息
        /// 
        /// 出发城市ID
        /// 到达城市ID
        /// 起飞时间
        /// 返回符合条件的机票实体集合
        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
    {
        /// 
        /// 执行SQL查询,封装查询结果到实体类和集合
        /// 
        /// 要执行的SQL语句
        /// SQL语句中的参数列表
        /// 返回封装好的实体集合
        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 成员
        /// 
        /// 根据省份ID,查询省份信息
        /// 
        /// 省份ID
        /// 返回省份实体信息
        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;
        }
        /// 
        /// 查询所有省份
        /// 
        /// 返回所有省份实体集合
        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();
        /// 
        /// 执行SQL查询,封装查询结果到实体类和集合
        /// 
        /// 要执行的SQL语句
        /// SQL语句中的参数列表
        /// 返回封装好的实体集合
        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 成员
        /// 
        /// 查询符合条件的机票信息
        /// 
        /// 出发城市ID
        /// 到达城市ID
        /// 起飞时间
        /// 返回符合条件的机票实体集合
        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"];
        /// 
        /// 创建接口实例的方法
        /// 
        /// 
        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();
        /// 
        /// 查询符合条件的机票信息
        /// 
        /// 出发城市ID
        /// 到达城市ID
        /// 起飞时间
        /// 返回符合条件的机票实体集合
        [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)为客户;

完整代码案例下载地址

你可能感兴趣的:(设计模式,创建型)