第四课 简单工厂模式(Simple Factory)

 

第四课 简单工厂模式(Simple Factory

    工厂模式的作用就如他的名字,将大量实现共同接口的产品实例话返回,就像真正的工厂一样。工厂模式可以动态的决定将哪一个类实例化,不必实现知道每次要实例化哪一个类。工厂方式呢,有三种形态:

1.       简单工厂(Simple Factory)模式:又称静态工厂方法模式,是最常见的工厂实现。

2.       工厂方法(Factory Method)模式:又称多态性工厂(Polymorphic Factory)模式,貌似了解的人就不多了。

3.       抽象工厂(Abstract Factory)模式:又称工具箱(Toolkit)模式。常见,知道的人很多,但很多人都是错误的理解。

 

很多人可能这么说“工厂模式直接基于父子,子类的继承和转换”这是一个设计师群里的人给我回答的,他还给我“废话”了很多,其实我知道,他根本不了解工厂模式,只是用过简单工厂,以为工厂模式就是简单工厂了。这里我可以说,这个理解是错误的,工厂模式的3种形态都有自己的存在价值。(目前工厂方法我还没体会到,需要继续学习)所以首先大家要端正自己的学习态度,然后好好体会。

 

这节课介绍简单工厂模式。

    简单工厂模式,是不同的工厂方法模式的一个特殊实现。为什么这么说呢,往下看,嘿嘿。

    咱们用个最直接的办法,从例子还是看起。(Java与模式的例子)

    现在有一个农场公司,专门销售各类水果,暂时定为

l         葡萄(Grape

l         草莓(Strawberry

l         苹果(Apple

这里首先定义了一个水果类(Fruit)里面抽取了水果的三个阶段

u       种植plant()

u       生长grow()

u       收获harvest()

Fruit 接口定义如下

1.        public interface Fruit

2.        {

3.            void grow();

4.         

5.            void harvest();

6.         

7.            void plant();

8.        }

 

下面看苹果

1.        public class Apple implements Fruit

2.        {

3.         

4.            public void grow()

5.            {

6.                System.out.println("Apple is growing...");

7.            }

8.         

9.            public void harvest()

10.         {

11.             System.out.println("Apple has been harvested.");

12.         }

13.      

14.         public void plant()

15.         {

16.             System.out.println("Apple has been planted.");

17.         }

18.      

19.         public int getTreeAge(){ return treeAge; }

20.      

21.         public void setTreeAge(int treeAge){ this.treeAge = treeAge; }

22.      

23.         private int treeAge;

24.     }

 

苹果是多年生植物,这里加了一个TreeAge作为扩展的属性。

 

接着葡萄

 

1.        public class Grape implements Fruit

2.        {

3.            public void grow()

4.            {

5.                System.out.println("Grape is growing...");

6.            }

7.         

8.            public void harvest()

9.            {

10.             System.out.println("Grape has been harvested.");

11.         }

12.      

13.         public void plant()

14.         {

15.             System.out.println("Grape has been planted.");

16.         }

17.      

18.         public boolean getSeedless()

19.         {

20.             return seedless;

21.         }

22.      

23.         public void setSeedless(boolean seedless)

24.         {

25.             this.seedless = seedless;

26.         }

27.      

28.         private boolean seedless;

29.     }

 

同样由于葡萄分为有子和无子的,扩展了Seedless属性。

 

最后草莓

1.         

2.        public class Strawberry implements Fruit

3.        {

4.            

5.            public void grow()

6.            {

7.                System.out.println("Strawberry is growing...");

8.            }

9.         

10.         public void harvest()

11.         {

12.             System.out.println("Strawberry has been harvested.");

13.         }

14.      

15.         public void plant()

16.         {

17.             System.out.println("Strawberry has been planted.");

18.         }

19.      

20.     }

草莓没有扩展属性。

 

然后园丁登场了。

1.        public class FruitGardener

2.        {

3.            public static Fruit factory(String which) throws BadFruitException

4.            {

5.                if (which.equalsIgnoreCase("apple"))

6.                {

7.                    return new Apple();

8.                }

9.                else if (which.equalsIgnoreCase("strawberry"))

10.             {

11.                 return new Strawberry();

12.             }

13.             else if (which.equalsIgnoreCase("grape"))

14.             {

15.                 return new Grape();

16.             }

17.             else

18.             {

19.                 throw new BadFruitException("Bad fruit request");

20.             }

21.         }

22.     }

园丁(FruitGardener)会根据客户需求,生产出不同的水果(好像生产用在这里有点牵强哦,算了)。如果接到不合法的要求,则会抛出BadFruitException异常。

1.        public class BadFruitException extends Exception

2.        {

3.            public BadFruitException(String msg)

4.            {

5.                super(msg);

6.            }

7.        }

 

在使用的时候,客户端只需要盗用FruitGardenerfactory()即可。如下。

1.        try

2.        {

3.          FruitGardener.factory("grape");

4.          FruitGardener.factory("apple");

5.          FruitGardener.factory("strawberry");

6.          ...

7.        }

8.        catch(BadFruitException e)

9.        {

10.       do...

11.     }

 

示例代码到此结束。

现在咱们来回顾一下。首先园丁类FruitGardener就是简单工厂类的实现了。

然后分析下,首先有3种水果,这就是我们这个工厂需要生产的对象了。那么示例怎么处理的呢。它首先定义了 Fruit水果的一个接口。将水果共通的特性抽取出来。然后分别给三种水果实现了对应的类对象。最后,在通过园丁类(工厂类)的Factory(“水果名”)这一静态方法,返回类对象。上述几点构成了简单工厂模式的实现。

很简单吧。但是你注意到这里面的关键点了吗?

首先,模式的核心是工厂类,这个类通过必要的逻辑判断(其实一般就是标志了),决定什么时候创建哪一个产品的实例,并返回产品接口引用。从而实现了用接口引用多个实例对象,达到 对产品的可扩展性。如果新增一个产品,只需要新实现一个产品,并修改工厂方法,返回新产品即可。对于产品而言,简单工厂实现了开闭原则,这是优点。但是新增产品后,必然导致了工厂方法的修改,这是他存在的缺点。

 

在产品种类很相对稳定,取得产品逻辑相对简单的情况下,简单工厂无疑是一个最佳选择。他方便实现,简化取得产品的逻辑,并且有着良好的扩展性。

但是要想进一步提高代码的可扩展性,进一步遵循开闭原则,则需要使用工厂方法模式。下一节我们就来讨论他。

 

简单工厂简单吧~

 

有人反映没体现出好处来,追加一个例子,出自《大话设计模式》

 

目的:要实现一个计算器通用工具类。

        根据可变性封装原则,要把这里的计算逻辑进行封装。根据依赖倒转原则,要依靠抽象不要依靠实现。经过分析,不管什么计算,都需要2个计算数和一个获得结果的方法,所以抽象出来了一个计算类Operation.(四则运算也可以分解为各个简单运算的)。

        下面给出了常见的各个算法的逻辑实现类(加减乘除开方等等),这里不介绍了。然后通过一个简单工厂方法,根据传入的运算符号,返回相应的运算逻辑类实例。这样做有什么好处了呢。首先自然是开闭原则。假设我加法运算需要修改,我只需要修改加法运算类GetResult()的实现,不需要修改基类方法,并不影响调用运算类的代码。这就达到了开闭原则的对修改关闭,对扩展开放。但是简单工厂的缺点还是存在的,如果新增计算逻辑对象的话,必须要修改工厂类,这就决定了应用简单工厂时,应当基本可以确定逻辑不会变化。例如本例中,我实际应用中可能就只会涉及到这些计算逻辑。所以采用简单工厂。

         貌似我又说了很多废话,大家可以自己实现一个计算类,来比较一下。总之还是慢慢体会。

 

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. namespace OperationLibrary
  5. {
  6.     /// <summary>
  7.     /// 运算类
  8.     /// </summary>
  9.     public class Operation
  10.     {
  11.         private double _numberA = 0;
  12.         private double _numberB = 0;
  13.         /// <summary>
  14.         /// 数字A
  15.         /// </summary>
  16.         public double NumberA
  17.         {
  18.             get
  19.             {
  20.                 return _numberA;
  21.             }
  22.             set
  23.             {
  24.                 _numberA = value;
  25.             }
  26.         }
  27.         /// <summary>
  28.         /// 数字B
  29.         /// </summary>
  30.         public double NumberB
  31.         {
  32.             get
  33.             {
  34.                 return _numberB;
  35.             }
  36.             set
  37.             {
  38.                 _numberB = value;
  39.             }
  40.         }
  41.         /// <summary>
  42.         /// 得到运算结果
  43.         /// </summary>
  44.         /// <returns></returns>
  45.         public virtual double GetResult()
  46.         {
  47.             double result = 0;
  48.             return result;
  49.         }
  50.         /// <summary>
  51.         /// 检查输入的字符串是否准确
  52.         /// </summary>
  53.         /// <param name="currentNumber"></param>
  54.         /// <param name="inputString"></param>
  55.         /// <returns></returns>
  56.         public static string checkNumberInput(string currentNumber, string inputString)
  57.         {
  58.             string result = "";
  59.             if (inputString == ".")
  60.             {
  61.                 if (currentNumber.IndexOf(".") < 0)
  62.                 {
  63.                     if (currentNumber.Length == 0)
  64.                         result = "0" + inputString;
  65.                     else
  66.                         result = currentNumber + inputString;
  67.                 }
  68.             }
  69.             else if (currentNumber == "0")
  70.             {
  71.                 result = inputString;
  72.             }
  73.             else
  74.             {
  75.                 result = currentNumber + inputString;
  76.             }
  77.             return result;
  78.         }
  79.     }
  80.     /// <summary>
  81.     /// 加法类
  82.     /// </summary>
  83.     class OperationAdd : Operation
  84.     {
  85.         public override double GetResult()
  86.         {
  87.             double result = 0;
  88.             result = NumberA + NumberB;
  89.             return result;
  90.         }
  91.     }
  92.     /// <summary>
  93.     /// 减法类
  94.     /// </summary>
  95.     class OperationSub : Operation
  96.     {
  97.         public override double GetResult()
  98.         {
  99.             double result = 0;
  100.             result = NumberA - NumberB;
  101.             return result;
  102.         }
  103.     }
  104.     /// <summary>
  105.     /// 乘法类
  106.     /// </summary>
  107.     class OperationMul : Operation
  108.     {
  109.         public override double GetResult()
  110.         {
  111.             double result = 0;
  112.             result = NumberA * NumberB;
  113.             return result;
  114.         }
  115.     }
  116.     /// <summary>
  117.     /// 除法类
  118.     /// </summary>
  119.     class OperationDiv : Operation
  120.     {
  121.         public override double GetResult()
  122.         {
  123.             double result = 0;
  124.             if (NumberB == 0)
  125.                 throw new Exception("除数不能为0。");
  126.             result = NumberA / NumberB;
  127.             return result;
  128.         }
  129.     }
  130.     /// <summary>
  131.     /// 平方类
  132.     /// </summary>
  133.     class OperationSqr : Operation
  134.     {
  135.         public override double GetResult()
  136.         {
  137.             double result = 0;
  138.             result = NumberB * NumberB;
  139.             return result;
  140.         }
  141.     }
  142.     /// <summary>
  143.     /// 平方根类
  144.     /// </summary>
  145.     class OperationSqrt : Operation
  146.     {
  147.         public override double GetResult()
  148.         {
  149.             double result = 0;
  150.             if (NumberB < 0)
  151.                 throw new Exception("负数不能开平方根。");
  152.             result = Math.Sqrt(NumberB);
  153.             return result;
  154.         }
  155.     }
  156.     /// <summary>
  157.     /// 相反数类
  158.     /// </summary>
  159.     class OperationReverse : Operation
  160.     {
  161.         public override double GetResult()
  162.         {
  163.             double result = 0;
  164.             result = -NumberB;
  165.             return result;
  166.         }
  167.     }
  168.     /// <summary>
  169.     /// 运算类工厂
  170.     /// </summary>
  171. public class OperationFactory
  172. {
  173.     public static Operation createOperate(string operate)
  174.     {
  175.         Operation oper = null;
  176.         switch (operate)
  177.         {
  178.             case "+":
  179.                 {
  180.                     oper = new OperationAdd();
  181.                     break;
  182.                 }
  183.             case "-":
  184.                 {
  185.                     oper = new OperationSub();
  186.                     break;
  187.                 }
  188.             case "*":
  189.                 {
  190.                     oper = new OperationMul();
  191.                     break;
  192.                 }
  193.             case "/":
  194.                 {
  195.                     oper = new OperationDiv();
  196.                     break;
  197.                 }
  198.             case "sqr":
  199.                 {
  200.                     oper = new OperationSqr();
  201.                     break;
  202.                 }
  203.             case "sqrt":
  204.                 {
  205.                     oper = new OperationSqrt();
  206.                     break;
  207.                 }
  208.             case "+/-":
  209.                 {
  210.                     oper = new OperationReverse();
  211.                     break;
  212.                 }
  213.         }
  214.         return oper;
  215.     }
  216. }
  217. }

调用方法:

 

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using OperationLibrary;
  5. namespace 计算器控制台
  6. {
  7.     class Program
  8.     {
  9.         static void Main(string[] args)
  10.         {
  11.             try
  12.             {
  13.                 Console.Write("请输入数字A:");
  14.                 string strNumberA = Console.ReadLine();
  15.                 Console.Write("请选择运算符号(+、-、*、/):");
  16.                 string strOperate = Console.ReadLine();
  17.                 Console.Write("请输入数字B:");
  18.                 string strNumberB = Console.ReadLine();
  19.                 string strResult = "";
  20.                 Operation oper;
  21.                 oper = OperationFactory.createOperate(strOperate);
  22.                 oper.NumberA = Convert.ToDouble(strNumberA);
  23.                 oper.NumberB = Convert.ToDouble(strNumberB);
  24.                 strResult = oper.GetResult().ToString();
  25.                 Console.WriteLine("结果是:" + strResult);
  26.                 Console.ReadLine();
  27.             }
  28.             catch (Exception ex)
  29.             {
  30.                 Console.WriteLine("您的输入有错:" + ex.Message);
  31.             }
  32.         }
  33.     }
  34. }

作者:王文斌

转载请注明出处

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值