彬月论坛
UI层:
(new FavoriteService()).Append(this.TopicID, Visitor.Current.NickName);
业务逻辑层:
public void Append(int topicID, string nickName)
{
if (topicID <= 0 || nickName == null || nickName == "")
return;
this.DriveFavoriteTask().Append(topicID, nickName);
}
/// <summary>
/// 驱动收藏夹数据库任务
/// </summary>
/// <returns></returns>
private IFavoriteTask DriveFavoriteTask()
{
return DBTaskDriverBase.Instance.DriveFavoriteTask();
}
数据访问层接口定义:
void Append(int topicID, string nickName);
SQLServer数据访问层:
public void Append(int topicID, string nickName)
{
if (topicID <= 0 || nickName == null || nickName == "")
return;
MySqlParamCollection parameters = new MySqlParamCollection();
// 设置主题编号
parameters.Add("@TopicID", SqlDbType.Int).Value = topicID;
// 设置用户名称
parameters.Add("@NickName", SqlDbType.NVarChar, 20).Value = nickName;
// 执行 SQL 查询
SQLHelper.ExecuteNoneQuery(SQL_APPEND, CommandType.StoredProcedure, parameters.ToArray());
}
数据层的抽象工厂:
/// <summary>
/// 获取数据库任务驱动实例
/// </summary>
/// <returns></returns>
public static DBTaskDriverBase Instance
{
get
{
if (g_theInstance != null)
return g_theInstance;
lock (typeof(DBTaskDriverBase))
{
if (g_theInstance == null)
{
Type type = Type.GetType(SystemConfManager.Context.DALConf.ActiveProvider.DBTaskDriver);
// 建立 DBTaskDriverBase 数据库任务驱动实例
DBTaskDriverBase instance = Activator.CreateInstance(type) as DBTaskDriverBase;
g_theInstance = instance;
}
}
// 返回数据库任务驱动实例
return g_theInstance;
}
}
public abstract IFavoriteTask DriveFavoriteTask();
这其中还有掌管接口实例的DBTaskDriver
public override IFavoriteTask DriveFavoriteTask()
{
return new FavoriteTask();
}
我们在看一下PetShop的代码
UI层:
//get category id
string categoryKey = Request.QueryString["categoryId"];
//bind data
Product product = new Product();
productsList.DataSource = product.GetProductsByCategory(categoryKey);
productsList.DataBind();
业务逻辑层:
private static readonly IProduct dal = PetShop.DALFactory.DataAccess.CreateProduct();
public IList<ProductInfo> GetProductsByCategory(string category) {
// Return new if the string is empty
if(string.IsNullOrEmpty(category))
return new List<ProductInfo>();
// Run a search against the data store
return dal.GetProductsByCategory(category);
}
数据访问层接口定义:
IList<ProductInfo> GetProductsByCategory(string category);
SQLServer数据访问层:
public IList<ProductInfo> GetProductsByCategory(string category) {
IList<ProductInfo> productsByCategory = new List<ProductInfo>();
SqlParameter parm = new SqlParameter(PARM_CATEGORY, SqlDbType.VarChar, 10);
parm.Value = category;
//Execute a query to read the products
using (SqlDataReader rdr = SqlHelper.ExecuteReader(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_Select_PRODUCTS_BY_CATEGORY, parm)) {
while (rdr.Read()) {
ProductInfo product = new ProductInfo(rdr.GetString(0), rdr.GetString(1), rdr.GetString(2), rdr.GetString(3), rdr.GetString(4));
productsByCategory.Add(product);
}
}
return productsByCategory;
}
数据层的抽象工厂:
private static readonly string path = ConfigurationManager.AppSettings["WebDAL"];
public static PetShop.IDAL.IProduct CreateProduct() {
string className = path + ".Product";
return (PetShop.IDAL.IProduct)Assembly.Load(path).CreateInstance(className);
}
我们分析一下,二者实现上的区别:
PetShop在业务逻辑层中,使用了一个单利,为了不重复建立具体的数据访问层对象,然后,在中间层是调用数据访问层的同名函数,其跟冰月论坛在SQLServer数据访问层上基本相同!只是在数据层的抽象工厂有一些差别!
在彬月论坛中,业务逻辑层使用return DBTaskDriverBase.Instance.DriveFavoriteTask(),DriveXXXTask() 来建立一个具体的接口实例,而 PetShop 则是使用不同的工厂方法,来建立不同的接口实例!使用PetShop这种方式会在配置文件里写比较多的配置信息。而彬月论坛只写一个配置信息,就可以产生不同的接口实例,不是直接产生某个接口的实例,而是先产生一个被我称之为 DBTaskDriver 的东西,你可以把它视作掌管接口实例的大总管。要想建立接口实例,先得建立这个大总管,然后再由它来建立具体的接口实例。虽然大总管具备建立具体接口的能力,但是他并不能知道到底真的要建立具体哪个实例?所以,只好将他这种能力抽象化,他变成了一个抽象的大总管,而且建立具体接口的能力被推迟到了具体的数据访问层里。这样,我只需要知道:1. 我呼叫大总管, 2. 大总管告诉具体的接口实例,而不是,我呼叫工厂类里的每个具体的工厂!在抽象大总管中,覆盖数据层的抽象工厂里的抽象类!