模板方法模式
一、完成者信息
姓名:陈绯
学号:07770230
二、模式信息
模式名称:模板方法模式
1.问题描述
生活场景:大家都经常会用到对数据库中表进行操作,有时候数据库中有若干个表,我们往往是一个一个的对相应的表进行连接数据库,然后对指定的表进行增、删、改、查的一系列操作,组后关闭数据库的连接。但是当我们要对大型的数据库进行这些操作的时候,你会发现这些操作很繁琐,要对每一个表都进行相同的处理,加大的数据的操作工作。
设计目的:实现对若干个不相同的表进行重复的增删改查工作。
2.不假思索的思路
思路描述:对TemplateMethod数据库中的Categories表进行数据库的连接,表的增删改查以及数据库的关闭等操作。
类结构图如下:
存在问题:
试想:当表相对较少的时候操作还比较简单,但是当表相对较多的时候,就会非常的麻烦,需要对每一个表重复上面的几个操作。所以“变化”是软件设计的永恒主题,有变化就会带来无穷尽的复杂,那我们就找出一种模式去应变这种变化的复杂性,设计模式的艺术性和复杂度就在于如何分析,并发现系统中的变化和稳定点,并使用特定的设计方法来应对这种变化。
代码如下:
3.归纳阶段:
思路描述:结合上面的变化(Template Method)就是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method让子类重新定义一个算法的某些步骤而无需改变算法的结构。
模板方法就是关于怎么样将若干个方法集成到一个方法中,以便形成一个解决问题的算法骨架,它的关键在于,在一个抽象类中定义一个算法骨架,即将若干个方法集成到一个方法中,并称该方法为一个模板方法,或直接就叫模板。模板方法所调用的其他方法通常称为抽象的方法,这些抽象的方法相当于算法骨架中的各个步骤,这些步骤的实现可以由子类去完成。(实际处理交给子类区处理)
Template Method的UML类图如下:
根据上面的归纳我们需要对TemplateMethod数据库中的表进行相关的操作。对于数据库操作,无非就是下面的几项操作:
Connect(); //连接数据库
Select(); //执行查询命令
Insert(); //执行插入命令
Delete(); //执行删除命令
Updata(); //执行更新命令
Display(); //显示数据
Disconnect(); //断开数据库连接
虽然这些步骤是固定的,但是对于每一张具体的数据表所执行的查询却是不一样的。这样就需要一个抽象角色,给出顶级行为的实现。
用模板方法模式修改后的类图如下:
代码的实现:
运行结果:
4.验证阶段:
思路描述:针对上面的操作新增加一个对Products表的操作。
类结构图:
增加的代码如下:
namespace TemplateMethod
{
//具体类(数据库中的Products表)
class Products : DataSqlObject
{
private string sqlconn = "Data Source=.;Initial Catalog=TemplateMethod;Integrated Security=True";
private string commandString;
private DataSet dataSet;
private SqlConnection dataConnection;
//Methods方法
protected override void Connect()
{
dataConnection = new SqlConnection(sqlconn);
dataConnection.Open();
}
protected override void Select()
{
commandString = "select top 10 ProductName from Products";
SqlDataAdapter da = new SqlDataAdapter(commandString, dataConnection);
dataSet = new DataSet();
da.Fill(dataSet, "Products");
}
protected override void Display()
{
Console.WriteLine("-------------Show top 10 ProductName--------------");
DataTable dataTable = dataSet.Tables["Products"];
//DataTable dataTable = new DataTable();
foreach (DataRow row in dataTable.Rows)
{
Console.WriteLine(row["ProductName"].ToString());
}
Console.WriteLine();
}
protected override void Insert()
{
Console.WriteLine("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
Console.WriteLine("插入成功!!");
}
protected override void Delete()
{
Console.WriteLine("删除成功!!");
}
protected override void Updata()
{
Console.WriteLine("更新成功!!");
}
protected override void Disconnect()
{
dataSet.Dispose();
dataConnection.Close();
}
}
}
namespace TemplateMethod
{
//模板方法模式的应用测试
public class App
{
public static void Main()
{
DataSqlObject dso;
dso = new Categories();
dso.Run();
dso = new Products();
dso.Run();
Console.Read();
}
}
}
运行结果:
这样应用模板方法以后不管再对多少张表进行操作,骨架是不变的,而实际的一些步骤延迟到子类中去实现。
5.模板方法模式总结:
1. 模板方法模式在一个类中形式化的定义算法,而由它的子类实现细节的处理,其优势是,在子类定义处理算法时不会改变算法的结构,其特点是,每个不同的实现都需要定义一个子类,这也是符合高内聚的责任分配模式,不能简单的说是它的缺点。
2. 可以通过在抽象模板定义模板方法给出成熟的算法步骤,同时又不限制步骤的细节,具体模板实现算法细节不会改变整个算法的骨架。
3.适合模板方法模式的情景
(1)设计者需要给出一个算法的固定步骤,并将某些步骤的具体实现留给子类来实现。
(2)需要对代码进行重构,将各个子类公共行为提取出来集中到一个共同的父类中以避免代码重负。
namespace TemplateMethod
{
//"AbstractClass"抽象类
public abstract class DataSqlObject
{
//Methds方法
protected abstract void Connect();
protected abstract void Select();
protected abstract void Insert();
protected abstract void Delete();
protected abstract void Updata();
protected abstract void Display();
protected abstract void Disconnect();
//Template Method模板方法
public void Run()
{
Connect(); //连接数据库
Select(); //执行查询命令
Insert(); //执行插入命令
Delete(); //执行删除命令
Updata(); //执行更新命令
Display(); //显示数据
Disconnect(); //断开数据库连接
}
}
}
//在这个顶级的框架DataSqlObject中给出了模板固定的轮廓,public void Run()便是模版方法。而Connect()、Select()、Insert()、Delete()、Updata()、Display()、Connect()这几个抽象方法就留给具体的子类去实现:
namespace TemplateMethod
{
//具体类(数据库中的Categories表)
class Categories : DataSqlObject
{
private string sqlconn = "Data Source=.;Initial Catalog=TemplateMethod;Integrated Security=True";
private string commandString;
private DataSet dataSet;
private SqlConnection dataConnection;
//Methods方法
protected override void Connect()
{
dataConnection = new SqlConnection(sqlconn);
dataConnection.Open();
}
protected override void Select()
{
commandString = "select CategoryName from Categories";
SqlDataAdapter da = new SqlDataAdapter(commandString , dataConnection );
dataSet= new DataSet();
da.Fill(dataSet, "Categories");
}
protected override void Display()
{
Console.WriteLine("--------------ShowCategoryName-------------------");
DataTable dataTable = dataSet.Tables["Categories"];
//DataTable dataTable = new DataTable();
foreach (DataRow row in dataTable.Rows)
{
Console.WriteLine(row["CategoryName"].ToString());
}
Console.WriteLine();
}
protected override void Insert()
{
Console.WriteLine("~~~~~~~~~~~~~~~~~~~~Categories~~~~~~~~~~~~~~~~~~~");
Console.WriteLine("插入成功!!");
}
protected override void Delete()
{
Console.WriteLine("删除成功!!");
}
protected override void Updata()
{
Console.WriteLine("更新成功!!");
}
protected override void Disconnect()
{
dataSet.Dispose();
dataConnection.Close();
}
}
}
//最后就是客户端程序的调用,不需要再去调用每一个步骤的方法:
namespace TemplateMethod
{
public class App
{
public static void Main()
{
DataSqlObject dso;
dso = new Categories();
dso.Run();
Console.Read();
}
}
}