.NET设计模式:工厂方法模式(Factory Method)

设计模式中,创建型模式是最常用的,也是最基础的设计模式。理解这些,对于理解别的复杂的模式有一定的帮助。一般来说,讲创建型模式都先会讲单件模式,这里,为了讲述方便,我先从工厂方法讲起。
下面先从一个案例分析开始这一讲吧:
中国企业需要一项简单的财务计算:每月月底,财务人员要计算员工的工资。
员工的工资 = (基本工资 + 奖金 - 个人所得税)。
中国企业奖金和个人所得税的计算规则是:
奖金 = 基本工资(4000) * 10%
个人所得税 = (基本工资 + 奖金) * 40%
美国企业的工资计算同样是: 员工的工资 = 基本工资 + 奖金 - 个人所得税。
但是他们的奖金和个人所得税的计算规则不同于中国企业:
美国企业奖金和个人所得税的计算规则是:
奖金 = 基本工资 * 15 %
个人所得税 = (基本工资 * 5% + 奖金 * 25%)
(注:以上案例来自TerryLee 设计模式系例文章《NET设计模式(3):抽象工厂模式(Abstract Factory)》中的案例。)
在这里,假设我们需要为某一个跨国公司在美国和中国的企业设计这样一个员工工资计算系统。当然我们可以分别为美国的公司和中国的公司量身定做二套系统,但明显这种做法不明智的,浪费人力物力不说,碰到系统升级等行为,我们不得不为此而付出更多的代价。
我们可以看到,不管是在美国的企业还是在中国的企业,我们要解决的都是同一个问题,那就是员工工资的计算,唯一不同的就是中国企业和美国企业奖金和个人所得税的计算方法不一样而已,这样的话,我们完全可以只设计一个软件系统,而根据不同的国家采取不同的部署即可以解决。
在这里我们尽可能把这套系统想的最简单,因为我们不是要了解这个系统复杂的业务,而是在这个简单的系统里来运用设计模式解决方案,这样更明显一点,也更好理解一点,当然在这个杂谈的例子里,主要是为了讲述设计模式的用法,可能会导致设计过度,这个在这里不作讨论了,呵呵,这些在讲之前先声明一下,免得各位朋友误解。
好了言归正传,既然我们决定只开发一个软件系统,接下来就是怎么来设计了。如果抛开面向对象方法的话,用面向过程的,那是最简单不过了,用IF、ELSE等判断一下,当前要用于哪一个国家公司的员工工资计算,再根据上面的计算方法就可以算出员工工资了,这些在这里就不再详细说明了,在TerryLee 设计模式系例文章《NET设计模式(3):抽象工厂模式(Abstract Factory)》中已经讲的很详细了,我们就直接切入正题。
工厂方法模式,主要是用来解决某一个单一对象的创建问题。把变化部分封装在单独的对象里,然后在实际应用时,根据不同的情况来获取不同的对象,从而满足解决方案的需求,注意工厂方法是解决某个对象的创建问题的。根据这个我们再来看这个案例,对于程序的主干部分,我想比较明确了,就是要计算员工工资,至于计算工资的方法,则根据不同的国家有不同的规则,也就是说计算工资具体实现是变化的。好,既然我们已经找到了变化点在哪里,我们就把每个国家的计算工资实现封装在一个类里,当然,不管是美国公司还是中国公司,都只要实现一个计算工资方法即可,这样我们可以抽象出一个计算工资的接口来,代码如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace DesignPattern.IBLL
6 {
7 public interface ISalary
8 {
9 double Calculate(double basicSalary);
10 }
11 }
12
接下来,我们定义分别对于美国公司和中国公司的具体实现类:
中国公司:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace DesignPattern.BLL
6 {
7 public class ChineseSalary : IBLL.ISalary
8 {
9 public double Calculate(double basicSalary)
10 {
11 double bonus;
12 double tax;
13 double salary;
14
15 bonus = basicSalary * 0.1;//奖金计算
16 tax = (basicSalary + bonus) * 0.4;//个人所得税计算
17
18 salary = basicSalary + bonus - tax;//最终所得工资计算
19
20 return salary;
21 }
22 }
23 }
24
美国公司:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace DesignPattern.BLL
6 {
7 public class AmericanSalary : IBLL.ISalary
8 {
9 public double Calculate(double basicSalary)
10 {
11 double bonus;
12 double tax;
13 double salary;
14
15 bonus = basicSalary * 0.15;//奖金计算
16 tax = basicSalary * 0.05 + bonus * 0.25;//个人所得税计算
17
18 salary = basicSalary + bonus - tax;//最终所得工资计算
19
20 return salary;
21 }
22 }
23 }
24
好计算工资具体的实现类已经完成,接下来,我们就要创建专门的工厂,用它来创建实际用到的计算工资的对象。每个工厂要做的就是创建自己对应的计算工资方法的对象,同样我们可以抽象出一个接口,代码如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace DesignPattern.IBLL
6 {
7 public interface IFactory
8 {
9 ISalary CreateSalary();
10 }
11 }
12
注意,这里CrateSalary方法返回的是ISalary接口,这个就是在开始篇里讲到的其中一个原则,要依赖于抽象,不要依赖于实现细节。
接下来,分别创建对应于美国企业和中国企业的具体的工厂方法:
中国企业:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace DesignPattern.Factory
6 {
7 public class ChineseFactory : IBLL.IFactory
8 {
9 public IBLL.ISalary CreateSalary()
10 {
11 return new BLL.ChineseSalary();
12 }
13
14 }
15 }
16
美国企业:
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace DesignPattern.Factory
6 {
7 public class AmericanFactory : IBLL.IFactory
8 {
9 public IBLL.ISalary CreateSalary()
10 {
11 return new BLL.AmericanSalary();
12 }
13
14 }
15 }
16
到此为止,按照我们的当初设计,分离出变化点,封装在单独的对象里,再创建工厂,利用不同的工厂方法创建相应的对象,已经完成。在这里可能会有朋友会说,何必再多此一举创建工厂方法呢,直接根据不同的情况初始化不同的实现对象不就可以了,确实,如果单单要实现这个功能的话确实足够了,但在实际的应用中,这些对象可能在各个模块中会被频繁的创建,这样的话,如果要在美国公司和中国公司分别部署的话,则比较困难,而且很难适应将来的变化,而用工厂方法的话,我们则可以把具体工厂方法的创建统一来管理,在需要用到的模块里再根据该工厂方法创建相应的对象即可,这样的话,一旦要改变部署的话,我们只要改变具体工厂方法的创建即可,因为这个是统一来管理的,则可以把改变降到最低,当然我在下面的几篇里会讲到更好的方法来应对这种变化。
下面我们就来看看最后的实现吧:
1 double basicSalary;
2 double result;
3
4 basicSalary = Convert.ToDouble(txtBasicSalary.Text.Trim());
5
6 IBLL.IFactory factory = new Factory.ChineseFactory();
7 IBLL.ISalary salary = factory.CreateSalary();
8
9 result = salary.Calculate(basicSalary);
10
11 lbSalary.Text = result.ToString();
如果要在美国公司用,则只要改变一个语句:

1 IBLL.IFactory factory = new Factory.ChineseFactory();
改成:
1 IBLL.IFactory factory = new Factory.AmericanFactory();
即可。
好了,工厂方法就讲到这里了,这里,我们看到,还是需要改变代码来实现不同的部署,这里可以有更好的方法来实现,我们只需要改变配置文件,不必修改代码就可以实现,这一点我就在下一篇中再改进。由于个人的理解有限,有些原理性的东西也讲不大清楚,这一点希望各位朋友能够一起讨论,一起进步。
 
 

      在上一讲“设计模式杂谈:创建型模式之工厂方法(Factory Method)”中,已经通过一个案例对工厂方法进行了讲述。也有不少朋友看了提出了一些建议,确实,在上一讲中,只是简单的讲了工厂方法的用法,但有些地方并不适合于实际应用。主要是最后的创建工厂方法实例时,我把这个工厂方法的创建与该工厂方法创建的具体对象,以及它的执行都放在一起,显然这种做法是错误的,如果这样做的话,还不如直接创建要执行的具体对象,没有必要再搞一个工厂方法进去,有点多此一举的味道,就好象一个包装盒,外面又包了一层,但却并没有起到一定的作用。在这一讲中,在讲单件模式之前,我先对上一讲中的问题进行一些必要的忧化,可能这样会更符合实际的应用。
      现在我们再回头看一下上一讲中最后实现的一段代码:
 1double basicSalary;
 2                double result;
 3
 4                basicSalary = Convert.ToDouble(txtBasicSalary.Text.Trim());
 5
 6                IBLL.IFactory factory = new Factory.ChineseFactory();
 7                IBLL.ISalary salary = factory.CreateSalary();
 8
 9                result = salary.Calculate(basicSalary);
10
11                lbSalary.Text = result.ToString();
      我们现在可以把这个系统想的复杂一些,如果说工资的计算在很多模块里都要用到,按现在的这种做法,则必须在要用到的模块里,重新通过IBLL.IFactory factory = new Factory.ChineseFactory();这个来创建工厂方法,再通过这个工厂来创建相应的ISalary对象,那么一旦需求改了,需要换成美国公司的,那么必须修改每一个模块,这样做的话,那么这个工厂方法真是一个鸡肋了,还不如不要了,可能更方便。所以首选必须把具体工厂的创建放在一个单独的地方,这样就可以统一管理,一旦需求改了,只要改变该地方就可以了。
      好,下面我就就再创建了个FactoryUtility.cs文件,具体代码:  1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4using System.Configuration;
 5using System.Reflection;
 6
 7namespace DesignPattern.Common
 8{
 9    public class FactoryUtility
10    {
11        public IBLL.IFactory GetFactory()
12        {
13            IBLL.IFactory factory = new Factory.ChineseFactory();
14
15            return factory;
16        }
17
18    }
19}
20
      这样我们就可以把上面实现部分代码修改成如下所示:
 1double basicSalary;
 2                double result;
 3
 4                basicSalary = Convert.ToDouble(txtBasicSalary.Text.Trim());
 5
 6                IBLL.IFactory factory = new FactoryUtility().GetFactory();
 7                IBLL.ISalary salary = factory.CreateSalary();
 8
 9                result = salary.Calculate(basicSalary);
10
11                lbSalary.Text = result.ToString();     
      这样的话,如果要满足美国公司的需求,则只要修改FactoryUtility.cs一个文件即可,不用变动其它。经过这一忧化,的确有所改观,但一旦需求变化的话,还是要修改代码。好我们再进一步来讨论这个问题,现在如果 要满足美国公司的要求,则需要修改代码,那怎么样才能不用修改代码呢,这个通过配置+反射就能够很好的解决。首先,建立应用程序配置文件App.Config,进行如下配置:
1<?xml version="1.0" encoding="utf-8" ?>
2<configuration>
3  <appSettings>
4    <add key="FactoryName" value="DesignPattern.Factory.ChineseFactory"/>
5  </appSettings>
6</configuration>
      通过这个配置,我们可以读取到当前工厂方法的类,再通过反射机制来创建该工厂对象即可,通过进一步的忧化,FactoryUtility.cs文件修改后代码如下:  1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4using System.Configuration;
 5using System.Reflection;
 6
 7namespace DesignPattern.Common
 8{
 9    public class FactoryUtility
10    {
11        public IBLL.IFactory GetFactory()
12        {
13            string factoryName = ConfigurationSettings.AppSettings["FactoryName"];
14            factory = (IBLL.IFactory)Assembly.Load("Salary").CreateInstance(factoryName);
15
16            return factory;
17        }
18
19    }
20}
21
      这时我们再来看看,如果要满足美国企业的时候,我们再不需要去改变程序代码,只要修改配置文件App.Config即可:
1<?xml version="1.0" encoding="utf-8" ?>
2<configuration>
3  <appSettings>
4    <add key="FactoryName" value="DesignPattern.Factory.AmericanFactory"/>
5  </appSettings>
6</configuration>
      当然,这里对于客户来说还不是很直观,这个可以再进一步的去忧化配置文件,这里就不再讲述了。
      到此为上,经过上述的一系列优化后,已经变得很灵活了,能基本适应美国公司和中国公司的需求。
      好,我们现在转到正题(呵,好象也不是什么正题了)。下面我们来看一下创建型设计模式的单件模式,其实这个模式是比较特殊的一种,也是最好理解的。顾名思义,就是只创建一个实例,这在一些特定的场合是非常有用的,比如说最常见的,就是我们进行数据库操作时必须要创建的一个sqlConnection对象,由于数据库连接都是通过这个对象来操作的,所以我们没有必要创建该对象的多个实例,只创建一个就可以了,这样即节省资源又可以避免一些异常的发生,更容易控制。
      其实,在程序开发中,我们已经在不知不觉的使用单件模式了。最简单的就是使用static关键字定义对象,其实这就是一种单件模式了。常见的单件模式的样式如下代码所示:
 
 1private static object ob;
 2        public static object OB
 3        {
 4            get
 5            {
 6                if (ob == null)
 7                {
 8
 9                    ob = new object();
10
11                }
12                return ob;
13            }
14        }
      也可以对该单件模式进行改进,如对于多线程应用程序,我们就应该在上面加一把锁,以防该对象被多次创建:   private static readonly object pad = new object();
        private static object ob;
        public static object OB
        {
            get
            {
               if(ob == null)
               {
                  lock (pad)
                  {
                     if (ob == null)
                     {
                                       
                        ob = new object();
                      }
                }
               }
                return ob;
            }
        }
      如果有些朋友想更多的了解单件模式的话,请看TerryLee写的设计模式系列“ .NET设计模式系列 ”。
      现在我们再回头看看原来的程序,一旦部署后,那么其实这个工厂方法也就确定,由于我们真正要用到的实现方法对象是由该工厂方法来创建的,所以该工厂方法没有必要被多次实例化,在整个系统中我们只需要一个实例久可以了,由这个工厂实例我们就可以创建在计算工资时用到的对象,因此在这里我们就可以用到单件模式了。
  
      再一次修改FactoryUtility.cs文件,得到新的代码:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4using System.Configuration;
 5using System.Reflection;
 6
 7namespace DesignPattern.Common
 8{
 9    public class FactoryUtility
10    {
11        private static readonly object ton = new object();
12        private static IBLL.IFactory factory = null;
13
14        public static IBLL.IFactory Factory
15        {
16            get
17            {
18                if (factory == null)
19                {
20                    lock (ton)
21                    {
22                        if (factory == null)
23                        {
24
25                            string factoryName = ConfigurationSettings.AppSettings["FactoryName"];
26                            factory = (IBLL.IFactory)Assembly.Load("Salary").CreateInstance(factoryName);
27
28                        }
29                    }
30                }
31                return factory;
32            }
33        }
34    }
35}
36
      最后,我们再来看一下,最后实现代码:
 1 double basicSalary;
 2                double result;
 3
 4                basicSalary = Convert.ToDouble(txtBasicSalary.Text.Trim());
 5
 6
 7                IBLL.ISalary salary = FactoryUtility.Factory.CreateSalary();
 8
 9                result = salary.Calculate(basicSalary);
10
11                lbSalary.Text = result.ToString();
      好了,这篇就讲到这里了,希望各位朋友能看得懂。
 
在上一讲中,对系统做了进一步的优化,使之更灵活,以适合需求的变化,也经过几位热心朋友的指点,对一些关键的细节进行了修正,自己也有了更进一步的理解,在此非常感谢他们。
      在这一讲,来看看抽象工厂模式的运用。抽象工厂模式目的是要解决“一系列对象”的创建工作,这里指的是一系列的对象,这跟工厂方法创建某个对象有点类似,个人觉得可以认为工厂方法是一个比较特殊的抽象工厂,是抽象工厂模式的特殊用法,所以在结构上有点类似。
      抽象工厂模式很有用,因为在很多情况下,我们针对某一个解决方案,需要的不仅仅是一个对象就够了,而是需要创建一系列的相关对象来完成。如李建忠老师讲的一个案例里,关于游戏场景的,一个游戏场景往往有许多东西组成,如树,道路,河流等等,而在一个游戏里往往会有多个不同的场景,针对这些不同的场景就应该有不同的树、道路和、河流这些东西。这个时候树、道路、河流这些就是一系列的对象,我们要根据不同的场景来创建相应的这些对象,这里就可以用抽象工厂方法来解决。这里讲的有些笼统了,因为是已有的东西,就带过讲讲了,有兴趣的朋友可以去看李建忠老师的Webcast课程。
      现在我们再来重新回顾前面讲的案例,在前面几篇里,我是把整个的员工工资计算当作一个对象来处理,这里有点违反了设计原则中的“单一职责原则”,这里工资的计算是根据基本工资、奖金和个人所得税来计算的,基本工资这里当作一个输入项,暂且不管,而奖金和个人所得税本身就有自己的业务算法(这里的算法很简单,不过纯粹为了说明设计模式运用,这个就暂且不管,呵呵),所以这里我们应该把奖金和个人所得税的计算单独拿出来,这样更符合“单一职责原则”。对于奖金的计算,不管是美国公司还是中国公司 ,就认为只有一个GetBonus方法,用来返回一个double型的数值,这样我们可以抽象出一个接口,如下:
1namespace DesignPattern.IBLL
2{
3    public interface IBonus
4    {
5        double GetBonus(double basicSalary);
6    }
7}
8
      下面分别就美国公司和中国公司实现该接口:
      美国公司:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.BLL
 6{
 7    public class AmericanBonus : IBLL.IBonus
 8    {
 9        public double GetBonus(double basicSalary)
10        {
11            return basicSalary * 0.15;//奖金计算
12        }
13    }
14}
15
      中国公司:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.BLL
 6{
 7    public class ChineseBonus : IBLL.IBonus
 8    {
 9        public double GetBonus(double basicSalary)
10        {
11            return basicSalary * 0.1;//奖金计算
12        }
13    }
14}
15
      同样对于个人所得税,也作如上处理:
      接口:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.IBLL
 6{
 7    public interface ITax
 8    {
 9        double GetTax(double basicSalary);
10    }
11}
12
      美国公司:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.BLL
 6{
 7    public class AmericanTax : IBLL.ITax
 8    {
 9        public double GetTax(double basicSalary)
10        {
11            return basicSalary * 0.05 + basicSalary * 0.15 * 0.25;//个人所得税计算
12        }
13    }
14}
15
      中国公司:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.BLL
 6{
 7    public class ChineseTax : IBLL.ITax
 8    {
 9        public double GetTax(double basicSalary)
10        {
11            return (basicSalary + basicSalary * 0.1) * 0.4;//个人所得税计算
12        }
13    }
14}
15
      具体实现对象的类我们已经设计好,接下来看看抽象工厂是如何工作的。这里已经很明确我们要返回的有二个对象,那就是计算奖金的IBonus对象和计算个人所得税的ITax对象,所以我们可以抽象出工厂接口如下:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.IBLL
 6{
 7    public interface IFactory
 8    {
 9        IBonus CreateBonus();
10
11        ITax CreateTax();
12    }
13}
14
      针对不同公司来创建相关的具体对象:
      美国公司 :
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.Factory
 6{
 7    public class AmericanFactory : IBLL.IFactory
 8    {
 9        public IBLL.IBonus CreateBonus()
10        {
11            return new BLL.AmericanBonus();
12        }
13
14        public IBLL.ITax CreateTax()
15        {
16            return new BLL.AmericanTax();
17        }
18
19    }
20}
21
      中国公司 :
        1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.Factory
 6{
 7    public class ChineseFactory : IBLL.IFactory
 8    {
 9        public IBLL.IBonus CreateBonus()
10        {
11            return new BLL.ChineseBonus();
12        }
13
14        public IBLL.ITax CreateTax()
15        {
16            return new BLL.ChineseTax();
17        }
18
19    }
20}
21
      在最后计算员工工资时,我们只要得到一个计算奖金的对象和计算个人所得税 的对象,就可以得到最终的工资了
1double basicSalary = Convert.ToDouble(txtBasicSalary.Text.Trim());
2                double salary;
3
4                IBLL.IBonus bonus = FactoryUtility.Factory.CreateBonus();
5                IBLL.ITax tax = FactoryUtility.Factory.CreateTax();
6
7                salary = basicSalary + bonus.GetBonus(basicSalary) - tax.GetTax(basicSalary);
8
9                lbSalary.Text = salary.ToString();
      最后声明一下,这篇文章跟TerryLee 的.NET设计模式(3):抽象工厂模式(Abstract Factory) 在实现上可以说是一样的,只不过加上我自己的说明而已,这样做目的是想通过重构的方法逐渐改善原有代码,使之更加可维护。并且,也可以通过比较更好的理解工厂方法和抽象工厂模式的实际应用。李建忠的课程里有这么一句话“设计模式是通过重构的方法来逐步实现的”(好象不是原话了,呵),确实,对于一个复杂的系统来说,我们不可能一下子就能够设计的很完善,通过重构可以有一个递进的顺序。
 
关于设计模式的杂谈,已经断断续续写了四篇了,但反应好象不怎么样,呵呵,大家都对设计模式不陌生了,再加上这几篇又是很简单的东西,所以没有多少价值,不过不管怎么样,既然写了,还是继续了,给自己一个总结的机会。
      好了,不说废话了,开门见山吧。这讲我主要讲生成器模式,这种模式主要是用来解决“复杂对象的创建”,这类所谓的复杂对象,往往有好几个部分组成,也可以说有好多个算法组成。而往往这些子部分和算法是经常变化的,但是组合在一起的总的算法是相对稳定的。这个时候,我们就可以用生成器模式来解决此类问题。生成器模式需要创建一系列的对应的生成器类,内部封装各子部分或子算法的实现以及最终结果的返回,当具体使用时,实例化需要用到的生成器类,再通过一个指导员角色的类来指示这些子算法的执行,最后可以根据这些算法返回最终我们需要的结果。
      还是按照我以前的思维,通过对原来案例的重构来说明生成器模式的运用场合。在那个案例中,员工工资的的计算,需要通过基本工资、奖金和个人所得税来计算得出,不管是美国公司还是中国公司都是如此,在对抽象工厂的讲述中,我们已经把奖金和个人所得税的计算单独出来,做为一个子部分,再通过这二个子部分去最终得出员工工资,我们可以从这里开始进一步重构。从另一个角度去看这个问题,我们就会发现,对于这二个公司来说,最终的计算员工工资的算法是相对稳定的,而实现这个最终算法的其它部分,如奖金计算和个人所得税的计算是需要变化的。所以,这个解决方案,我们还可以通过生成器模式来解决。
      好,接下来,我们来看具体的实际运用,至于奖金和个人所得税的计算方法跟上一讲中抽象工厂模式里的一样,这里就不再帖出来了,有兴趣的朋友可以看一下上一讲内容。所以,接下来我们要做的就是如何来创建生成器类,上面也提到了,该生成器是用来进行子算法计算的以及最终结果的返回,因此,我们需要二个方法来对应奖金和个人所得税的计算,这二个不需要返回值,最后还需要一个方法来计算最终结果并返回,返回值为double型。
      从上面的分析中,我们先来创建该生成器的接口,代码如下:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.IBLL
 6{
 7    public interface IBuilder
 8    {
 9        void CalculateBonus(double basicSalary);
10
11        void CalculateTax(double basicSalary);
12
13        double GetSalary(double basicSalary);
14    }
15}
16
      接下来,针对美国公司和中国公司分别实现该接口:
     
      美国公司:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.Factory
 6{
 7    public class AmericanBuilder : IBLL.IBuilder
 8    {
 9        private double _bonus;
10        private double _tax;
11        private double _salary;
12
13        public void CalculateBonus(double basicSalary)
14        {
15            IBLL.IBonus bonus = new BLL.AmericanBonus();
16            _bonus = bonus.GetBonus(basicSalary);
17        }
18
19        public void CalculateTax(double basicSalary)
20        {
21            IBLL.ITax tax = new BLL.AmericanTax();
22            _tax = tax.GetTax(basicSalary);
23        }
24
25        public double GetSalary(double basicSalary)
26        {
27            _salary = _bonus + basicSalary - _tax;
28
29            return _salary;
30        }
31
32    }
33}
34
      中国公司:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.Factory
 6{
 7    public class ChineseBuilder : IBLL.IBuilder
 8    {
 9        private double _bonus;
10        private double _tax;
11        private double _salary;
12
13        public void CalculateBonus(double basicSalary)
14        {
15            IBLL.IBonus bonus = new BLL.ChineseBonus();
16            _bonus = bonus.GetBonus(basicSalary);
17        }
18
19        public void CalculateTax(double basicSalary)
20        {
21            IBLL.ITax tax = new BLL.ChineseTax();
22            _tax = tax.GetTax(basicSalary);
23        }
24
25        public double GetSalary(double basicSalary)
26        {
27            _salary = _bonus + basicSalary - _tax;
28
29            return _salary;
30        }
31
32    }
33}
34
      (注:或许有人认为这里对于CalculateTax和CalculateBonus的计算,没有必要再去单独出来一个类了,让人感觉这里有点过度设计。)
        最后,我们还需要一个指导员角色的类来指导这些对象的生成:
 1using System;
 2using System.Collections.Generic;
 3using System.Text;
 4
 5namespace DesignPattern.Common
 6{
 7    public class SalaryManager
 8    {
 9        private double basicSalary;
10
11        public SalaryManager(double basicSalary)
12        {
13            this.basicSalary = basicSalary;
14        }
15
16        public void Construct(IBLL.IBuilder builder)
17        {
18            builder.CalculateBonus(basicSalary);
19
20            builder.CalculateTax(basicSalary);
21        }
22    }
23}
24
      其中的Construct方法,通过传进来的生成器,来指导内部算法的执行。
      最终程序调用如下:
 1 double basicSalary = Convert.ToDouble(txtBasicSalary.Text.Trim());
 2                double salary;
 3
 4                SalaryManager salaryManager = new SalaryManager(basicSalary);
 5
 6                salaryManager.Construct(FactoryUtility.Factory);
 7
 8                salary = FactoryUtility.Factory.GetSalary(basicSalary);
 9
10                lbSalary.Text = salary.ToString();
      呵呵,终于写完了。写文章真是累的,不管是简单还是复杂。这几篇杂谈也主要是想表达在不同的思考方式上,可以有不同的解决方案,况且象我讲的几篇中,不管是工厂方法、抽象工厂还是生成器模式,都有相似的地方,这几篇内容通过重构的方法,对这几种模式进行了比较,从而增加认识的程度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值