• 网络学院
  • IT资讯
  • 操作系统
  • 网络技术
  • 软件应用
  • 办公软件
  • 编程技术
  • 网站架设
  • 数据库类
  • 平面设计
  • 多媒体类
  • 游戏资讯
  • 教学论文
  • 认证考试
封装的变化之封装对象创建的变化
  站点:
  • 首 页
  • 最新软件
  • 文章教程
  • 国内软件
  • 国外软件
  • 绿色软件
  • 源码下载
  • 字体下载
封装的变化之封装对象创建的变化
软件发布 封装的变化之封装对象创建的变化
网络软件 系统工具 应用软件 联络聊天 图形图像 多媒体类 行业软件 游戏娱乐 编程开发 安全相关 教育教学 数码软件 绿软下载
热门软件: QQ 瑞星 pplive e话通 木马克星 千千静听 office2000 五笔字根 Photoshop 视频分割
返回文章教程首页 >> 认证考试 >> 系统工程师 >> 封装的变化之封装对象创建的变化

封装的变化之封装对象创建的变化

添加时间: 2007-4-9 2:51:26  作者: 系统工程师认证参考  阅读次数:34   来源: http://www.d9soft.com

       

 
考虑一个日志记录工具。目前需要提供一个方便的日志api,使得客户可以轻松地完成日志的记录。该日志要求被记录到指定的文本文件中,记录的内容属于字符串类型,其值由客户提供。我们可以非常容易地定义一个日志对象:
  public class log
{
 public void write(string target, string log)
 {
  //实现内容;
 }
}

  当客户需要调用日志的功能时,可以创建日志对象,完成日志的记录:
  log log = new log();
log.write(“error.log”, “log”);

  然而随着日志记录的频繁使用,有关日志的文件越来越多,日志的查询与 管理 也变得越不方便。此时,客户提出,需要改变日志的记录方式,将日志内容写入到指定的数据表中。显然,如果仍然按照前面的设计,具有较大的局限性。 现在我们回到设计之初,想象一下对于日志api的设计,需要考虑到这样的变化吗?这里存在两种设计理念,即渐进的设计和计划的设计。从本例来分析,要求设计者在设计初就考虑到日志记录方式在未来的可能变化,并不容易。再者,如果在最开始就考虑全面的设计,会产生设计上的冗余。因此,采用计划的设计固然具有一定的前瞻性,但一方面对设计者的要求过高,同时也会产生一些缺陷。那么,采用渐进的设计时,遇到需求变化时,利用重构的方法,改进现有的设计,又需要考虑未来的再一次变化吗?这是一个见仁见智的问题。对于本例而言,我们完全可以直接修改write()方法,接受一个类型判断的参数,从而解决此问题。但这样的设计,自然要担负因为未来可能的再一次变化,而导致代码大量修改的危险,例如,我们要求日志记录到指定的xml文件中。

  所以,变化是完全可能的。在时间和技术能力允许的情况下,我更倾向于将变化对设计带来的影响降低到最低。此时,我们需要封装变化。

  在封装变化之前,我们需要弄清楚究竟是什么发生了变化?从需求看,是日志记录的方式发生了变化。从这个概念分析,可能会导致两种不同的结果。一种情形是,我们将日志记录的方式视为一种行为,确切的说,是用户的一种请求。另一种情形则从对象的角度来分析,我们将各种方式的日志看作不同的对象,它们调用接口相同的行为,区别仅在于创建的是不同的对象。前者需要我们封装“用户请求的变化”,而后者需要我们封装“日志对象创建的变化”。

  封装“用户请求的变化”,在这里就是封装日志记录可能的变化。也就是说,我们需要把日志记录行为抽象为一个单独的接口,然后才分别定义不同的实现。如图一所示:

图一:封装日志记录行为的变化

  如果熟悉设计模式,可以看到图一所表示的结构正是command模式的体现。由于我们对日志记录行为进行了接口抽象,用户就可以自由地扩展日志记录的方式,只需要实现ilog接口即可。至于log对象,则存在与ilog接口的弱依赖关系:
  public class log
{
 private ilog log;
 public log(ilog log)
 {
  this.log = log;
 }
 public void write(string target, string logvalue)
 {
  log.execute(target, logvalue);
 }
}

  我们也可以通过封装“日志对象创建的变化”实现日志api的可扩展性。在这种情况下,日志会根据记录方式的不同,被定义为不同的对象。当我们需要记录日志时,就创建相应的日志对象,然后调用该对象的write()方法,实现日志的记录。此时,可能会发生变化的是需要创建的日志对象,那么要封装这种变化,就可以定义一个抽象的工厂类,专门负责日志对象的创建,如图二所示:
 
图二:封装日志对象创建的变化

  图二是factory method模式的体现,由抽象类logfactory专门负责log对象的创建。如果用户需要记录相应的日志,例如要求日志记录到数据库,需要先创建具体的logfactory对象:
  logfactory factory = new dblogfactory();

  当在应用程序中,需要记录日志,那么再通过logfactory对象来获取新的log对象:
  log log = factory.create();
log.write(“errorlog”, “log”);

  如果用户需要改变日志记录的方式为文本文件时,仅需要修改logfactory对象的创建即可:
  logfactory factory = new txtfilelogfactory();

  为了更好地理解“封装对象创建的变化”,我们再来看一个例子。假如,我们需要设计一个数据库组件,它能够访问 微软 的sql server数据库。根据ado.net的知识,我们需要使用如下的对象:sqlconnection, sqlcommand, sqldataadapter等。

  如果仅就sql server而言,在访问数据库时,我们可以直接创建这些对象:
  sqlconnection connection = new sqlconnection(strconnection);
sqlcommand command = new sqlcommand(connection);
sqldataadapter adapter = new sqldataadapter();

  如果在一个数据库组件中,充斥着如上的语句,显然是不合理的。它充满了僵化的坏味道,一旦要求支持其他数据库时,原有的设计就需要彻底的修改,这为扩展带来了困难。

  那么我们来思考一下,以上的设计应该做怎样的修改?假定该数据库组件要求或者将来要求支持多种数据库,那么对于connection,command,dataadapter等对象而言,就不能具体化为sql server的对象。也就是说,我们需要为这些对象建立一个继承的层次结构,为他们分别建立抽象的父类,或者接口。然后针对不同的数据库,定义不同的具体类,这些具体类又都继承或实现各自的父类,例如connection对象:

图三:connection对象的层次结构

  我为connection对象抽象了一个统一的iconnection接口,而支持各种数据库的connection对象都实现了iconnection接口。同样的,command对象和dataadapter对象也采用了相似的结构。现在,我们要创建对象的时候,可以利用多态的 原理 创建: iconnection connection = new sqlconnection(strconnection);

  从这个结构可以看到,根据访问的数据库的不同,对象的创建可能会发生变化。也就是说,我们需要设计的数据库组件,以现在的结构来看,仍然存在无法应对对象创建发生变化的问题。利用“封装变化”的原理,我们有必要把创建对象的责任单独抽象出来,以进行有效地封装。例如,如上的创建对象的代码,就应该由专门的对象来负责。我们仍然可以建立一个专门的抽象工厂类dbfactory,并由它负责创建connection,command,dataadapter对象。至于实现该抽象类的具体类,则与目标对象的结构相同,根据数据库类型的不同,定义不同的工厂类,类图如图四所示:

图四:dbfactory的类图

  图四是一个典型的abstract factory模式的体现。类dbfactory中的各个方法均为abstract方法,所以我们也可以用接口来代替该类的定义。继承dbfactory类的各个具体类,则创建相对应的数据库类型的对象。以sqldbfactory类为例,创建各自对象的代码如下:
  public class sqldbfactory: dbfactory
{
 public override iconnection createconnection(string strconnection)
 {
  return new sqlconnection(strconnection);
 }
 public override icommand createcommand(iconnection connection)
 {
  return new sqlcommand(connection);
 }
 public override idataadapter createdataadapter()
 {
  return new sqldataadapter();
 }
}

  现在要创建访问sql server数据库的相关对象,就可以利用工厂类来获得。首先,我们可以在程序的初始化部分创建工厂对象:
  dbfactory factory = new sqldbfactory();

  然后利用该工厂对象创建相应的connection,command等对象:
  iconnection connection = factory.createconnection(strconnection);
icommand command = factory.createcommand(connection);

  由于我们利用了封装变化的 原理 ,建立了专门的工厂类,以封装对象创建的变化。可以看到,当我们引入工厂类后,connection,command等对象的创建语句中,已经成功地消除了其与具体的数据库类型相依赖的关系。在如上的代码中,并未出现sql之类的具体类型,如sqlconnection、sqlcommand等。也就是说,现在创建对象的方式是完全抽象的,是与具体实现无关的。无论是访问何种数据库,都与这几行代码无关。至于涉及到的数据库类型的变化,则全部抽象到dbfactory抽象类中了。需要更改访问数据库的类型,我们也只需要修改创建工厂对象的那一行代码,例如将sql server类型修改为oracle类型:
  dbfactory factory = new oracledbfactory();

  很显然,这样的方式提高了数据库组件的可扩展性。我们将可能发生变化的部分封装起来,放到程序固定的部分,例如初始化部分,或者作为全局变量,更可以将这些可能发生变化的地方,放到配置文件中,通过读取配置文件的值,创建相对应的对象。如此一来,不需要修改代码,也不需要重新编译,仅仅是修改xml文件,就能实现数据库类型的改变。例如,我们创建如下的配置文件:
  <appsettings>
 <add key=”db” value=”sqldbfactory”/>
</appsettings>

  创建工厂对象的代码则相应修改如下:
  string factoryname = configurationsettings.appsettings[“db”].tostring();
//dblib为数据库组件的程序集:
dbfactory factory = (dbfactory)activator.createinstance(“dblib”,factoryname).unwrap();

  当我们需要将访问的数据库类型修改为oracle数据库时,只需要将配置文件中的value值修改为“oracledbfactory”即可。这种结构具有很好的可扩展性,较好地解决了未来可能发生的需求变化所带来的问题。

 

上下文章:

 

上一篇文章: 封装的变化之不断变化的需求 下一篇文章: 极限编程(XP)的有效实践

相关文章:

  • IGN评价:《红色警戒3》的本质从未变化过
  • Mac和Linux将成为黑客的攻击对象
  • 如何手动创建oracle数据库
  • VB.net2008创建发送与接收端程序
  • 界面变化大 WLM9 Wave 3亮点速览

相关软件:

  • 一键封装工具Dprep 5.0.0707 简体中文绿色版
  • 虚拟DOS引导系统创建工具 V6.0 简体绿色版
  • 深度系统封装部署工具 2.3 简体中文绿色版
  • 万能驱动包(封装专用) V7.10 简体中文版
  • 虚拟DOS引导系统创建工具 V6.2
  • PHP&MySQL无需编程轻松创建数据库网站 v2.0

 

快速导航

  • 网络学院
  • 精品汇聚
  • 字体下载
  • 教程下载
  • ASP源码
  • PHP源码
  • Net源码
  • JSP 源码

认证考试分类导航

  • 微软认证
  • 计算机等级考试
  • 软件水平考试
  • 思科认证
  • Oracle认证
  • Linux认证
  • JAVA认证
  • 网络工程师
  • 系统工程师
  • 程序员

本类经典文章推荐

  • SQLServer的安全检查
  • 系统设计师资格与水平考纲 (原高级...
  • 系统分析员备考之ISO9000系列基础...
  • 开发数据库的WEB查询
  • 在builder中向Excel传递数据
  • 用Powerbuilder开发WEB数据库
  • PowerBuilder制作IE风格的图标按钮
  • PowerBuilder编程技巧四则
  • 小议数据库主键选取策略
  • 跨数据库文献检索统一平台的实现

系统工程师阅读排行

  • 数据库原理各章节简答题总结
  • 利用C++Builder6.0开发简单的车辆...
  • 数据库系统工程师下午试卷
  • 跨数据库文献检索统一平台的实现
  • 项目进度的黑洞——已完成90%
  • 用Powerbuilder开发WEB数据库
  • 系统设计师资格与水平考纲 (原高级...
  • 小议数据库主键选取策略
  • 系统分析员备考之ISO9000系列基础...
  • 数据库系统工程师全真预测试卷(一...

认证考试阅读总排行

  • 全国计算机等级考试一级模拟试题01
  • 全国计算机等级考试一级模拟试题10
  • 全国计算机等级考试一级模拟试题08
  • MCSD简介
  • 全国计算机等级考试一级考试最新模...
  • 全国计算机等级考试一级模拟试题02
  • 全国计算机等级考试一级模拟试题07
  • 全国计算机等级考试上机考试应试技...
  • 一级(WINDOWS)试题解析-Word篇
  • 全国计算机等级考试一级模拟试题06

广告位置

字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 回到顶部

关于我们 | 版权声明 | 免责条款 | 广告联系 | 软件发布 | 下载帮助 | 下载排行 | 网站地图 | 特别鸣谢 | 友情连接

copyright; 2005-2008 D9soft.com 第九软件网 版权所有