在创建型模式中有一个模式是不得不学的,那就是抽象工厂模式(Abstract Factory),这是创建型模式中最为复杂,功能最强大的模式.它常与工厂方法组合来实现。平时我们在写一个组件的时候一般只针对一种语言,或者说是针对一个区域的人来实现。
例如:现有有一个新闻组件,在中国我们有这样的需求:在显示新闻列表的同时,附加一个操作:例如给新闻的人气加一。这种需求是非常容易实现的,可是有朝一日你的这个新闻组件应用到了美国呢。你的功能还能满足当地的需求吗?此时美国的需求是:在显示新闻列表的同时,把这条新闻加入到某个RSS中去。可想,不做修改直接用是不行的,那如果直接修改类方法呢?这样实际也是可行的,但是违背了"开-闭"的编程原则,不便以后的维护。 那不修改就只有新加类了,我们可以保留原有功能的同时增加一批类,方法签名都同于之前的,只是实现方式不同而已。为什么要这样做呢?本人的思路是这样的:
新闻组件无非可以分为两块:
第一:读取新闻,这是固定不变的,所以可以抽象出来。
第二:读取新闻同时的附加操作,可以有,也可以没有,可以有一种操作也可以是多种,这里我可以把它们都封闭进一个方法中.这样在外界看起来就是调用了一个方法。所以也可以抽象出来。
结论:这种情况就是抽象工厂中的系列产品了,生成产品的流程基本都一样,不同的是生产过程。我对新闻组件的改造,具体实现过程如下:先贴出类图:
第一:所谓工厂肯定是要有一个最上层的管理工厂了,这里我称为parentFactory,它下面有两个子工厂,我称为:childFactory,分别是负责美国和中国的childFactory_China和childFactory_US。parentFactory的责任就是管理好这两个子工厂。生产子工厂实例的方法我用了反射的原理,这样可以在web.config文件中配置就可以决定调用哪一个子工厂来生产产品了。
Code
/**//// <summary>
/// 此类为基类抽象工厂,即parentFactory,它主要负责生成出子工厂实例
/// </summary>
public abstract class AbstractFactoryClass
{
/**//// <summary>
/// 取得生成新闻标题的类实例
/// </summary>
/// <returns></returns>
public abstract getNews_Class getNews_Instance();
/**//// <summary>
/// 其它方法实例,例如:增加新闻人气,把此新闻添加进RSS中
/// </summary>
public abstract otherOperationClass otherMethod_Instance();
//把抽象类设置成静态变量,避免多次加载程序集
private static AbstractFactoryClass instance=null ;
public static AbstractFactoryClass GetInstance()
{
//取得当前工厂名称
string factoryName = ConfigurationSettings .AppSettings["factoryName"].ToString();
//AbstractFactoryClass instance;
if (instance == null)
{
if (factoryName != "")
instance = (AbstractFactoryClass)Assembly.Load("AbstractFactoryCompent").CreateInstance(factoryName);
else
instance = null;
}
return instance;
}
}
web.config文件中的配置节:
Code
<appSettings>
<add key="factoryName" value="AbstractFactoryCompent.AbstractFactory_US"></add>
</appSettings>
第二:完成负责美国和中国的childFactory_China和childFactory_US两个子工厂,它们的功能都是一样的,找到合适的工厂(我在这称为:concreteFactory)来完成两个具体部件的加工工作,这两个部件分别是:1读取新闻部件,2:读取新闻后进行的额外操作的部件。这里以中国境内的子工厂为倒来说明:childFactory_China:这个子工厂主要是"找到"具体生产产品的工厂,我在这称为:concreteFactory。
Code
public class AbstractFactory_China:AbstractFactoryClass
{
/**//// <summary>
/// CN:取得生成新闻标题的类实例
/// </summary>
/// <returns></returns>
public override getNews_Class getNews_Instance()
{
return new getNews_Class_China();
}
/**//// <summary>
/// CN:其它方法实例,例如:增加新闻人气,把此新闻添加进RSS中
/// </summary>
public override otherOperationClass otherMethod_Instance()
{
return new otherOperationClass_China();
}
}
第三:具体工厂部分,我在这称为:concreteFactory,它们负责生成出具体的产品来,对应上面的新闻组件,就是负责生成:1能够读取新闻的部件,2:读取新闻后能够进行相应操作的部件。我在这称为concreteProduct,最终产品。这里就说明一下中国境内的具体工厂的类实现代码,其它的就省略了。
1:getNews_Class_China:读取新闻部件的具体工厂:
Code
public class getNews_Class_China:getNews_Class
{
/**//// <summary>
/// CN:读取新闻标题
/// </summary>
/// <returns></returns>
public override IList getNews()
{
List<string> newsTitle = new List<string>();
for (int i = 0; i < 10; i++)
{
newsTitle.Add("cn:" + i.ToString());
}
return newsTitle;
}
}
2:otherOperationClass_China:读取新闻后进行附加操作部件的具体工厂.
Code
public class otherOperationClass_China:otherOperationClass
{
/**//// <summary>
/// cn:在显示新闻的同时会把此新闻的人气加一
/// </summary>
/// <returns></returns>
public override string otherMethod()
{
return "CN把此新闻的访问量或者说是人气加一";
}
}
第四:有了产品当然少不了消费者了,这里我称为customer,customer只与parentFactory和concreteProduc有直接关系,customer可以指定调用哪一个系列的产品。
第五:页面代码:把新闻列表绑定到控件中,同时为了说明问题,把customer在绑定新闻时的附加操作内容以文本的形式显示出来.
Code
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
cs:
Code
IList newsTitle = AbstractFactoryClass.GetInstance().getNews_Instance().getNews();
this.GridView1.DataSource = newsTitle ;
this.GridView1.DataBind();
this.Label1.Text = AbstractFactoryClass.GetInstance().otherMethod_Instance().otherMethod();
第六:运行效果:
本例有点就模式而模式的意思,其实本人也只是模式的初学者,很难把在实际当中的模式应用拿出来讲,说实在的,本人应用模式特别少。就上面的需求其实有非常多的方法可以实现,只是各有所长而已。在前一段时间,本人学习装饰者模式的时候,就根据同样的需求用装饰者实现过,效果也不错。在网站新闻模块中应用装饰者模式 有兴趣的朋友可以对比看看,不妥处望指教。
在以下情况下应当考虑使用抽象工厂模式:本人在这就不献丑了,直接引用.NET设计模式(3):抽象工厂模式(Abstract Factory),希望大家不要笑我懒啊 :)
1:一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
2:这个系统有多于一个的产品族,而系统只消费其中某一产品族。
3:同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
4:系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
总结:在本例中,我们发现抽象工厂虽然能够非常完美的满足需求,但是也有缺点:难以扩展抽象工厂以生产新种类的产品。所有的子工厂都是事先安排好的,如果要生成一个全新的系列产品还是要修改类。
注:
本文引用:http://terrylee.cnblogs.com/archive/2005/12/13/295965.html