技术开发 频道

浅析设计模式之工厂方法

DotNet中的工厂方法 


    ADO.net 2.0中微软在原来的IDBConnection和具体实现 如 SqlConnection等之间增加了一个抽象类DBConnection,将一些重复东西放到这个抽象层。DBConnection里有个CreateCommand,这就是一个工厂方法,由于有了这个方法的存在我们可以写出这样的代码:

public override User GetUserByUserName(string userName) { using (DbConnection conn = GetConnection()) { User u; using (DbCommand comm = conn.CreateCommand()) { comm.CommandType = CommandType.Text; comm.CommandText = GETUSERBYUSERNAME_TRAP_USER; SetUserNameParam(userName, comm); conn.Open(); using (DbDataReader reader = comm.ExecuteReader(CommandBehavior.CloseConnection)) { if (!reader.Read()) return null; u = new User(); u.UserId = reader["userid"].ToString(); u.UserName = reader["uname"].ToString(); u.UserPwd = reader["pwd"].ToString(); reader.Close(); } comm.Parameters.Clear(); } conn.Close(); return u; } }



    你看得出来这是针对那种数据的实现么?看不出吧,实现了数据库无关性,将变与不变分开了,客户程序面对着稳定的接口。

工厂方法在DotNet中的演进

    我们可以利用反射机制化解switch语句的泥潭,在上面可口可乐的例子中我们可以给工厂方法传入一个类的限定名利用反射产生实例,去掉switch语句。这样还可以去掉子类了。 


    实现如下:

public class Creator ……………… public 广告纸 Get广告纸(string className) { Assembly asm = Assembly.LoadFrom(className+”.dll”); 广告纸 o = asm.CreateInstance (className) as 广告纸; return o; }


 


    但是使用反射就失去了编译器的强类型检查,如果传入一个错误的字符串这个问题只有等到运行时刻才能发现,能不用就不用了。.net 2.0中我们有了泛型,在这里我们可以用泛型来解决这个问题了。 


    另一个实现如下:
public class Creator<T> { public 广告纸 Get广告纸() { return new T(); } }

 

    上面所说的两种演进虽然已经失去了工厂方法模式原来的型构,但依然得到我们想要的:封装变化,为客户程序提供稳定的接口,不将需求的变化扩散到客户程序。所以说模式是灵活的,模式要这么多模式要表达的是她们的思想并不是模式的实现形式。

工厂方法和其他模式的关系 

    与抽象工厂模式:抽象工厂模式实际上是包含了很多工厂方法的特例,抽象工厂模式就是将这些工厂方法阻止起来,利用这些工厂方法创建一系列相关的对象。 

    模板方法:上一篇中(http://tech.it168.com/m/2007-09-19/200709191421700.shtml,《浅析设计模式之模板方法》)我们描述了模板方法模式,实现模板方法算法中的每一小步就是工厂方法了。

总结 

    在这一篇中我们引出了软件开发的真谛:寻找变化,封装变化。其实我们学习OO,学习设计模式要达到的就是这个目的。将变与不变相分离,将以后的维护点统一、集中起来,不让变化分散在各处。在敏捷开发中有一个名言:拥抱变化。是的,我们不能避免软件开发中的变,如果没有变,我想软件开发也失去了她灿烂的色彩。但是我们可以隔离变化,勇敢的面对这些变化才会演绎出软件之美,才造就了GoF、Martin Folwer这些大家。

0
相关文章