幸运星空

Lucker的程序人生

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

前言

在三层结构中,数据库是最底层,负责对数据库的操作,如添加,删除,修改数据等.上一篇中最后一幅图"各项目相互之间的关系和调用图"也清晰的反映出了这一点.从图中我们还可以发现,DAL中大量的采用了"Factory"的形式.到底什么是"Factory"呢?,"Factory"在DAL中起到什么样的作用呢?带着这些疑问我们开始吧.

工厂模式

设计模式是一门专门的学科,也是需要在实践中不断积累的经验,目前流行的的设计模式很多,其中最简单的可能要属"工厂模式"了.

工厂模式最主要的特点就是工厂类(A)根据调用者传递过来的参数(P)形式,通过智能分析判断,选择返回一组拥有共同父类(F)的子类(F1,F2...)中的一个的实例,其中每个子类针对父类完成不同的操作,即工厂类根据条件创建不同的子类,以完成不同的工作.工厂模式的原型如下图所示:

image

PetShop 4系统中的工厂模式

Petshop 4中大量运用了工厂设计模式,项目名称中以"Factory"结尾的都是抽象的工厂类,如下:

  • DALFactory:数据访问层的抽象工厂(决定创建哪种数据库类型的数据访问层。可以选择:SQLServer,Oracle)
  • CacheDependencyFactory:缓存依赖类的工厂类。(创建具体表的缓存依赖)
  • MessagingFactory :异时处理消息队列的抽象工厂(反射创建具体的异时处理类)
  • ProfileDALFactory:ProfileDAL的工厂类(反射选择创建Oracle 和SQL Server的 ProfileDAL)

以DALFactory为例,当用户访问数据库时,用户调用DALFactory类,DALFactory类根据用户使用的数据库的类型,决定是实例化SQLServerDAL还是OracleDAL,而这两个DAL类都继承自IDAL类,当实例类完成操作后,返回IDAL类.这样,对于用户来说,不管使用的是什么类型的数据库,调用方法和返回结果都是一样的.这样做的好处就非常明显了:当由SQLServer数据库切换来Oracle数据库上时,不需要修改任何程序.

数据层的数据访问

前面简单了解了一下PetShop4系统中的工厂模式,在DALFactory类中,有一个重要的父类:IDAL类,它是实现数据访问的接口集合.首先来了解一下接口的定义:接口只是一种约束形式,它中包括成员的定义,而不定义成员的具体实现.也就是说,接口只是一个具有成员框架的空壳子.它必须被继承,并在继承类中实现成员的内容.接口的主要目的是为不相关的类提供一个通用的处理服务.它可以实现多继承.

在IDAL的接口中,定义了全部数据库访问所需要的方法.但是是在SQLServerDAL和OracleDAL两个类中去实现的.这样做的好处是有利于实现数据封装的安全性和有利于将来的扩展.

IDAL类中的5个数据访问接口

接口名 所在的.cs文件名 说明
ICategory ICategory.cs 定义对商品类别的访问方法
IInventory IInventory.cs 定义对商品数量的访问方法
IItem IItem.cs 定义对商品详细信息的访问方法
IOrder IOrder.cs 定义对订单的访问方法
IProduct IProduct.cs 定义对商品的访问方法

以IProduct接口为例:

    /// <summary>
    /// Interface for the Product DAL
    /// </summary>
    public interface IProduct{
        /// <summary>
        /// Method to search products by category name
        /// </summary>
        /// <param name="category">Name of the category to search by</param>
        /// <returns>Interface to Model Collection Generic of search results</returns>
        IList<ProductInfo> GetProductsByCategory(string category);   

        /// <summary>
        /// Method to search products by a set of keyword
        /// </summary>
        /// <param name="keywords">An array of keywords to search by</param>
        /// <returns>Interface to Model Collection Generic of search results</returns>
        IList<ProductInfo> GetProductsBySearch(string[] keywords);

        /// <summary>
        /// Query for a product
        /// </summary>
        /// <param name="productId">Product Id</param>
        /// <returns>Interface to Model ProductInfo for requested product</returns>
        ProductInfo GetProduct(string productId);
    }

注:

  1. 大家在查看这些接口定义的时候,会发出文件中仍然保留了命名空间的形式,其实,在ASP.NET3.5中,已经取消了显示的命名空间.
  2. 接口定义的代码中还使用了泛形.关于泛开的知识,我自己还有待加强.

SQLServerDAL的实现

SQLServerDAL中的Product类将SQL语句和其参数定义成了多个常量,这样更于维护,仔细分析这些常量,发现它们的组合非常灵活,可以方便的实现多种条件下的查询,比如按类别,按ID号,还可以按名称和类别ID来模糊查询等.

//Static constants
private const string SQL_SELECT_PRODUCTS_BY_CATEGORY = "SELECT Product.ProductId, Product.Name, Product.Descn, Product.Image, Product.CategoryId FROM Product WHERE Product.CategoryId = @Category";
private const string SQL_SELECT_PRODUCTS_BY_SEARCH1 = "SELECT ProductId, Name, Descn, Product.Image, Product.CategoryId FROM Product WHERE ((";
private const string SQL_SELECT_PRODUCTS_BY_SEARCH2 = "LOWER(Name) LIKE '%' + {0} + '%' OR LOWER(CategoryId) LIKE '%' + {0} + '%'";
private const string SQL_SELECT_PRODUCTS_BY_SEARCH3 = ") OR (";
private const string SQL_SELECT_PRODUCTS_BY_SEARCH4 = "))";
private const string SQL_SELECT_PRODUCT = "SELECT Product.ProductId, Product.Name, Product.Descn, Product.Image, Product.CategoryId FROM Product WHERE Product.ProductId  = @ProductId";
private const string PARM_CATEGORY = "@Category";
private const string PARM_KEYWORD = "@Keyword";
private const string PARM_PRODUCTID = "@ProductId";

Product类通过几个方法来实现功能:

  • public IList<ProductInfo> GetProductsByCategory(string category)// Query for products by category
  • public IList<ProductInfo> GetProductsBySearch(string[] keywords)// Query for products by keywords. The results will include any product where the keyword appears in the category name or product name
  • public ProductInfo GetProduct(string productId)// Query for a product

在方法实现的过程中,用到了MS的一个数据库访问助手:SqlHelper类(或OracleHelper类),关于SqlHelper类的介绍,在我以前的博文中就过说明,有兴趣的朋友的可以找到了解一下.

OracleDAL的实现和SQLServerDAL相似,这里不再多加阐述.

DALFactory的实现

DALFactory中,一个重要的方面就是判断使用的数据库类型,这个工作是由DaraAccess类来完成的.该类中一个重要的静态变量path如下:

// Look up the DAL implementation we should be using
private static readonly string path = ConfigurationManager.AppSettings["WebDAL"];

ConfigurationManager是专门来用获取Web.congig文件中节点信息的类,path来自于AppSettings结点的WebDAL项目.打开Web.config文件,可以找到:

<add key="WebDAL" value="PetShop.SQLServerDAL"/>

这个WebDAL项目指明了当前使用的数据库的类型.修改它就可以修改下面要实例化的DAL类了.

DALFactory判断了要实例化的类,那又是怎么实施实例化的呢?

在DaraAccess类中,有5个与IDAL类中名称相似的类.它们就是用来实例化IDAL中的接口的方法.以CreateCategory方法为例:

public static PetShop.IDAL.ICategory CreateCategory() {
    string className = path + ".Category";
    return (PetShop.IDAL.ICategory)Assembly.Load(path).CreateInstance(className);
}

上面的返回值很值得研究:

  • 首先,采用了强制类型转换,将返回结果转换成ICagegory类型.
  • 其次,使用Load来加载指定的数据库处理类.
  • 最后,使用CreateInstance方法,从程序集中查找指定的类型,然后创建它的实例.
posted on 2008-12-17 13:58  Lucker  阅读(552)  评论(0编辑  收藏  举报