有朋友看了我这篇文章后说模式并不存在相互转换,因为它们有不同的应用背景,我认为用转换的确不妥,那就改用功能替换吧,就是说一个功能的实现并不局限于一种模式.
在上一篇实际项目中的策略模式应用中,我分析了一下实际项目中如何应用策略模式,我们知道设计模式有二十多种,是不是在一个实现方法上只能唯一使用一种模式呢?它们之间是否有共同点,或者说它们之间是不是可以转换呢?
在这篇文章中我还是继续上一篇的项目来说一下策略模式有没有可能和工厂模式相互转换,知道设计模式的朋友一定知道,工厂模式在设计模式当中的应用应该来说是最多的,因为它是很多模式的基础.
策略模式的类图如下:
工厂方法模式的思想:
简单工厂模式的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。
该模式中包含的角色及其职责工厂(Creator)角色.
简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
抽象(Product)角色
简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品(Concrete Product)角色
简单工厂模式的特点:
简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。
不难发现,简单工厂模式的缺点也正体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,所以“高内聚”方面做的并不好。另外,当系统中的具体产品类不断增多时,可能会出现要求工厂类也要做相应的修改,扩展性并不很好。
本人将上文中导出数据部分转换为用工厂模式的方法实现,类关系图如下:
此方法中的具体实现方法我就省略了,有兴趣的朋友可能去看下jillzhang的博客,里面有关于组件开发的文章.
接口如下:
Code
/**//// <summary>
/// 将GridView导出到其他文件的接口
/// </summary>
public interface IExporter
{
/**//// <summary>
/// 导出类型的名称
/// </summary>
string ExportTypeName { get;set;}
/**//// <summary>
/// 将GirdView导出为其他格式的文件
/// </summary>
/// <param name="grid">要导出的GridView对象</param>
/// <param name="unExportedColumnNames">不导出的列名称集合</param>
void Export(GridView grid);
}
工厂类如下:
Code
public class FactoryDAL
{
/**//// <summary>
/// create instance by type
/// </summary>
/// <param name="sType"></param>
/// <returns></returns>
public static IExporter createInstance(string sType)
{
IExporter EX=null ;
switch (sType)
{
case "excel":
EX= new ExcelExporter();
break;
case "word":
EX = new WordExporter();
break;
case "pdf":
EX = new PdfExporter();
break;
default :
EX = new ExcelExporter();
break;
}
return EX;
}
}
根据不同的导出类型实现的具体类如下:
Code
/**//// <summary>
/// Excel导出
/// </summary>
public class ExcelExporter:IExporter
{
private string _ExportTypeName = "导出方式为EXCEL";
/**//// <summary>
/// 导出类型的名称
/// </summary>
public string ExportTypeName
{
get { return this ._ExportTypeName ; }
set{this._ExportTypeName =value ; }
}
public methods#region public methods
/**//// <summary>
/// 将GirdView导出为其他格式的文件
/// </summary>
/// <param name="grid">要导出的GridView对象</param>
/// <param name="unExportedColumnNames">不导出的列名称集合</param>
public void Export(GridView grid)
{
//具体代码略
}
#endregion
}
Code
public class PdfExporter : IExporter
{
private string _ExportTypeName = "导出方式为pdf";
/**//// <summary>
/// 导出类型的名称
/// </summary>
public string ExportTypeName
{
get { return this._ExportTypeName; }
set { this._ExportTypeName = value; }
}
public PdfExporter()
{
}
public void Export(GridView grid)
{
//具体代码略
}
}
Code
/**//// <summary>
/// Word导出
/// </summary>
public class WordExporter:IExporter
{
private string _ExportTypeName = "导出方式为word";
/**//// <summary>
/// 导出类型的名称
/// </summary>
public string ExportTypeName
{
get { return this._ExportTypeName; }
set { this._ExportTypeName = value; }
}
public methods#region public methods
/**//// <summary>
/// 将GirdView导出为其他格式的文件
/// </summary>
/// <param name="grid">要导出的GridView对象</param>
/// <param name="unExportedColumnNames">不导出的列名称集合</param>
public void Export(GridView grid)
{
//具体代码略
}
#endregion
}
客户端调用:
前台页面:
Code
<asp:DropDownList ID="DropDownList1" runat="server">
<asp:ListItem Selected="True" Value="pdf">pdf导出</asp:ListItem>
<asp:ListItem Value="word">word导出</asp:ListItem>
<asp:ListItem Value="excel">excel导出</asp:ListItem>
</asp:DropDownList>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="导出" />
cs:
Code
protected void Button1_Click(object sender, EventArgs e)
{
IExporter EX = FactoryDAL.createInstance(this.DropDownList1.SelectedValue.ToString().Trim());
Response.Write(EX.ExportTypeName);
}
我只是想说明下工厂模式和其它模式的关系,也并不是说此种转换一定实用于实际项目,这还是要实际情况实际分析,不同的模式有不同的好处,只要能够解决问题就是好方法,古人云:条条大道通罗马.在模式的应用中我们一般是主张利用组合,少用继承,可以将多种模式结合起来用,这样可以扬长补短.
注:本文参考了下面文章:
http://baike.baidu.com/view/1227908.htm