仓库源文站点原文


title: 抽象工厂模式(Abstract Factory Pattern) tags:


抽象工厂模式的定义是:

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

<!-- more -->

实现

上一篇{% post_link Factory-Method-Pattern '工厂方法模式(Factory Method Pattern)' %}中,我们已经能生产不同区域的不同披萨了,但是每家店使用的原料都是不一致的,做为一个好的连锁店,我们需要确保原料的高质量。这里需要注意的是,即使是同一种披萨,在不同的区域使用的原料也是会有区别的,会根据当地人的口味进行调整,那么为了保证以上两点,我们需要建立原料的工厂。

首先,即使原料略有不同,但是原料的种类就是那么几种:面团(Dough)、酱(Sauce)、起司(Cheese)、蔬菜(Veggies)、意大利辣香肠(Pepperoni)和蛤(Clam)。

大多数的披萨,都是由上面这些原料组成的,所以我们的原料工厂要保证能生产这些原料:

/// <summary>
/// 披萨原料工厂
/// </summary>
public interface PizzaIngredientFactory
{
    public IDough createDough();
    public ISauce createSauce();
    public ICheese createCheese();
    public IVeggies[] createVeggies();
    public IPepperoni createPepperoni();
    public IClams createClam();
}

每种原料下面又分成好多种不同地区的原料,以面团为例:

namespace DesignPattern.AbstractFactoryPattern
{
    /// <summary>
    /// 面团
    /// </summary>
    public interface IDough
    {
        public string ToString();
    }

    /// <summary>
    /// 厚皮面团
    /// </summary>
    public class ThickCrustDough : IDough
    {
        public override string ToString()
        {
            return "厚皮面团";
        }
    }

    /// <summary>
    /// 薄皮面团
    /// </summary>
    public class ThinCrustDough : IDough
    {
        public override string ToString()
        {
            return "薄皮面团";
        }
    }
}

其他种类的原料也是类似:

namespace DesignPattern.AbstractFactoryPattern
{
    /// <summary>
    /// 酱
    /// </summary>
    public interface ISauce
    {
        public string ToString();
    }

    /// <summary>
    /// 意大利西红柿酱
    /// </summary>
    public class MarinaraSauce : ISauce
    {
        public string ToString()
        {
            return "意大利西红柿酱";
        }
    }

    /// <summary>
    /// 梅子番茄酱
    /// </summary>
    public class PlumTomatoSauce : ISauce
    {
        public string ToString()
        {
            return "梅子西红柿酱";
        }
    }
}
namespace DesignPattern.AbstractFactoryPattern
{
    /// <summary>
    /// 起司
    /// </summary>
    public interface ICheese
    {
        public string ToString();
    }

    /// <summary>
    /// 芝士丝
    /// </summary>
    public class MozzarellaCheese : ICheese
    {
        public string ToString()
        {
            return "芝士丝";
        }
    }

    /// <summary>
    /// 帕尔马干酪
    /// </summary>
    public class ParmesanCheese : ICheese
    {
        public string ToString()
        {
            return "帕尔马干酪";
        }
    }

    /// <summary>
    /// 雷吉亚诺奶酪
    /// </summary>
    public class ReggianoCheese : ICheese
    {
        public string ToString()
        {
            return "雷吉亚诺奶酪";
        }
    }
}
namespace DesignPattern.AbstractFactoryPattern
{
    /// <summary>
    /// 蔬菜
    /// </summary>
    public interface IVeggies
    {
        public string ToString();
    }

    /// <summary>
    /// 茄子
    /// </summary>
    public class Eggplant : IVeggies
    {
        public override string ToString()
        {
            return "茄子";
        }
    }

    /// <summary>
    /// 大蒜
    /// </summary>
    public class Garlic : IVeggies
    {
        public override string ToString()
        {
            return "大蒜";
        }
    }

    /// <summary>
    /// 菠菜
    /// </summary>
    public class Spinach : IVeggies
    {
        public override string ToString()
        {
            return "菠菜";
        }
    }

    /// <summary>
    /// 洋葱
    /// </summary>
    public class Onion : IVeggies
    {
        public override string ToString()
        {
            return "洋葱";
        }
    }

    /// <summary>
    /// 蘑菇
    /// </summary>
    public class Mushroom : IVeggies
    {
        public override string ToString()
        {
            return "蘑菇";
        }
    }

    /// <summary>
    /// 辣椒
    /// </summary>
    public class RedPepper : IVeggies
    {
        public override string ToString()
        {
            return "辣椒";
        }
    }

    /// <summary>
    /// 黑橄榄
    /// </summary>
    public class BlackOlives : IVeggies
    {
        public override string ToString()
        {
            return "黑橄榄";
        }
    }
}
namespace DesignPattern.AbstractFactoryPattern
{
    /// <summary>
    /// 意大利辣香肠
    /// </summary>
    public interface IPepperoni
    {
        public string ToString();
    }

    public class SlicedPepperoni : IPepperoni
    {
        public override String ToString()
        {
            return "切意大利辣香肠";
        }
    }
}
namespace DesignPattern.AbstractFactoryPattern
{
    /// <summary>
    /// 蛤
    /// </summary>
    public interface IClams
    {
        public string ToString();
    }

    /// <summary>
    /// 新鲜的蛤
    /// </summary>
    public class FreshClams : IClams
    {
        public override String ToString()
        {
            return "长岛之声的新鲜蛤";
        }
    }

    /// <summary>
    /// 冷冻的蛤
    /// </summary>
    public class FrozenClams : IClams
    {
        public override String ToString()
        {
            return "切萨皮克湾的冷冻蛤";
        }
    }
}

接下来,我们就可以根据原料工厂来创建不同地区的原料工厂了,以纽约原料工厂为例:

/// <summary>
/// 纽约披萨原料工厂
/// </summary>
public class NYPizzaIngredientFactory : PizzaIngredientFactory
{
    public IDough createDough()
    {
        return new ThinCrustDough();
    }

    public ISauce createSauce()
    {
        return new MarinaraSauce();
    }

    public ICheese createCheese()
    {
        return new ReggianoCheese();
    }

    public IVeggies[] createVeggies()
    {
        IVeggies[] veggies = {
        new Garlic(),
        new Onion(),
        new Mushroom(),
        new RedPepper()
    };
        return veggies;
    }

    public IPepperoni createPepperoni()
    {
        return new SlicedPepperoni();
    }

    public IClams createClam()
    {
        return new FreshClams();
    }
}

同样的,芝加哥原料工厂如下:

/// <summary>
/// 芝加哥披萨原料工厂
/// </summary>
public class ChicagoPizzaIngredientFactory : PizzaIngredientFactory
{
    public IDough createDough()
    {
        return new ThickCrustDough();
    }

    public ISauce createSauce()
    {
        return new PlumTomatoSauce();
    }

    public ICheese createCheese()
    {
        return new MozzarellaCheese();
    }

    public IVeggies[] createVeggies()
    {
        IVeggies[] veggies = {
            new BlackOlives(),
            new Spinach(),
            new Eggplant()
        };
        return veggies;
    }

    public IPepperoni createPepperoni()
    {
        return new SlicedPepperoni();
    }

    public IClams createClam()
    {
        return new FrozenClams();
    }
}

现在,所有的原料已经准备完成,我们需要修改一下披萨,使其只能使用我们原料工厂提供的原料:

public abstract class Pizza
{
    public String name;

    public IDough dough;
    public ISauce sauce;
    public IVeggies[] veggies;
    public ICheese cheese;
    public IPepperoni pepperoni;
    public IClams clam;

    /// <summary>
    /// 准备
    /// </summary>
    public abstract void prepare();

    /// <summary>
    /// 烘焙
    /// </summary>
    public void bake()
    {
        Console.WriteLine("350摄氏度烘焙25分钟。");
    }

    /// <summary>
    /// 切
    /// </summary>
    public void cut()
    {
        Console.WriteLine("将披萨切成对角。");
    }

    /// <summary>
    /// 装盒
    /// </summary>
    public void box()
    {
        Console.WriteLine("将披萨放入盒中");
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public String getName()
    {
        return name;
    }

    public override String ToString()
    {
        StringBuilder result = new StringBuilder();
        result.Append("---- " + name + " ----\n");
        if (dough != null)
        {
            result.Append(dough);
            result.Append("\n");
        }
        if (sauce != null)
        {
            result.Append(sauce);
            result.Append("\n");
        }
        if (cheese != null)
        {
            result.Append(cheese);
            result.Append("\n");
        }
        if (veggies != null)
        {
            for (int i = 0; i < veggies.Length; i++)
            {
                result.Append(veggies[i]);
                if (i < veggies.Length - 1)
                {
                    result.Append(", ");
                }
            }
            result.Append("\n");
        }
        if (clam != null)
        {
            result.Append(clam);
            result.Append("\n");
        }
        if (pepperoni != null)
        {
            result.Append(pepperoni);
            result.Append("\n");
        }
        return result.ToString();
    }
}

在抽象类 Pizza 中,prepare 方法也被定义为抽象方法,因为这里我们需要根据不同的披萨生成不同的原料。

接下来,我们就可以制作披萨了:

/// <summary>
/// 芝士披萨
/// </summary>
public class CheesePizza : Pizza
{
    PizzaIngredientFactory ingredientFactory;

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

    public override void prepare()
    {
        Console.WriteLine("准备:" + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
    }
}

在重写的 prepare 方法中,当我们需要什么原料我们只要向原料工厂要就行了。具体是什么原料,由原料工厂来决定,纽约的原料工厂就给纽约风格的原料,芝加哥的原料工厂就给芝加哥风格的原料。

同样的,蛤蜊披萨也是:

/// <summary>
/// 蛤蜊披萨
/// </summary>
public class ClamPizza : Pizza
{
    PizzaIngredientFactory ingredientFactory;

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

    public override void prepare()
    {
        Console.WriteLine("准备:" + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
        clam = ingredientFactory.createClam();
    }
}

相对于 CheesePizzaClamPizza 多了蛤蜊作为原谅,至于蛤蜊的种类,就由所在地的工厂来决定。如果是靠海的纽约,那就可以拿到新鲜的蛤蜊,如果是内陆的芝加哥,那么就只能使用冷冻的蛤蜊了。

另外两种披萨:

/// <summary>
/// 素食披萨
/// </summary>
public class VeggiePizza : Pizza
{
    PizzaIngredientFactory ingredientFactory;

    public VeggiePizza(PizzaIngredientFactory ingredientFactory)
    {
        this.ingredientFactory = ingredientFactory;
    }

    public override void prepare()
    {
        Console.WriteLine("准备:" + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
        veggies = ingredientFactory.createVeggies();
    }
}
/// <summary>
/// 意大利辣香肠比萨
/// </summary>
public class PepperoniPizza : Pizza
{
    PizzaIngredientFactory ingredientFactory;

    public PepperoniPizza(PizzaIngredientFactory ingredientFactory)
    {
        this.ingredientFactory = ingredientFactory;
    }

    public override void prepare()
    {
        Console.WriteLine("准备:" + name);
        dough = ingredientFactory.createDough();
        sauce = ingredientFactory.createSauce();
        cheese = ingredientFactory.createCheese();
        veggies = ingredientFactory.createVeggies();
        pepperoni = ingredientFactory.createPepperoni();
    }
}

再回到披萨店:

public abstract class PizzaStore
{
    protected abstract Pizza createPizza(String item);

    public Pizza orderPizza(String type)
    {
        Pizza pizza = createPizza(type);

        Console.WriteLine("制作一个" + pizza.getName());

        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();

        return pizza;
    }
}

创建纽约披萨加盟店和芝加哥披萨加盟店:

/// <summary>
/// 纽约披萨店
/// </summary>
public class NYPizzaStore : PizzaStore
{
    protected override Pizza createPizza(string item)
    {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();

        if (item.Equals("cheese"))
        {
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("纽约风格芝士披萨");
        }
        else if (item.Equals("veggie"))
        {
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("纽约风格素食披萨");
        }
        else if (item.Equals("clam"))
        {
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("纽约风格蛤蜊披萨");
        }
        else if (item.Equals("pepperoni"))
        {
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("纽约风格意大利辣香肠披萨");
        }

        return pizza;
    }
}
/// <summary>
/// 芝加哥披萨店
/// </summary>
public class ChicagoPizzaStore : PizzaStore
{
    protected override Pizza createPizza(string item)
    {
        Pizza pizza = null;
        PizzaIngredientFactory ingredientFactory = new ChicagoPizzaIngredientFactory();

        if (item.Equals("cheese"))
        {
            pizza = new CheesePizza(ingredientFactory);
            pizza.setName("芝加哥风格芝士披萨");
        }
        else if (item.Equals("veggie"))
        {
            pizza = new VeggiePizza(ingredientFactory);
            pizza.setName("芝加哥风格素食披萨");
        }
        else if (item.Equals("clam"))
        {
            pizza = new ClamPizza(ingredientFactory);
            pizza.setName("芝加哥风格蛤蜊披萨");
        }
        else if (item.Equals("pepperoni"))
        {
            pizza = new PepperoniPizza(ingredientFactory);
            pizza.setName("芝加哥风格意大利辣香肠披萨");
        }

        return pizza;
    }
}

这两家披萨店就是抽象工厂的客户,如果想生产纽约风格的披萨,只需要使用纽约披萨原料工厂提供的原料。

注意的点

代码

AbstractFactoryPattern

最后

最后让我们点个披萨吃吧:

PizzaStore nyStore = new NYPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");