设计模式(二)(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 设计模式》

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

 

posted @ 2014-10-31 14:02  cctext  阅读(436)  评论(1编辑  收藏  举报