设计模式实战:AbstractFactory,Singleton

如果我们要做一个需要能够支持各种数据库的ORM。可以用到AbstractFactorySingleton等设计模式。

我们先分析一下,要实现一个ORM,我们首先需要一个能够和各种不同数据库平台交互的一致的接口,我们把它叫做DBWR,意思就是“数据库读写”。它可以读取数据库中的数据,对数据库执行DDL操作。我们认为它有这些功能:

1、读取数据,以DataTable的形式返回,其原型是:

public DataTable GetData(string Sql);

2、执行Sql语句,并返回受影响的行数,其原型是:

    public int ExecSql(string Sql);

 在实践中,我们经常以参数的形式作为某种条件来读取数据或者把数据写入数据库,这样一是方便,二是安全。因此还应该加上如下函数:

3public DataTable GetData(string Sql, IDataParameter[] Params);

4public int ExecSql(string Sql, IDataParameter[] Params);

另外,我们经常只要从数据库中获取一个值,完全没有必要用DataTable的形式,就用一个object好了。所以我们再加上下面的函数:

5public object GetSingleValue(string Sql);

6public object GetSingleValue(string Sql, IDataParameter [] Params);
    下面是DBWR的简单类图:
  
    

在上面的函数定义中,我们为什么用IDataParameter,而不用SqlParameter呢?请注意,我们的DBWR类是需要与各种支持.net的数据库平台进行交互的,如果用SqlParameter的话,就只能与Sql Server进行交互了。

.net中,对数据库进行连接的通用接口是IDbConnection.执行Sql语句的是IDbCommand,当然还有用来填充IDbCommandParameters属性IDataParameter,当然,如果我们需要更加方面的操作,那就需要一个IDbDataAdapter的实例。但是各数据平台对他们的实现是不同的,不要期望Sql Server能够与Oracle能够统一。我们的DBWR类需要获取这一系列操作数据库的、相关的接口的实例,但是又不知道这些实例的具体的类,怎么办呢?这个时候,就可以用AbstractFactory设计模式来解决这个问题。它的意图就是“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类”。

我们把这个能够为我们提供这些能与不同数据库平台打交道的接口,但又不必指定具体类的工具叫做DbInterfaceGenerator(意思就是“数据库接口生成器”)它有这些功能:

1、获取能够连接数据库的IDbConnection的实例:

public abstract IDbConnection GetConnection();

2、获取能够执行Sql语句的IDbCommand的实例:

public abstract IDbCommand GetCommand();

3、获取IDataParameter的实例:

   A、按参数名称,参数的值获取参数:

public abstract IDataParameter GetParameter(string ParameterName, object ParameterValue);

B、按参数名称,参数的长度,参数的精度,参数的数据库类型的名字,比如“varchar”获取参数:

        public abstract IDataParameter GetParameter(string ParameterName, int? Length, byte? Scale, string DbTypeName);

C、按参数名称,参数的长度,参数的精度,参数的数据库类型的名字,比如“varchar”,参数的值获取参数:

   public abstract IDataParameter GetParameter(string ParameterName, int? Length, byte? Scale, string DbTypeName, object ParameterValue);

   为什么把参数的长度,参数的精度声明为int?呢?因为有时我们并不需要指定参数的长度和精度,这时,就用null代替好了。

4、获取IDbDataAdapter

public abstract IDbDataAdapter GetAdapter();


    下面是的
DbInterfaceGenerator简单类图:
  

那么对应Sql Server数据库,那就是SqlDbInterface,它返回的就是分别是SqlConnectionSqlCommandSqlParameterSqlDataAdapter对应Oracel数据库,那就是OracleDbInterface.它返回的就是OracleConnectionOracleCommandOracleParameterOracleDataAdapter

对其他的数据库,就是XXXDbInterface返回就是对应的Connneciton,Command,ParamterDataAdapter

下面是它们的简单类图:

 不同数据库进行交互的问题解决了,我们又碰到了一个问题,我们的DBWR类每次需要用到DbInterfaceGenerator类某个子类的实例的时候,难道每次都new一个新的实例么?这样做,既不方便,也会影响性能。一般来说,只要我们决定了用哪种数据库,系统一旦启动,就不会再更改。所以我们用以与数据交互的DbInterface只要有一个实例就可以了,它在第一次需要的的时候就生成。可以用Singleton模式达到我们的要求。它的目的就是“保证一个类仅有一个实例,并提供一个访问它的全局访问点”。

我们给DbInterfaceGenerator添加一个能够让其他类可以访问它本身唯一实例的“全局访问点”,叫做DbInterface

改进后的DbInterfaceGenerator 的类图如下:
  
   

对于DBWR类,我们也需要提供一个这样的访问点,叫做Instance。改进后的类图是:
 

我们非常幸运,因为我们使用C#,实现这种Singleton模式,非常容易。两条简单的语句就可以实现DBWRInstance

public static readonly DBWR Instance = new DBWR();

protected DBWR() { }

当然,我们也可以把我们的DBWR类的构造函数申明为private.

不过,对于DbInterfaceGeneratorDbInterface,就没有这么容易了。但也不要紧张,大家注意到public static readonly DBWR的构造函数没有?套用领导们常说的话:“只要抓住了public static readonlyprotected/private 构造函数(){} 这两个基本点,我们的属性就符合Singleton模式了”。其实现如下:

    public static readonly DbInterfaceGenerator DbInterface = GetDbInterface();

    private static DbInterfaceGenerator GetDbInterface()

    {

       string InterfaceType = System.Configuration.ConfigurationManager.AppSettings["DbInterfaceType"];

       string InterfaceAssembly = System.Configuration.ConfigurationManager.AppSettings["DbInterfaceAssembly"];

       if (!string.IsNullOrEmpty(InterfaceType) && !string.IsNullOrEmpty(InterfaceAssembly))

       {

          return (DbInterfaceGenerator)
      System.AppDomain.CurrentDomain.CreateInstance(InterfaceAssembly, InterfaceType).Unwrap();

       }

       return new SqlDbInterface();

    }

        GetDbInterface函数中,我们用到了“反射”,这是.net中一个非常重要的特性,他对于实现工厂方法,提供了“无与伦比的方便”。相关函数还有“Activator.CreateInstance”等。

        如果我们的数据库平台不是Sql Server,那么需要在我们的App.config文件的AppSettings 节中,添加“DbInterfaceType”和“DbInterfaceAssembly”这两个元素。

具体代码因为较长,不便在这里贴出,请参考DongLiORM中的DBWR.cs, DbInterface.cs,SqlDbInterface.cs

参考文件:

TerryLee的《.NET设计模式(2):单件模式(Singleton Pattern)

TerryLee的《.NET设计模式(3):抽象工厂模式(Abstract Factory)

  《设计模式中文版》

posted @ 2007-07-18 19:59 永红 阅读(2555) 评论(19)  编辑 收藏 网摘 所属分类: .Net设计模式

  回复  引用    
#1楼 2007-07-18 21:43 | 中创站长 [未注册用户]
八十年代初,摆个地摊就能发财,可很多人不敢。
九十年代初,买支股票就能挣钱,可很多人不信。
二十一世纪,开个网站就能赚钱,可很多人不试
今天你还在犹豫吗?还在徘徊犹豫不前吗?
前怕狼后怕虎使得你做什么都不会成功,
道理很简单,因为你不懂的抓住时机和敏锐的眼光。
机会就在眼前!努力财富就离你不远!
中创网赚祝你成功!联系咨询QQ:510475424 http://aiq.cctve.cn
  回复  引用  查看    
#2楼 [楼主]2007-07-18 21:46 | 永红      
TO:中创站长
请不要发广告。下次一定会删除。

  回复  引用  查看    
#3楼 [楼主]2007-07-18 21:46 | 永红      
TO ALL,这是技术社区,请不要发广告。
  回复  引用    
#4楼 2007-07-18 21:53 | apple [未注册用户]
学习了
  回复  引用  查看    
#5楼 [楼主]2007-07-18 22:14 | 永红      
TO apple, 与诸君共勉。

  回复  引用  查看    
#6楼 2007-07-18 22:19 | 让风吹--笨牛      
我觉得这样就能支持不同的数据库,只能算是理论上吧。
SQL语句、存储过程就通不过。
  回复  引用    
#7楼 2007-07-18 23:33 | se [未注册用户]
hehe
  回复  引用  查看    
#8楼 [楼主]2007-07-19 08:09 | 永红      
To 让风吹--笨牛:
觉得这样就能支持不同的数据库,只能算是理论上吧。 SQL语句、存储过程就通不过
--------------------------------------
当然不可能支持所有的数据库,但至少支持能支持那些达到了同一个标准(比如Sql 92)的数据库。前提是,使用标准的Sql功能。
当然,现在这样子还不能完全支持,还需要后续的动作,这只不过是我为了说明AbstractFactory和Singleton模式在实践中的应用。
  回复  引用    
#9楼 2007-07-19 08:21 | cobra [未注册用户]
很好的指导性文章,mark。
  回复  引用    
#10楼 2007-07-19 08:47 | lib [未注册用户]
正好要用到。
  回复  引用  查看    
#11楼 2007-07-19 09:21 | Anytao      
理论与实践的结合,博客园需要这样的精品。
  回复  引用  查看    
#12楼 2007-07-19 11:50 | Anders06      
不错,
  回复  引用  查看    
#13楼 [楼主]2007-07-19 12:30 | 永红      
TO cobra, lib, Anytao, Anders06:
谢谢。各位的关注,是我写作的动力。也希望大家能够把自己在实际项目中的经验共享出来,以便大家都能进步。




  回复  引用  查看    
#14楼 2007-07-19 13:01 | yiki      
很好
  回复  引用  查看    
#15楼 [楼主]2007-07-19 21:19 | 永红      
To yiki:谢谢,我会努力的。
  回复  引用    
#16楼 2007-07-20 13:18 | 戈多 [未注册用户]
写的不错
  回复  引用    
#17楼 2007-07-24 12:39 | 过客 [未注册用户]
不错,希望有更多精彩内容
  回复  引用  查看    
#18楼 [楼主]2007-07-24 12:49 | 永红      
谢谢戈多&过客,有大家的支持,我会更加努力。
现在有写了另外的一篇《设计模式实战:组合型模式Composite、Adapter》(http://www.cnblogs.com/Yahong111/archive/2007/07/23/828684.html),欢迎大家拍砖。
  回复  引用  查看    
#19楼 2008-09-01 09:21 | 阿鹏      
very good

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2007-07-24 07:46 编辑过
Google站内搜索

China-pub 计算机图书网上专卖店!6.5万品种 2-8折!
近千种 9-95 新二手计算图书火热销售中!
开发者征途系统新作:《设计模式——基于C#的工程化实现及扩展》



相关文章:

相关链接: