时间:2016-9-27来源:本站原创作者:佚名

在上一篇关于设计模式的图文“利用C#实现Strategy策略模式”中,我们留下了一个念想:通过简单工厂模式与Strategy模式的组合能够更好的实现客户端与实际操作算法之间的解耦合,减轻客户端的职责,但简单工厂模式把客户端关于算法策略的选择放到Context中,通过传递的参数,在switch中决定程序要使用的算法策略。这样当扩展算法策略后,该Context中需要对switch增加分支以便包容新增添的算法策略,客户端若要使用该算法也需要进行相应的修改。对于程序员来说,这样的代码是无法忍受的,也不符合我们的开闭原则。既然发现问题,就一定能够有办法解决,下面介绍的AbstractFactory抽象工厂模式可以提供解决之道,希望大家细细品味。

抽象工厂模式

“在我们的代码中时时刻刻都充斥着创建对象,但是你曾经有无思考过,你的对象可以这么创建,也可以那么创建。同时还可以随时随刻切换。这是不是难以置信?我们将通过各种创建型模式来挖掘其中的奥秘。”

场景1:

人物:大鸟、小菜

“我本来写好了一个项目,是给一家企业做的电子商务网站,是用SQLServer作为数据库的,应该说上线后除了开始有些小问题,基本都还可以。而后,接到另外一家公司类似需求的项目,但这家公司想省钱,租用了一个空间,只能用Access,不能用SQLServer,于是要求我改造原来那个项目的代码。”

“哈哈,你的麻烦来了。”

“是呀,那是相当的麻烦。但开始我觉得很简单呀,因为地球人都知道,SQLServer和Access在ADO.NET上的使用是不同的,在SQLServer上用的是System.Data.SqlClient命名空间下的SqlConnection、SqlCommand、SqlParameter、SqlDataReader、SqlDataAdapter,而Access则要用System.Data.OleDb命名空间下的相应对象,我以为只要做一个全体替换就可以了,哪知道,替换后,错误百出。”

“那是一定的,两者有不少不同的地方。你都找到了些什么问题?”

“实在是多呀。在插入数据时Access必须要insertinto而SQLServer可以不用into的;SQLServer中的GetDate()在Access中没有,需要改成Now();SQLServer中有字符串函数Substring,而Access中根本不能用,我找了很久才知道,可以用Mid,这好像是VB中的函数。”

“小菜还真犯了不少错呀,insertinto这是标准语法,你干吗不加into,这是自找的麻烦。”

“这些问题也就罢了,最气人的是程序的登陆代码,老是报错,我怎么也找不到出了什么问题,搞了几个小时。最后才知道,原来Access对一些关键字,例如password是不能作为数据库的字段的,如果密码的名字是password,SQLServer中什么问题都没有,运行正常,在Access中就是报错,而且报得让人莫名其妙。”

“‘关键字’应该要用‘[’和‘]’包起来,不然当然是容易出错的。”

“就这样,今天加班到这时候才回来。”

“以后你还有的是班要加了。”

“为什么?”

“只要网站要维护,比如修改或增加一些功能,你就得改两个项目吧,至少在数据库中做改动,相应的程序代码都要改,甚至和数据库不相干的代码也要改,你既然有两个不同的版本,两倍的工作量也是必然的。”

“是呀,如果那一天要用Oracle数据库,估计我要改动的地方更多了。”

“那是当然,Oracle的SQL语法与SQLServer的差别更大。你的改动将是空前的。”

“大鸟只会夸张,哪有这么严重,大不了再加两天班就什么都搞定了。”

“哼”,大鸟笑着摇摇头,很不屑一顾,“菜鸟程序员碰到问题,只会用时间来摆平,所以即使整天加班,老板也不想给菜鸟加工资,原因就在于此。”

“你什么意思嘛!”小菜气道,“我是菜鸟我怕谁。”接着又拉了拉大鸟,“那你说怎么搞定才是好呢?”

场景2:

人物:大鸟、小菜

“你先写一段你原来的数据访问的做法给我看看。”

“那就用,‘新增用户’和‘得到用户’为例吧。”

代码见:AbstractFactory_Level1

“这里之所以不能换数据库,原因就在于SqlServerUsersu=newSqlServerUser()使得su这个对象被框死在SQLServer上了。如果这里是灵活的,专业的说法,是多态的,那么在执行’su.Insert(user);’和’su.GetUser(1)’时就不用考虑是用SQLServer还是用Access。”

“我明白你的意思了,你是希望我用‘工厂方法模式’来封装newSqlServerUser()所造成的变化?”

“工厂方法模式是定义一个用于创建对象的接口,让子类决定实例化哪一个类。来试试看吧。”

利用工厂方法模式实现

人物:大鸟、小菜

代码见:AbstractFactory_Level2

“现在如果要换数据库,只需要把newSqlServerFactory()改成newAccessFactory(),此时由于多态的关系,使得声明IUser接口的对象iu事先根本不知道是在访问哪个数据库,却可以在运行时很好地完成工作,这就是所谓业务逻辑与数据访问的解耦。”

“但是,大鸟,这样写,代码里还是有指明‘newSqlServerFactory()’呀,我要改的地方,依然很多。”

“这个先不急,待会再说,问题没有完全解决,你的数据库里不可能只有一个User表吧,很可能有其他表,比如增加部门表(Department表),此时如何办呢?”

利用抽象工厂模式实现

人物:大鸟、小菜

代码见:AbstractFactory_Level3

“大鸟,这样就可以做到,只需要更改IFactoryfactory=newAccessFactory()为IFactoryfactory=newSqlServerFactory(),就实现了数据库访问的切换了。”

“这里我们其实就是公开了一个IFactory接口以及IUser、IDepartment两个针对数据库表单的接口,给用户使用,而我们程序的内部会决定采用哪种方式。这样的好处就是我们将低层的实现以及类名都隐藏了,同时客户使用的时候只需要







































北京白癜风医院在哪里
最权威的白癜风医院

转载请注明原文网址:http://www.helimiaopu.com/cxtx/953.html

------分隔线----------------------------