本文源自深入浅出设计模式. 只不过我是使用C#/.NET Core实现的例子.

 

当你看见new这个关键字的时候, 就应该想到它是具体的实现.

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

这就是一个具体的类, 为了更灵活, 我们应该使用的是接口(interface).

有时候, 你可能会写出这样的代码:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

这里有多个具体的类被实例化了, 是根据不同情况在运行时被实例化的. 

当你看到这样的代码, 你就会知道当有需求需要对其进行修改或者扩展的时候, 你就得把这个文件打开, 然后看看在这里应该添加或者删除点什么. 这类的代码经常会分散在程序的多个地方, 这维护和更新起来就很麻烦而且容易出错.

针对interface进行编程的时候, 你知道可以把自己独立于系统未来可能要发生的变化. 为什么呢? 因为如果你针对interface编程, 那么对于任何实现了该接口的具体类对你来说都可以用, 多态吗.

项目原始需求

有一个前沿的披萨店, 做披萨, 下面是订购披萨的类:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

new一个披萨, 然后按照工序进行加工 最后返回披萨.

但是, 一个披萨店不可能只有一种披萨, 可能会有很多中披萨, 所以你可能会这样修改代码:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

根据传入的类型, 创建不同的披萨, 然后加工返回.

然后问题来了, 随着时间的推移, 一个披萨店会淘汰不畅销的披萨并添加新品种披萨.

使用上面的代码就会出现这个问题, 针对需求变化, 我不得不把OrderPizza的部分代码改来改去:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

从这里, 我们也可以看到, 上半部分是会变化的部分, 下半部分是不变的部分, 所以它们应该分开(把变化的部分和不变的部分分开, 然后进行封装).

结构应该是这样的:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

右上角是变化的部分, 把这部分封装到一个对象里, 它就是用来创建披萨的对象, 我们把这个对象叫做: 工厂.

工厂负责创建对象的细节工作. 我们创建的这个工厂叫做SimplePizzaFactory, 而orderPizza()这个方法就是该工厂的一个客户(client).

任何时候客户需要披萨的时候, 披萨工厂就会给客户创建一个披萨.

接下来, 我们就建立这个简易的披萨工厂:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

就是通过传入的类型参数, 建立并返回不同类型的披萨.

这样我们就把披萨创建的工作封装到了一个类里面, 发生变化的时候, 只需要修改这一个类即可.

注意: 有时候上面这种简单工厂可以使用静态方法, 但是这样也有缺点, 就是无法通过继承来扩展这个工厂了.

回来修改PizzaStore这个类:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

工厂是从构造函数传入的, 并在PizzaStore里面保留一个引用.

在OrderPizza()方法里面, 我们使用工厂的创建方法代替了new关键字, 所以在这里没有具体的实例化.

简单工厂的定义

简单/简易工厂并不是一个设计模式, 更多是一个编程习惯. 但是使用的非常广泛.

简单工厂类图:

使用C# (.NET Core) 实现简单工厂(Simple Factory) 和工厂方法设计模式 (Factory Method Pattern)

这个很简单, 就不解释了. 

简单工厂就到这, 下面要讲两个重量级的工厂模式.

用C#/.NET Core实现简单工厂

Pizza父类:

using System;
using System.Collections.Generic;

namespace SimpleFactory.Pizzas
{
    public abstract class Pizza
    {
        public string Name { get; protected set; }
        public string Dough { get; protected set; }
        public string Sauce { get; protected set; }
        protected List<string> Toppings = new List<string>();

        public void Prepare()
        {
            Console.WriteLine($"Preparing: {Name}");
            Console.WriteLine($"Tossing: {Dough}");
            Console.WriteLine($"Adding sauce: {Sauce}");
            Console.WriteLine("Adding toppings: ");
            Toppings.ForEach(x => Console.WriteLine($"  {x}"));
        }

        public void Bake()
        {
            Console.WriteLine("Bake for 25 minutes");
        }

        public void Cut()
        {
            Console.WriteLine("Cutting the pizza into diagnol slices");
        }

        public void Box()
        {
            Console.WriteLine("Placing pizza in official PizzaStore box......");
        }
    }
}
View Code

相关文章: