设计模式 -- 抽象工厂

还记得吧?我们已经学完了简单工厂和工厂方法了,今天把“抽象工厂”学习完,那么我们的工厂模式就算学完了。

1、什么是“抽象工厂”?

     抽象工厂模式提供一个接口,用语创建相关或依赖对象的家族,而不需要明确指定具体类。这个概念还真是不好理解,没事,我们接着以例子来说明。

     还是关于Pizza饼的故事。Pizza的做法(面团+酱汁+芝士)都是相同的,唯一的差别是他们使用的原料。由于各地区Pizza风味不同,原料使用上自然会有差别,有的地区会在原料上偷工减料,这样就会败坏Pizza长年以来的好名声。为了确保各地区Pizza质量,我们决定要建造一个工厂来生产原料,这个工厂将负责创建原料家族中每一种原料,也就是说工厂将需要生产“面团”,“酱汁”,“芝士”等。这样,每一个地区的原料都必须从工厂取得,那么我们就能保证Pizza的质量了。

2、抽象工厂如何实现?

     首先,我们需要些一个Pizza原料的工厂接口(PizzaIngredientFactory),这个接口负责创建所有原料。接下来我们需要为每个地区创建一个继承自PizzaIngredientFactory的子类来实现每一种创建方法。然后呢,我们需要将各地区的原料工厂整合进各地区的PizzaStore中。

写到这了,还是让我们先看看代码吧

首先,我们要有一个原料工厂

 

//抽象原料工厂
    public interface PizzaIngredientFactory
    {
         Dough createDough();
         Sauce createSauce();
         Cheese createCheece();
         Veggies[] createVeggies();
         Pepperoni createPepperoni();
         Clam createClam();
    }

 

接下来,为各地区创建原料工厂

//纽约地区的原料工厂
    public class NYPizzaIngredientFactory:PizzaIngredientFactory
    {
        public Dough createDough()
        {
            return new ThinCrustDough();
        }
        public Sauce createSauce()
        {
            return new MarinaraSauce();
        }
        public Cheese createCheece()
        {
            return new ReggianoCheese();
        }
        public Veggies[] createVeggies()
        {
            Veggies[] veggies = {new Garlic(),new Onion(),new Mushroom(),new Redpepper()};//注意数组声明方式,[]放在数据类型之后
            return veggies;
        }
        public Pepperoni createPepperoni()
        {
            return new SlicePepperoni();
        }
        public Clam createClam()
        {
            return new FreshClam();
        }
    }
//芝加哥地区的原料工厂
   public class ChicagoPizzaIngredientFactory:PizzaIngredientFactory
    {
        public Dough createDough()
        {
            return new ThickCrustDough();
        }
        public Sauce createSauce()
        {
            return new PlumTomatoSauce();
        }
        public Cheese createCheece()
        {
            return new MazzarellaCheese();
        }
        public Veggies[] createVeggies()
        {
            Veggies[] veggies = { new BlackOlives(), new Spinach(), new EggPlant() };//注意数组声明方式,[]放在数据类型之后
            return veggies;
        }
        public Pepperoni createPepperoni()
        {
            return new SlicePepperoni();
        }
        public Clam createClam()
        {
            return new FrozenClam();
        }
    }

呵呵,看到这里是不是有点糊涂了?没事,你是看到了那些未知的原料的缘故,我们把他们写出来吧。

以下就是所有原料的类图,你会看到有很多很多原料,但是不用担心,我们只是给每个原料写了一个构造放方法,来表明它是什么原料。这个代码自己完成吧。

有了这些原料类,是不是觉得原料工厂好理解了?再来回顾一下,我们的原料工厂根据各地区的不同需求“生产”原料。那么这些原料何时又如何应用到Pizza身上呢?不要着急,往下走!

先让我们看看Pizza吧?你想把它设计成什么呢?普通类?抽象类?接口?呵呵,我们把它设计成抽象类吧,待会你就就会明白的。

 

public abstract class Pizza
    {
        public string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        //每个Pizza都持有一组在准备时会用到的原料
        public Dough dough;//面团
        public Sauce sauce;//酱汁
        public Veggies[] veggies;//蔬菜
        public Cheese cheese;//奶酪
        public Pepperoni pepperoni;//胡椒
        public Clam clam;//蛤蛎

        //抽象方法,这个方法收集Pizza需要的所有原料,而这些原料当然是来自工厂
        public abstract void prepare();

        public void bake()
        {
            Console.WriteLine("烘烤 25 分钟");
        }

        public void cut()
        {
            Console.WriteLine("将Pizza沿对角线切开");
        }

        public void box()
        {
            Console.WriteLine("将Pizza装在官方Pizza盒子中");
        }
    }

 

//奶酪Pizza
    public class CheesePizza:Pizza
    {
        PizzaIngredientFactory pizzaIngredientFactory;

        public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory)
        {
            this.pizzaIngredientFactory = pizzaIngredientFactory;
        }

        public override void prepare()
        {
            Console.WriteLine("prepare "+Name);
            dough = pizzaIngredientFactory.createDough();
            sauce = pizzaIngredientFactory.createSauce();
            cheese = pizzaIngredientFactory.createCheece();
        }
    }
//蛤蛎Pizza
    public class ClamPizza:Pizza
    {
        PizzaIngredientFactory pizzaIngredientFactory;//维护自己的工厂

        public ClamPizza(PizzaIngredientFactory pizzaIngredientFactory)
        {
            this.pizzaIngredientFactory = pizzaIngredientFactory;
        }

        public override void  prepare()
       {
           Console.WriteLine("prepare " + Name);
           dough = pizzaIngredientFactory.createDough();
           sauce = pizzaIngredientFactory.createSauce();
           cheese = pizzaIngredientFactory.createCheece();
           clam = pizzaIngredientFactory.createClam();
       }
    }

看看这个类图吧:

其实,这个Pizza还可以写很多子类,这里就不多写了。每一个具体的Pizza都要重写prepare方法,根据自己的需要来准备原料。

好了,差不多了,咱们进去PizzaStore看看吧!

//抽象的PizzaStore
    public abstract class PizzaStore
    {
        //请注意这里是一个抽象方法!!!
        public abstract Pizza createPizza(string item);

        public Pizza orderPizza(string item)
        {
            Pizza pizza;
            pizza = createPizza(item);
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();

            return pizza;
        }
    }
//重写createPizza方法
        public override Pizza createPizza(string item)
        {
            ChicagoPizzaIngredientFactory chFactory = new ChicagoPizzaIngredientFactory();
            Pizza pizza = null;

            if (item == "cheese")
            {
                pizza = new CheesePizza(chFactory);
                pizza.Name = "Chicago Style Cheese Pizza";
            }
            if (item == "clam")
            {
                pizza = new ClamPizza(chFactory);
                pizza.Name = "Chicago Style Clam Pizza";
            }
            return pizza;
        }
    }

public class NYPizzaStore:PizzaStore
    {
        public override Pizza createPizza(string item)
        {
            NYPizzaIngredientFactory nyFactory = new NYPizzaIngredientFactory();
            Pizza pizza = null;

            if (item == "cheese")
            {
                pizza = new CheesePizza(nyFactory);
                pizza.Name = "New York Style Cheese Pizza";
            }
            if (item == "clam")
            {
                pizza = new ClamPizza(nyFactory);
                pizza.Name = "New York Style Clam Pizza";
            }
            return pizza;
        }
    }

看到了吗?每一个地区的PizzaStore里面都重写了createPizza方法,并且在这个方法中都有自己需要的原料工厂,然后根据不同口味的Pizza来成产不同的Pizza,当然,在这个过程中,就会调用Pizza的工厂来生产原料了。
好了,差不多我们该收场了,请你吃Pizza吧,来!

static void Main(string[] args)
        {
            //纽约风味的蛤蛎Pizza
            NYPizzaStore NYPS = new NYPizzaStore();
            NYPS.orderPizza("clam");

            Console.WriteLine("\n");
            //纽约风味的奶酪Pizza
            NYPS.orderPizza("cheese");

            Console.ReadKey();
        }

OK!!这就完了,不过我们还是回顾一下吧!
首先,我们引入了原料抽象工厂,来创建Pizza原料家族。 这个工厂是抽象的,必然会有具体的工厂来继承它,那就是具体地区的原料工厂。那么这个工厂是怎么和Pizza或者PizzaStore发生联系的呢?------我们在具体Pizza类中维护了一个工厂!这样每个Pizza都会在prepare的时候调用自己的工厂来生产原料。不过要注意啊,这里维护的都是抽象工厂,因为我们不知道,这种口味的Pizza会在哪种风味的PizzaStore中被点。

然后,我们在具体的PizzaStore中维护了各个地区的原料工厂,这样就能在createPizza()的时候,把这个具体的原料工厂给Pizza,那么Pizza就能使用具体的工厂生产原料了!

在这里,我们还意识到了一点,就是工厂方法潜伏在了抽象工厂里。何时?呵呵,Pizza的prepare()方法和PizzaStore中的createPizza()方法。抽象工厂的任务是定义一个负责创建一组产品的接口,这个接口内部的每个方法都负责创建一个具体产品。同时,我们利用抽象工厂的子类来提供这些具体的做法,所以,在抽象工厂中使用抽象方法很自然。

posted on 2013-04-06 16:13  雨过晴空  阅读(213)  评论(0编辑  收藏  举报

导航