zoukankan      html  css  js  c++  java
  • 设计模式(二)(Factory method)工厂方法设计模式

    • 定义:

    1.) 工厂方法模式是用来封装对象的创建,通过让子类来决定创建的对象是什么,来达到将对象创建的过程封装的目的;

    2.) 定义了一个创建对象的接口,但由子类决定要实例的泪是哪一个。工厂方法让类把实例化推迟到子类。

    • 适用场景:

    代码中经常会出现:根据条件创建实现了同一个接口的不用类实例,而这些判定条件可能随时变动,导致我们这个不得不去改动很多代码。

    备注:简单工厂在Head First中,被认为不是设计模式的一种,但人们经常使用,大家习惯性的叫,久了也就言传为“工厂方法模式”。

    • 简单工厂方法
    • 解决了什么问题

    例如:

    string dbName=string.Empty;
                dbName="Access";
                MemberDaoBase memberDao=null;
                
                if(dbName.ToUpper()=="ACCESS"){
                    memberDao=new Access.MemberDao();
                }
                else if(dbName.ToUpper()=="SQLSERVER")
                {
                    memberDao=new SqlServer.MemberDao();
                }
                memberDao.Create(new Member());
                memberDao.Modify(new Member());
                memberDao.Remove(0);
                

    如果代码中不再变动还好,但这种情况很多时候是不存在的,当来了一个新的领导,领导说Sqlite的性能好且免费,那你就不得不去重新去写一个Sqlite.MemberDao,之后再在这里的判断条件中添加上

    1 else if(dbName.ToUpper()=="SQLITE")
    2 {
    3       memberDao=new SqlServer.SqliteDao();
    4 }

    当某天另外一个领导说我们不再支持SqlServer了,我们就不得不把else if(dbName.ToUpper()=="SQLSERVER") {...} 这块代码给注释了。我们就痛苦在这种“变动”中。

    问题分析:

    不稳定部分:

     1 string dbName=string.Empty;
     2             dbName="Access";
     3             MemberDaoBase memberDao=null;
     4             
     5             if(dbName.ToUpper()=="ACCESS"){
     6                 memberDao=new Access.MemberDao();
     7             }
     8             else if(dbName.ToUpper()=="SQLSERVER")
     9             {
    10                 memberDao=new SqlServer.MemberDao();
    11             }

    稳定部分: 

    1 memberDao.Create(new Member());
    2 
    3 memberDao.Modify(new Member());
    4 
    5 memberDao.Remove(0);

    如果我们将不稳定的部分给交给两外一个类单独管理,就能把这种耦合变得低一点,当我们需要“变动”时,只用去修改这个管理类;而这管理来是用来new 实例的,我们习惯。

    • “new管理类(简单工厂方法核心类)”:
     1 /// <summary>
     2     /// Description of MemberDaoFactory.
     3     /// </summary>
     4     public class MemberDaoFactory
     5     {        
     6         public MemberDaoBase Create(string dbName)
     7         {    
     8             if(dbName.ToUpper()=="ACCESS")
     9             {
    10                 Console.WriteLine("new Access.MemberDao()");
    11                 return new Access.MemberDao();
    12             }
    13             else if(dbName.ToUpper()=="SQLSERVER")
    14             {
    15                 Console.WriteLine("new SqlServer.MemberDao()");
    16                 return new SqlServer.MemberDao();
    17             }
    18             else
    19             {
    20                 throw new NotSupportedException(string.Format("Not supported {0}",dbName));
    21             }
    22         }
    23     }
    • 按照简单工厂方法的定义调整

    代码结构图:

    Member.cs

     1 /// <summary>
     2     /// Description of Member.
     3     /// </summary>
     4     public class Member
     5     {    
     6         private int id;
     7         private string name;
     8         
     9         public Member()
    10         {
    11         }
    12             
    13         public int Id 
    14         {
    15             get { return id; }
    16             set{id=value;}
    17         }
    18         
    19         public string Name 
    20         {
    21             get { return name; }
    22             set { name = value; }
    23         }
    24     }
    View Code

    Dao/MemberBO.cs

     1 using System;
     2 
     3 namespace FactoryMethod
     4 {
     5     /// <summary>
     6     /// Description of MemberBO.
     7     /// </summary>
     8     public class MemberBO
     9     {
    10         private MemberDaoFactory memberDaoFactory=null;
    11         private string dbName=string.Empty;
    12         
    13         public MemberBO(string dbName,MemberDaoFactory memberDaoFactory)
    14         {
    15             this.dbName=dbName;
    16             this.memberDaoFactory=memberDaoFactory;
    17         }
    18         
    19         public void Create(Member member)
    20         {
    21             if(member==null)
    22             {
    23                 throw new ArgumentNullException("member is null");
    24             }
    25             
    26             MemberDaoBase memberDao=this.memberDaoFactory.Create(this.dbName);
    27             
    28             memberDao.Create(member);
    29         }        
    30     }
    31 }

    Dao/MemberDaoBase.cs

     1 using System;
     2 
     3 namespace FactoryMethod
     4 {
     5     public abstract class MemberDaoBase
     6     {
     7         public abstract void Create(Member member);
     8         
     9         public abstract void Modify(Member member);        
    10         
    11         public abstract void Remove(int id);
    12     }
    13 }
    View Code

    Dao/SqlServer/MemberDao.cs

     1 using System;
     2 
     3 namespace FactoryMethod.SqlServer
     4 {
     5     /// <summary>
     6     /// Description of MemberDao.
     7     /// </summary>
     8     public class MemberDao:MemberDaoBase
     9     {
    10         public MemberDao()
    11         {
    12         }
    13         
    14         public override void Create(Member member)
    15         {
    16             //...
    17             Console.WriteLine("Insert member into sqlserver db");
    18         }
    19         
    20         public override void Modify(Member member)
    21         {
    22             //...
    23             Console.WriteLine("modify member from sqlserver db");
    24         }
    25         
    26         public override void Remove(int id)
    27         {
    28             //...
    29             Console.WriteLine("remove member from sqlserver db");
    30         }
    31     }
    32 }
    View Code

    Dao/Access/MemberDao.cs

     1 using System;
     2 
     3 namespace FactoryMethod.Access
     4 {
     5     /// <summary>
     6     /// Description of MemberDao.
     7     /// </summary>
     8     public class MemberDao:MemberDaoBase
     9     {
    10         public MemberDao()
    11         {
    12         }
    13         
    14         public override void Create(Member member)
    15         {
    16             //...
    17             Console.WriteLine("Insert member into access db");
    18         }
    19         
    20         public override void Modify(Member member)
    21         {
    22             //...
    23             Console.WriteLine("modify member from access db");
    24         }
    25         
    26         public override void Remove(int id)
    27         {
    28             //...
    29             Console.WriteLine("remove member from access db");
    30         }
    31     }
    32 }
    View Code

    客户端调用:

     1 class Program
     2     {
     3         public static void Main(string[] args)
     4         {
     5             Console.WriteLine("Hello World!");
     6             
     7             // TODO: Implement Functionality Here    
     8             MemberBO memberBO0=new MemberBO("access",new MemberDaoFactory());
     9             memberBO0.Create(new Member());
    10             
    11             MemberBO memberBO1=new MemberBO("sqlserver",new MemberDaoFactory());
    12             memberBO1.Create(new Member());
    13             
    14             Console.Write("Press any key to continue . . . ");
    15             Console.ReadKey(true);            
    16         }
    17     }

    输出结果:

    • 工厂方法

    当系统要求不再是只有普通人员了,分出了管理层和基层,而且程序中要求不同等级的数据放在不同网络上,且数据库中的字段名称不同,但意义还是一样时。

          我们当前系统的结构就不能很好的应对了,于是我们就需要这样处理:

    提取出对应的抽象MemberBO类,和MemberBO的具体实现类ManagerBO,EmployeeBO,MemberBO包含所有的外部需要的功能外还包含一个抽象的FactoryMethod函数,ManagerBO和EmployeeBO要实现FactoryMethod函数:

     

    对应的类:

      1  public class Member
      2     {
      3         public Member() { }
      4 
      5         public int ID { get; set; }
      6 
      7         public string Name { get; set; }
      8     }
      9 
     10     public abstract class MemberDaoBase
     11     {
     12         public abstract void Create(Member member);
     13 
     14         public abstract void Modify(Member member);
     15     }
     16 
     17     public abstract class MemberBOBase
     18     {
     19         protected virtual void Create(Member member, string dbName)
     20         {
     21             if (member == null)
     22             {
     23                 throw new ArgumentNullException("member is null!");
     24             }
     25 
     26             this.FactoryMethod(dbName).Create(member);
     27         }
     28 
     29         protected virtual void Modify(Member member, string dbName)
     30         {
     31             if (member == null)
     32             {
     33                 throw new ArgumentNullException("member is null!");
     34             }
     35 
     36             this.FactoryMethod(dbName).Modify(member);
     37         }
     38 
     39 
     40         public abstract MemberDaoBase FactoryMethod(string dbName);
     41     }
     42 
     43     public class ManagerBO : MemberBOBase
     44     {
     45         public override MemberDaoBase FactoryMethod(string dbName)
     46         {
     47             if (dbName.ToUpper() == "ACCESS")
     48             {
     49                 return new ManagerAccessDao();
     50             }
     51             else if (dbName.ToUpper() == "SQLSERVER")
     52             {
     53                 return new ManagerSqlServerDao();
     54             }
     55             else
     56             {
     57                 throw new NotImplementedException(string.Format("{0} not implemented", dbName));
     58             }
     59         }
     60     }
     61 
     62     public class EmployeeBO : MemberBOBase
     63     {
     64         public override MemberDaoBase FactoryMethod(string dbName)
     65         {
     66             if (dbName.ToUpper() == "ACCESS")
     67             {
     68                 return new EmployeeAccessDao();
     69             }
     70             else if (dbName.ToUpper() == "SQLSERVER")
     71             {
     72                 return new EmployeeSqlServerDao();
     73             }
     74             else
     75             {
     76                 throw new NotImplementedException(string.Format("{0} not implemented", dbName));
     77             }
     78         }
     79     }
     80 
     81     public class ManagerAccessDao : MemberDaoBase
     82     {
     83         public override void Create(Member member)
     84         {
     85             throw new NotImplementedException();
     86         }
     87 
     88         public override void Modify(Member member)
     89         {
     90             throw new NotImplementedException();
     91         }
     92     }
     93 
     94 
     95     public class ManagerSqlServerDao : MemberDaoBase
     96     {
     97         public override void Create(Member member)
     98         {
     99             throw new NotImplementedException();
    100         }
    101 
    102         public override void Modify(Member member)
    103         {
    104             throw new NotImplementedException();
    105         }
    106     }
    107 
    108     public class EmployeeAccessDao : MemberDaoBase
    109     {
    110         public override void Create(Member member)
    111         {
    112             throw new NotImplementedException();
    113         }
    114 
    115         public override void Modify(Member member)
    116         {
    117             throw new NotImplementedException();
    118         }
    119     }
    120 
    121 
    122     public class EmployeeSqlServerDao : MemberDaoBase
    123     {
    124         public override void Create(Member member)
    125         {
    126             throw new NotImplementedException();
    127         }
    128 
    129         public override void Modify(Member member)
    130         {
    131             throw new NotImplementedException();
    132         }
    133     }
    •  简单工厂和工厂方法之间的差异

    简单工厂是将全部的事情,在一个地方都处理完了,而工厂方法却是创建了一个框架,让子类决定要如何实现。

    例如:在工厂方法中我们有一个FactoryMethod()方法提供了一般的框架,一边创建Dao,FactoryMethod()方法依赖工厂方法创建具体类,决定制造出的Dao是什么。

    简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

    • 这样的调整好处在于什么?

    当我们需要条件一个新扩展Member数据操作类时,我们有统一的接口来,具体的操作方法都可不变,改动部分只需要扩展现有的MemberDaoFactory.cs,降低了应用层的耦合度。

    •  优点:

      1.) 优点:

    a.) 降低了应用层次调用的耦合度;

    b.) 当扩展时,有统一的接口类,开发更规范;

    c.) 代码逻辑更清晰,代码更易管理维护。    

      2.) 缺点:

    a.) 适用性很有限,前提条件有局限性;当我们的接口类MemberDaoBase.cs变动时,我们就需要改动多处代码;
    b.) 当需要扩展时,我们依然避免不了要改动代码(尽管可以进一步改进通过设置配置和反射达到避免MemberDaoFactory变动,但是当我们需要添加新的扩展时还避免不了改动代码)。

     参考资料:《Head First 设计模式》

      欢迎拍砖!请牛人们给指点。

  • 相关阅读:
    推荐:《TestDrive ASP.NET MVC》 节选与作者访谈
    30天敏捷结果(15):让自己处于宁静状态
    MDSF:如何使用GMF来做TOGAF建模工具
    强烈推荐:好书、好人、好谚语
    推荐:50个加强表单的jQuery插件
    101与金根回顾敏捷个人:(1)基于MBTI模型发现你的职业性格
    30天敏捷结果(19):你在为谁做事?
    30天敏捷生活(13):获得他人的反馈
    SourceForge.net上的新项目(2005/07/05)
    Open License,开源的许可生成器,实现你自己的许可管理器/应用
  • 原文地址:https://www.cnblogs.com/yy3b2007com/p/4062181.html
Copyright © 2011-2022 走看看