MyMSDNTVLibrary ( http://blog.joycode.com/musicland/posts/13776.aspx ) 是我以前写的一个小型 WinForms 项目 ,当时的想法是为初学者们演示如何创建一个简单但却完整的小项目。很多朋友都对这个简单的小东西很感兴趣,西安的一位朋友在看着源码重新做了一遍之后,甚至还自己增加了添加 TV 的新功能。这让我感到非常欣慰。
正好最近又复习了一遍设计模式,我开始重新审视原有的应用程序结构,发现了一些应该改进的地方。比如说,我在写 MyMSDNTVLibrary 的第一个版本时就非常想让它能够很方便地支持不同种类的数据源,例如 Access 、 SQL Server ,甚至是单纯的 XML 。我知道实现起来并不难,但怎样做才能最有效最有利于代码复用?想来想去,我决定在数据访问这一部分应用 Factory Method 模式。
Factory Method 是 GOF 在 Design Pattersn 一书中给出的一种模式, GOF 为它做出的定义是:
Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
简单来说, Factory Method 的目的是想创建几个相似的(实现同一接口或继续同一父类)类中的某一个,为了达到这一目的,需要创建几个相似的 creator 类,通过 creator 类来决定创建哪一个所需的对象类。它的 UML 图示如下:
具体到这个项目来说,我需要针对不同的数据源来创建几个不同的 DBHelper (我的个人习惯是通过 DBHelper 来封装针对特定的数据源的访问动作),如 OleDBHelper 、 SqlDBHelper 等,这些 Helper 有非常相近的结构,因此可以让它们继续于同一接口—— IDBHelper 。 IDBHelper 的定义如下:
using System;
using System.Data;
namespace musicland.MSDNTVLibrary.Component
{
public interface IDBHelper
{
DataSet GetAll();
}
}
注意其中给出了一个有待实现的方法 GetAll ,通过实现类对该方法的调用,可以获得应用程序所需的全部数据。
接下来就是从 IDBHelper 继续而来的两个具体数据访问辅助类。
**
OleDBHelper : **
using System;
using System.Configuration;
using System.Data;
using System.Data.OleDb;
namespace musicland.MSDNTVLibrary.Component
{
// This is the helper class that will interact with OleDB for info.
internal class OleDBHelper: IDBHelper
{
private OleDbConnection conn;
public OleDBHelper()
{
conn= new OleDbConnection(ConfigurationSettings.AppSettings["OleConnectionString"]);
}
public DataSet GetAll()
{
OleDbDataAdapter da= new OleDbDataAdapter("select * from Episode order by Date desc", conn);
DataSet ds= new DataSet();
try
{
da.Fill(ds, "Episode");
}
catch (OleDbException ex)
{
throw ex;
}
finally
{
if (conn.State!=ConnectionState.Closed)
conn.Close();
}
return ds;
}
}
}
**
SqlDBHelper : **
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
namespace musicland.MSDNTVLibrary.Component
{
// This is the helper class that will interact with SqlServer for info.
internal class SqlDBHelper: IDBHelper
{
SqlConnection conn;
public SqlDBHelper()
{
conn= new SqlConnection(ConfigurationSettings.AppSettings["SqlConncectionString"]);
}
public DataSet GetAll()
{
SqlCommand cmd= new SqlCommand("GetAll", conn);
cmd.CommandType=CommandType.StoredProcedure;
SqlDataAdapter da= new SqlDataAdapter(cmd);
DataSet ds= new DataSet();
try
{
conn.Open();
da.Fill(ds, "Episode");
}
catch (SqlException ex)
{
throw ex;
}