HeadFirst 设计模式之工厂模式

所有工厂模式都用来封装对象的创建。

工厂方法模式

举例中国版披萨:有个披萨店,卖不同种类的披萨,假定有蔬菜、水果披萨。每一个种类披萨有湖南和北京风味之分。

 public abstract class PizzaStore
    {       
        public abstract Pizza CreatePizza(PizzaType pizzaType);
        public Pizza OrderPizza(PizzaType pizzaType)
        {
            Pizza pizza = CreatePizza(pizzaType);
            pizza.Prepare();
            pizza.Bake();
            pizza.Box();
            return pizza;
        }
    }

 public class HunanPizzaStore : PizzaStore
    {
        public override Pizza CreatePizza(PizzaType pizzaType)
        {
            Pizza pizza=null;
            switch (pizzaType)
            {
                case PizzaType.Fruit:
                    pizza = new HunanStyleFruitPizza();
                    break;
                case PizzaType.Vegetalbe:
                    pizza = new HunanStyleVegetablePizza();
                    break;
            }
            return pizza;
        }
    }

 工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。通常由创建类(PizzaStore)和产品类(Pizza)组成。正式定义为:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。在上面的创建者(类)中,CreatePizza被称为工厂方法。 测试使用代码如下:

 PizzaStore pizzaStore = new HunanPizzaStore();
 pizzaStore.OrderPizza(PizzaType.Fruit);

 当程序中直接实例化一个对象时,就是在依赖它的具体类。依赖性就很高,代码应该减少这种依赖,解耦,OO设计原则中“依赖倒置原则”(Dependency Inversion Principle)描述的就是要依赖抽象,不要依赖具体类。与“针对接口编程,不针对实现编程”类似,但这里强调“抽象”。不能让高层组件依赖低层组件,而且,不管高层组件和低层组件,都应该依赖抽象。

在上面例子中,PizzaStore是“高层组件”,而比萨实现是“低层组件”。把低层组件抽象出来,工厂方法刚好能派上用场。在上面例子中,高层组件PizzaStore和低层组件都依赖了Pizza抽象。通常高层组件依赖低层组件,但工厂方法却让低层组件依赖了高层的抽象Pizza对象,这就是“倒置”的现象。在低层组件的实现中,工厂方法将这些具体的类取出PizzaStore,各种不同种类的Pizza就只能依赖一个抽象,同时比萨店也依赖这个抽象,倒置就实现了。

抽象工厂模式

在上面的例子中,假定各种不同风味的Pizza就是制作Pizza时原料的不同,例如湖南风味酱汁少、辣椒多,北京风味酱汁多、不放辣(仅举例说明,不深究合理性)。不用单独创建各种类的 HunanStylePizza 或BeijingStylePizza 。此时改用创建不同的原料来制作各种风味的Pizza。

首先创建一个原料接口,两个原料工厂,分别生产湖南风味和北京风味的原料:

    public interface IPizzaIngredientFactory
    {
        Vegetable[] CreateVegetable();
        Fruit[] CreateFruit();
        Sauce CreateSauce();
        Pepper CreatePepper();
    }

    public class HunanIngredientFactory : IPizzaIngredientFactory
    {
        public Fruit[] CreateFruit()
        {
            return new Fruit[] { new Orange(),new Apple() };
        }

        public Pepper CreatePepper()
        {
            return new Pepper() { Weight=2.5f, };
        }

        public Sauce CreateSauce()
        {
            return new HunanPizzaSauce();
        }

        public Vegetable[] CreateVegetable()
        {
            return new Vegetable[] { new Onion(),new Tomato(),new Potato()};
        }
    }

    public class BeijingIngredientFactory : IPizzaIngredientFactory
    {
        public Fruit[] CreateFruit()
        {
            return new Fruit[] { new Orange(), new Apple(),new Banana() };
        }

        public Pepper CreatePepper()
        {
            return new Pepper() { Weight = 0 };
        }

        public Sauce CreateSauce()
        {
            return new BeijingPizzaSauce();
        }

        public Vegetable[] CreateVegetable()
        {
            return new Vegetable[] { new Onion(), new Tomato() };
        }
    }

接着将Pizza抽象类中的Prepare定义为抽象方法,目的为了让工厂来完成制作披萨的原料准备工作。

public abstract class Pizza
    {
        public string Name { get; set; }

        public abstract void Prepare();
    
        public void Bake()
        {
            Console.WriteLine("{0} 烘焙25 至30 分钟",Name);
        }
        public void Box()
        {
            Console.WriteLine("{0}, 装盒, 完工",Name);
        }
    }

把工厂方法模式中的BeijingStyleVegetablePizza和HunanStyleVegetablePizza 合并成一类VegetablePizza,让工厂来处理不同的风味。同水果种类的披萨也合并改造。

 public class VegetablePizza : Pizza
    {
        IPizzaIngredientFactory ingredientFactory;
        public VegetablePizza(IPizzaIngredientFactory factory)
        {
            this.ingredientFactory = factory;
        }
        public override void Prepare()
        {
            Console.WriteLine("准备中: {0}",Name);
            Vegetable[] vegetables= ingredientFactory.CreateVegetable();
            foreach (var veg in vegetables)
            {
                Console.WriteLine("        >>添加:{0}", veg.Name);
            }
            Pepper pepper = ingredientFactory.CreatePepper();
            if (pepper.Weight > 0)
            {
                Console.WriteLine("        >>添加辣椒量:{0}g", pepper.Weight);
            }
            else
            {
                Console.WriteLine("        >>不放辣");
            }
            Sauce sauce = ingredientFactory.CreateSauce();
            Console.WriteLine("        >>添加酱料:{0}",sauce.Name);

            Console.WriteLine("{0} 披萨调料好了",Name);
        }

    }

测试生产披萨过程:

PizzaStore pizzaStore = new HunanPizzaStore();
            pizzaStore.OrderPizza(PizzaType.Fruit);
            Console.WriteLine();
            pizzaStore.OrderPizza(PizzaType.Vegetalbe);
            Console.WriteLine();
            pizzaStore = new BeijingPizzaStroe();
            pizzaStore.OrderPizza(PizzaType.Vegetalbe);

类的全局关系图

上面的设计被定义为“抽象工厂模式”:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

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

工厂方法与抽象工厂的异同:

都是用来创建对象,将客户从具类型中解耦。工厂方法通过继承有子类来创建对象,客户只需要知道他们所使用的抽象类型就可以了。抽象工厂通过对象的组合来完成,它提供一个用来创建一个产品家族的抽象类型,把一群相关的产品集合起来。当需要创建产品家族并把相关产品集合起来时,可以使用抽象工厂模式,如果目前还不知道将来需要实例化哪些具体类时,可以使用工厂方法模式。

发布了92 篇原创文章 · 获赞 55 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/elie_yang/article/details/103439885