设计模式-创建型-工厂模式

  • 2019 年 10 月 3 日
  • 笔记

工厂设计模式:

  顾名思义,该模式是用来生产对象的。在面向对象的设计模式中,万物皆对象,若使用new来创建对象,就会对该对象产生强耦合,加入我们需要更换该对象,那么使用该对象的对象都需要进行修改,这显然违背了开闭原则(OCP)。如果我们使用工厂来产生对象,我们只需要与这个工厂打交道就可以了,无需关心具体的对象,达到解耦的目的。

  接下来我们从实际的案例出发,从无工厂到有工厂的区别。

  去披萨店订购披萨,首先披萨的种类很多(CheesePizza、GreekPizza、DurianPizza{等),披萨的制作流程有prepare、bake、cut、box。

传统模式:

   

 1 internal class Program   2 {   3     private static void Main(string[] args)   4     {   5         new OrderPizza();   6     }   7 }   8   9 internal class OrderPizza  10 {  11     public OrderPizza()  12     {  13         Pizza pizza = null;  14         string orderType = "";  15         do  16         {  17             orderType = Console.ReadLine();  18             if (orderType == "cheese")  19             {  20                 pizza = new CheesePizza();  21                 pizza.setName("干酪披萨");  22             }  23             else if (orderType == "greek")  24             {  25                 pizza = new GreekPizza();  26                 pizza.setName("希腊披萨");  27             }  28             else  29             {  30                 Console.WriteLine("订购失败");  31                 break;  32             }  33             //开始制作  34             pizza.prepare();  35             pizza.bake();  36             pizza.cut();  37             pizza.box();  38         } while (true);  39     }  40 }  41  42 internal abstract class Pizza  43 {  44     private string name;  45  46     public abstract void prepare();  47  48     public void bake()  49     {  50         Console.WriteLine($"{this.name} 烘培");  51     }  52  53     public void cut()  54     {  55         Console.WriteLine($"{this.name} 修剪");  56     }  57  58     public void box()  59     {  60         Console.WriteLine($"{this.name} 打包");  61     }  62  63     public void setName(string name)  64     {  65         this.name = name;  66     }  67 }  68  69 internal class CheesePizza : Pizza  70 {  71     public override void prepare()  72     {  73         Console.WriteLine("干酪披萨准备中");  74     }  75 }  76  77 internal class GreekPizza : Pizza  78 {  79     public override void prepare()  80     {  81         Console.WriteLine("希腊披萨准备中");  82     }  83 }

view code

  传统模式的优缺点:

    1、比较好理解,易于操作

    2、违反OCP原则,即对扩展开放,对修改关闭。

    3、这里只订购了两种pizza,若现在又新增了品种DurianPizza,这个时候就需要添加该类以及修改OrderPizza中的代码。从上图中可以看出,OrderPizza依赖抽象类及具体实现类的,那怎样才能切断OrderPizza与类之间的依赖关系呢。于是我们想到,可以定义一个工厂,订购者不需要知道具体pizza的制作流程,只要直到我需要订购什么类型的pizza就行了。

 

简单工厂模式:

   

  1 internal class Program    2 {    3     private static void Main(string[] args)    4     {    5         new OrderPizza();    6     }    7 }    8    9 internal class OrderPizza   10 {   11     public OrderPizza()   12     {   13         Pizza pizza = null;   14         string orderType = "";   15         do   16         {   17             Console.Write("请输入订购类型:");   18             orderType = Console.ReadLine();   19             pizza = SimpleFactory.createPizza(orderType);   20             if (pizza == null)   21             {   22                 Console.WriteLine("订购失败");   23                 break;   24             }   25             //开始制作   26             pizza.prepare();   27             pizza.bake();   28             pizza.cut();   29             pizza.box();   30         } while (true);   31     }   32 }   33   34 internal static class SimpleFactory   35 {   36     public static Pizza createPizza(string orderType)   37     {   38         Pizza pizza = null;   39         do   40         {   41             if (orderType == "cheese")   42             {   43                 pizza = new CheesePizza();   44                 pizza.setName("干酪披萨");   45             }   46             else if (orderType == "greek")   47             {   48                 pizza = new GreekPizza();   49                 pizza.setName("希腊披萨");   50             }   51             else if (orderType == "durian")   52             {   53                 pizza = new DurianPizza();   54                 pizza.setName("榴莲披萨");   55             }   56             return pizza;   57         } while (true);   58     }   59 }   60   61 internal abstract class Pizza   62 {   63     private string name;   64   65     public abstract void prepare();   66   67     public void bake()   68     {   69         Console.WriteLine($"{this.name} 烘培");   70     }   71   72     public void cut()   73     {   74         Console.WriteLine($"{this.name} 修剪");   75     }   76   77     public void box()   78     {   79         Console.WriteLine($"{this.name} 打包");   80     }   81   82     public void setName(string name)   83     {   84         this.name = name;   85     }   86 }   87   88 internal class CheesePizza : Pizza   89 {   90     public override void prepare()   91     {   92         Console.WriteLine("干酪披萨准备中");   93     }   94 }   95   96 internal class GreekPizza : Pizza   97 {   98     public override void prepare()   99     {  100         Console.WriteLine("希腊披萨准备中");  101     }  102 }  103  104 internal class DurianPizza : Pizza  105 {  106     public override void prepare()  107     {  108         Console.WriteLine("榴莲披萨准备中");  109     }  110 }

view code

  简单工厂模式优缺点:

    1、由代码可以看出,虽然简单工厂模式一定程度上减少了因需求变更而导致的代码更改,但是实际仍违背了OCP原则。

    2、所以简单工厂模式只适合产品对象相对较少,且产品固定的需求,对产品变化无常的需求来说显然不适合。

 

工厂方法设计模式:

  披萨项目需求变更,客户点披萨时可以点不同口味的披萨。 

   

  1 internal class Program    2 {    3     private static void Main(string[] args)    4     {    5         new BJOrderPizza();    6     }    7 }    8    9 internal abstract class OrderPizza   10 {   11     public OrderPizza()   12     {   13         Pizza pizza = null;   14         string orderType = "";   15         do   16         {   17             Console.Write("请输入订购类型:");   18             orderType = Console.ReadLine();   19             pizza = createPizza(orderType);   20             if (pizza == null)   21             {   22                 Console.WriteLine("订购失败");   23                 break;   24             }   25             //开始制作   26             pizza.prepare();   27             pizza.bake();   28             pizza.cut();   29             pizza.box();   30         } while (true);   31     }   32   33     public abstract Pizza createPizza(string orderType);   34 }   35   36 internal class BJOrderPizza : OrderPizza   37 {   38     public override Pizza createPizza(string orderType)   39     {   40         Pizza pizza = null;   41         if (orderType == "cheese")   42         {   43             pizza = new BJCheesePizza();   44         }   45         else if (orderType == "greek")   46         {   47             pizza = new BJGreekPizza();   48         }   49         return pizza;   50     }   51 }   52   53 internal class LDOrderPizza : OrderPizza   54 {   55     public override Pizza createPizza(string orderType)   56     {   57         Pizza pizza = null;   58         if (orderType == "cheese")   59         {   60             pizza = new LDCheesePizza();   61         }   62         else if (orderType == "greek")   63         {   64             pizza = new LDGreekPizza();   65         }   66         return pizza;   67     }   68 }   69   70 internal abstract class Pizza   71 {   72     private string name;   73   74     public abstract void prepare();   75   76     public void bake()   77     {   78         Console.WriteLine($"{this.name} 烘培");   79     }   80   81     public void cut()   82     {   83         Console.WriteLine($"{this.name} 修剪");   84     }   85   86     public void box()   87     {   88         Console.WriteLine($"{this.name} 打包");   89     }   90   91     public void setName(string name)   92     {   93         this.name = name;   94     }   95 }   96   97 internal class BJCheesePizza : Pizza   98 {   99     public override void prepare()  100     {  101         Console.WriteLine("北京的干酪披萨准备中");  102     }  103 }  104  105 internal class BJGreekPizza : Pizza  106 {  107     public override void prepare()  108     {  109         Console.WriteLine("北京的希腊披萨准备中");  110     }  111 }  112  113 internal class LDCheesePizza : Pizza  114 {  115     public override void prepare()  116     {  117         Console.WriteLine("伦敦的干酪披萨准备中");  118     }  119 }  120  121 internal class LDGreekPizza : Pizza  122 {  123     public override void prepare()  124     {  125         Console.WriteLine("伦敦的希腊披萨准备中");  126     }  127 }

view code

  工厂方法模式的优缺点:

    1、让父类的实现延迟到子类中去,减少判断。

    2、换汤不换药,和简单工厂模式类似,一般适用于产品对象相对较少,且产品固定的需求。

    3、工厂方法一定程度上减轻了工厂的职责,将职责细化,避免工厂类无法正常运行而导致程序崩溃。

参考:https://www.jianshu.com/p/38493eb4ffbd