zoukankan      html  css  js  c++  java
  • 工厂模式

      所谓工厂,肯定是和生产有关。工厂模式主要包括工厂方法模式和抽象工厂模式,有些人把简单工厂也作为一种模式,在本文我分别讨论简单工厂模式,工厂方法模式,抽象工厂模式。这些模式中同样也和生产有关。接下来,我们来看看各种工厂的特点。

    简单工厂模式

      上面说了只是有些人把简单工厂看做是设计模式,其实是一种编程习惯,无论是否是设计模式,本文将先看看其用法,然后简单给出其类图,最后说出其特点。

    本节将面对多种比萨,先看看当顾客需要一个比萨时的过程:

    1.根据类型,制作一个比萨形状。2.然后进行烘烤3.切4.打包

    如果不熟悉的话,完全可以把其想想成面包的做法。

    当顾客根据自己的需求要一个比萨时,用代码模拟这个过程如下:

    public  class Pizza
        {
           public void bake() { }
           public void cut() { }
           public void box() { }
        }
        public class CheesePizza:Pizza
        {
            public CheesePizza()
            { }
        }
        public class GreekPizza : Pizza
        {
            public GreekPizza(){}
        }
        public class PepperoniPizza:Pizza
        {
            public PepperoniPizza() { }
        }
        public  class Store
        {
          public  Pizza OrderPizza(string type)
            {
                Pizza pizza = null;
                if (type=="Cheese")
                {
                    pizza = new CheesePizza();
                }
                else if (type=="Greek")
                {
                    pizza = new GreekPizza();
                }
                else if (type == "Pepperoni")
                {
                    pizza = new PepperoniPizza();
                }
                pizza.bake();
                pizza.cut();
                pizza.box();
                return pizza;
            }
        }

      以上的设计方法和我们的以前提到的过的原则(找出经常变化的部分,抽象成类),很明显在if else 的地方发生经常性变化。

    接下来就把if else 放到一个类中。修改后的代码

    public  class Store
    {
      public  Pizza OrderPizza(string type)
        {
            Pizza pizza = null;
            //if (type=="Cheese")
            //{
            //    pizza = new CheesePizza();
            //}
            //else if (type=="Greek")
            //{
            //    pizza = new GreekPizza();
            //}
            //else if (type == "Pepperoni")
            //{
            //    pizza = new PepperoniPizza();
            //}
            SimpleFactory factory = new SimpleFactory();
            pizza =factory.CreatePizza(type);
            pizza.bake();
            pizza.cut();
            pizza.box();
            return pizza;
        }
    }

    public class SimpleFactory
    {
        public Pizza CreatePizza(string type)
        {
            Pizza pizza = null;
            if (type == "Cheese")
            {
                pizza = new CheesePizza();
            }
            else if (type == "Greek")
            {
                pizza = new GreekPizza();
            }
            else if (type == "Pepperoni")
            {
                pizza = new PepperoniPizza();
            }
            return pizza;
        }
    }

    这样的话,就可以遵循了把变化的部分抽象成一个类。下次需要变化,只需要对变化的类的部分做修改即可。下面给出其UML图。

    image

      简单工厂的目的,主要负责实现生产对象的细节,根据订单来生产。每一个商店有对应着自己的工厂。在此,可以将OrderPizza是工厂的一个客 户,当然还可以是其他类似的方法,比如PizzaShopMenu也可以是工厂的客户。客户就是为了获取工厂生成的对象。前者是为了卖给people,后 者是为了使用Pizza类获取其描述和价格等。这样遵循了找出变化的部分,将其封装到一个类中的原则,从而到达了复用的目的。

      简单工厂之所以简单是因为它只根据需要,来生产出来指定的Pizza。特点:所有的产品都由一个工厂来生产。

      接下来我们来看看工厂方法的实现。

    工厂方法模式

      如果是有多个商店,各个商店对于相同名字的pizza都有自己的生成方法。而且,除了生成方法不一样,其他的烘烤,切,打包,都是使用一样的步骤。下面就该我们的工厂方法模式出厂了。

      由于生产pizza的方法决定于各个商店,不妨假设有两个商店。其公共的基类,应该有一个抽象的生产方法,具体的生产方法决定于商店。其UML类图如下:

    image

      上面的PizzaStore是一个抽象类,该类具有一个CreatePizza的抽象方法,真正实现的是具体的商店。

    除了有多种商店,每个商店有多种Pizza类,而且是Pizza名是相同的,只是地区不一样,下面Pizza类的命名方式为:地区+Pizza名,其UML类图为:

    image

      商店和pizza的大致联系如下图:

    image

      在工厂方法中,使用了一个重要的原则:

    原则:依赖倒置:依赖于抽象,不要依赖于具体类

      如果没有使用上述原则,而是直接让店铺依赖于每个Pizza类。

    image

      如果Pizza的实现变化了,就必须改变PizzaStore。每增加一个Pizza都会增加一个依赖。如果使用工厂方法设计模式的话,其依赖于抽 象,不依赖与具体类。我们可以抽象出一个Pizza类,让所有商店以及所有的Pizza类来依赖它。这里涉及到一个依赖倒置的另一种解释,高层组件和底层 组件都依赖于抽象。而不依赖与具体的实现,高层组件是有底层组件的方法构建 而成的。PizzaStore是由Pizza的Bake,Cut,Box方法构建。那么根据这个原则其大致图为:

    image

      这样的设计方法,对于任何添加新的Pizza种类,不会影响到PizzaStore。从而实现了松耦合的效果。

    工厂方法和简单工厂设计模式的区别:简单工厂设计模式,只有一个工厂,每次增加新类,都需要修改SimpleFactory的代码,不能对工厂的创 建方式进行分类管理,全部都由一个工厂制作。工厂方法,可以对工厂进行扩展,也就是可以对Pizza类分类管理,可以由不同的工厂去创建,更加灵活。这个好比,简单工厂只有可以看成商店只有一家供应商,需要什么样子的产品,直接给工厂说,工厂如果没有的话要不然制造出来对象,要不然告诉供应商,我不能创建。工厂方法可以看成商店有多个供应商,需要的产品,可以有多重选择。

    下面给出工厂方法的测试代码:

    PizzaStore store = new NYPizzaStore();
    store.OrderPizza("Greek");
    store.OrderPizza("Cheese");

    store = new ChicagoPizzaStore();
    store.OrderPizza("Greek");
    store.OrderPizza("Cheese");

    抽象工厂模式

      抽象工厂模式的定义:抽象工厂模式提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体的类。

    定义感觉还真有些抽象,下面就把他易于理解化。

    抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际的具体产品是什么。这样客户就从具体的产品中被解耦了。

    下面就来看个关于南北方饮食的差异:

      主食分别是北方风味和南方风味。无论是南方味道还是北方味道,其都包括主食和调料:北方主要是以面食和辣椒为主,南方主要是以大米和糖为主。

      下面就使用抽象工厂来抽象两个接口,分别是主食和调料,对应还有两种风味。

    image

      接下来是调料和事务的对应实现:

    image

      接下来看看其联系

    image

      在上图中,AbstractFactory接口定义了两个方法来分别获得调料和主食。下面的南北风味是可以看出其具体实现。

    这样就可以在前台查看风味的主食和调料就不用关心具体的实现。直接调用其Create方法就行了。

    测试代码:

    class Program
       {
           static void Main(string[] args)
           {
               Console.WriteLine("南方风味:");
               AbstractFactory factory = new SouthFood();
               Food food = factory.CreateFood();
               Console.WriteLine(food.Name);
               Condiment condiment = factory.CreateCondiment();
               Console.WriteLine(condiment.Name);


               Console.WriteLine("北方风味:");
               AbstractFactory factory2 = new NouthFood();
               Food food2 = factory2.CreateFood();
               Console.WriteLine(food2.Name);
               Condiment condiment2 = factory2.CreateCondiment();
               Console.WriteLine(condiment2.Name);
               Console.ReadKey();
           }
       }

      从该实例,可以看出抽象工厂是定义了多类产品。工厂方法是一个对象有多种做法,所以在抽象工厂中可以使用多个工厂方法。如果理解了工厂方法,那么抽象工厂应该更好理解些。

    抽象工厂是单个接口定义了多个方法,所以具体的工厂肯定都要实现创建方法。

    源码

    FactoryPattern.zip

    转自 http://www.cnblogs.com/lzhp/p/3375041.html

  • 相关阅读:
    LeetCode 1110. Delete Nodes And Return Forest
    LeetCode 473. Matchsticks to Square
    LeetCode 886. Possible Bipartition
    LeetCode 737. Sentence Similarity II
    LeetCode 734. Sentence Similarity
    LeetCode 491. Increasing Subsequences
    LeetCode 1020. Number of Enclaves
    LeetCode 531. Lonely Pixel I
    LeetCode 1091. Shortest Path in Binary Matrix
    LeetCode 590. N-ary Tree Postorder Traversal
  • 原文地址:https://www.cnblogs.com/xuekai-to-sharp/p/3375581.html
Copyright © 2011-2022 走看看