注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

天涯倦客的博客

祝福你朋友永远快乐!

 
 
 

日志

 
 

老生常谈:抽象工厂模式  

2011-03-15 16:39:15|  分类: 设计模式 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在创建型模式中有一个模式是不得不学的,那就是抽象工厂模式(Abstract Factory),这是创建型模式中最为复杂,功能最强大的模式.它常与工厂方法组合来实现。平时我们在写一个组件的时候一般只针对一种语言,或者说是针对一个区域的人来实现。 

    例如:现有有一个新闻组件,在中国我们有这样的需求:在显示新闻列表的同时,附加一个操作:例如给新闻的人气加一。这种需求是非常容易实现的,可是有朝一日你的这个新闻组件应用到了美国呢。你的功能还能满足当地的需求吗?此时美国的需求是:在显示新闻列表的同时,把这条新闻加入到某个RSS中去。可想,不做修改直接用是不行的,那如果直接修改类方法呢?这样实际也是可行的,但是违背了"开-闭"的编程原则,不便以后的维护。 那不修改就只有新加类了,我们可以保留原有功能的同时增加一批类,方法签名都同于之前的,只是实现方式不同而已。为什么要这样做呢?本人的思路是这样的:

    新闻组件无非可以分为两块: 

    第一:读取新闻,这是固定不变的,所以可以抽象出来。 

    第二:读取新闻同时的附加操作,可以有,也可以没有,可以有一种操作也可以是多种,这里我可以把它们都封闭进一个方法中.这样在外界看起来就是调用了一个方法。所以也可以抽象出来。 

    结论:这种情况就是抽象工厂中的系列产品了,生成产品的流程基本都一样,不同的是生产过程。我对新闻组件的改造,具体实现过程如下:先贴出类图:


  

 

      第一:所谓工厂肯定是要有一个最上层的管理工厂了,这里我称为parentFactory,它下面有两个子工厂,我称为:childFactory,分别是负责美国和中国的childFactory_ChinachildFactory_US。parentFactory的责任就是管理好这两个子工厂。生产子工厂实例的方法我用了反射的原理,这样可以在web.config文件中配置就可以决定调用哪一个子工厂来生产产品了。  

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客    /// <summary>
    
/// 此类为基类抽象工厂,即parentFactory,它主要负责生成出子工厂实例
    
/// </summary>

    public abstract class AbstractFactoryClass
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客    
{
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
/// <summary>
        
/// 取得生成新闻标题的类实例
        
/// </summary>
        
/// <returns></returns>

        public abstract  getNews_Class  getNews_Instance();
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
/// <summary>
        
/// 其它方法实例,例如:增加新闻人气,把此新闻添加进RSS中
        
/// </summary>

        public abstract otherOperationClass  otherMethod_Instance();
        
//把抽象类设置成静态变量,避免多次加载程序集
        private static AbstractFactoryClass instance=null ;
        
public static AbstractFactoryClass GetInstance()
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
{
            
//取得当前工厂名称
            string factoryName = ConfigurationSettings .AppSettings["factoryName"].ToString();
            
//AbstractFactoryClass instance;
            if (instance == null)
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客            
{
                
if (factoryName != "")
                    instance 
= (AbstractFactoryClass)Assembly.Load("AbstractFactoryCompent").CreateInstance(factoryName);
                
else
                    instance 
= null;
            }


            
return instance;
        }

     

       
    }
   

   

      web.config文件中的配置节:

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客
<appSettings>
        
<add key="factoryName" value="AbstractFactoryCompent.AbstractFactory_US"></add>
    
</appSettings>


    第二:完成负责美国和中国的childFactory_China和childFactory_US两个子工厂,它们的功能都是一样的,找到合适的工厂(我在这称为:concreteFactory)来完成两个具体部件的加工工作,这两个部件分别是:1读取新闻部件,2:读取新闻后进行的额外操作的部件。这里以中国境内的子工厂为倒来说明:childFactory_China:这个子工厂主要是"找到"具体生产产品的工厂,我在这称为:concreteFactory。 

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客
public class AbstractFactory_China:AbstractFactoryClass 
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客    
{
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
/// <summary>
        
/// CN:取得生成新闻标题的类实例
        
/// </summary>
        
/// <returns></returns>

        public override  getNews_Class getNews_Instance()
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
{
            
return new getNews_Class_China();
        
        }

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
/// <summary>
        
/// CN:其它方法实例,例如:增加新闻人气,把此新闻添加进RSS中
        
/// </summary>

        public override  otherOperationClass otherMethod_Instance()
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
{
            
return new otherOperationClass_China();
        }

    }

  

   第三:具体工厂部分,我在这称为:concreteFactory,它们负责生成出具体的产品来,对应上面的新闻组件,就是负责生成:1能够读取新闻的部件,2:读取新闻后能够进行相应操作的部件。我在这称为concreteProduct,最终产品。这里就说明一下中国境内的具体工厂的类实现代码,其它的就省略了。

    1:getNews_Class_China:读取新闻部件的具体工厂:

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客
public  class getNews_Class_China:getNews_Class 
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客    
{
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
/// <summary>
        
/// CN:读取新闻标题
        
/// </summary>
        
/// <returns></returns>

        public override  IList getNews()
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
{
            List
<string> newsTitle = new List<string>();
            
for (int i = 0; i < 10; i++)
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客            
{
                newsTitle.Add(
"cn:" + i.ToString());

            }

            
return newsTitle;
        
        }

    }

 

    2:otherOperationClass_China:读取新闻后进行附加操作部件的具体工厂.

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客
public  class otherOperationClass_China:otherOperationClass 
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客    
{
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
/// <summary>
        
/// cn:在显示新闻的同时会把此新闻的人气加一
        
/// </summary>
        
/// <returns></returns>

        public override string otherMethod()
老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客        
{
            
return "CN把此新闻的访问量或者说是人气加一";
        }

    }

  

   第四:有了产品当然少不了消费者了,这里我称为customer,customer只与parentFactory和concreteProduc有直接关系,customer可以指定调用哪一个系列的产品。

 

   第五:页面代码:把新闻列表绑定到控件中,同时为了说明问题,把customer在绑定新闻时的附加操作内容以文本的形式显示出来. 

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客
<asp:GridView ID="GridView1" runat="server">
        
</asp:GridView>
        
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

 

   cs:

老生常谈:抽象工厂模式 - 海里的贝壳 - apple的博客
 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

  评论这张
 
阅读(508)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017