设计模式:4. 工厂模式

笔者目前正在阅读《Head First设计模式》,首先对该书发表我的个人观点,非常有趣生动的一本书,在阅读这本书之前,我一直对设计模式抱有畏惧的心理,阅读该书之后,才发现设计模式可以这么通俗易懂,推荐各位去阅读原书。为加深知识印象,对书中内容进行梳理总结,书中的案例均由Java实现,而笔者本人目前主要使用C++,因此该文章通过C++来描述案例。由于本人水平有限,表达会有欠佳处,若要深入理解设计模式,还是推荐读者能够阅读原书。

你有一家披萨店,作为披萨店的主人,你可以这么编写点餐代码。

Pizza* orderPizza()
{
    Pizza* pizza = new Pizza();
    pizza->prepare(); // 准备(加上佐料等)
    pizza->bake();  // 烘烤
    pizza->cut();  // 切片
    pizza->box();  // 装盒
    return pizza;
}

当然了,作为一家披萨店,你不可能只售卖一种披萨。你要为顾客提供不同的口味。于是,你选择这么实现。

Pizza* orderPizza(string type)
{
    Pizza* pizza = nullptr;
    if (type == "cheese")
    {
      pizza = new CheesePizza();
    }
    else if (type == "greek")
    {
      pizza = new GreekPizza();
    }
    else if (type == "pepperoni")
    {
      pizza = new PepperoniPizza();
    }
    pizza->prepare(); // 准备(加上佐料等)
    pizza->bake();  // 烘烤
    pizza->cut();  // 切片
    pizza->box();  // 装盒
    return pizza;
}

这就会造成一个问题,如果店内推出了新口味的披萨,或者某一个口味销量不好,需要去掉。就需要修改这里的代码。
还记得我们设计模式的第一篇文章中讲的吗?在程序设计时,我们需要尽可能遵循一个原则:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
制作披萨会根据口味有所不同,而后面的准备、烘烤、装盒等操作都是一样的。所以我们把创建披萨的代码移动到另一个对象中,我们称这个对象为 “工厂”

class SimplePizzaFactory
{
public:
  Pizza* createPizza(string type)
  {
    Pizza* pizza = nullptr;
    if (type == "cheese")
    {
      pizza = new CheesePizza();
    }
    else if (type == "greek")
    {
      pizza = new GreekPizza();
    }
    else if (type == "pepperoni")
    {
      pizza = new PepperoniPizza();
    }
    return pizza;
  }
};

我们的披萨店现在要这么实现

class PizzaStore
{
public:
  PizzaStore(SimplePizzaFactory* factory)
  {
    m_factory = factory;
  }
  Pizza* orderPizza(string type)
  {
    Pizza* pizza = m_factory->createPizza(type);
    pizza->prepare();
    pizza->bake();
    pizza->cut();
    pizza->box();
    return pizza;
  }
private:
  SimpleFactory* m_factory;
};

上方这种方式叫做简单工厂,简单工厂不是一个设计模式,反而比较像是一种编程习惯,虽然它不是设计模式,但也会经常被使用。
后来,你的披萨店经营的非常不错,你打算要开一个分店。可是由于地理风俗差异,尽管是同一种口味的披萨,由不同地区工厂制作出来的却是不一样的。我们不能再依靠单一的工厂来为我们提供披萨了,而披萨店和工厂又不能耦合到一起,不然下次去一个新的地区开披萨店时,又要更改披萨店的代码。
既然各个工厂都是要提供披萨,只是具体的实现可能会有所不同,那就将工厂抽象成一个接口,披萨店类与这个抽象工厂组合,不需要知道具体的工厂是谁,只要像工厂要披萨就可以了。

class Factory
{
public:
  virtual Pizza* createPizza(string type) = 0;
};
class NYPizzaFactory: public Factory
{
  // 纽约披萨工厂
  // 具体实现省略...
};
class ChicagoPizzaFactory: public Factory
{
  // 芝加哥披萨工厂
  // 具体实现省略...
};

而披萨店只需要在创建的时候指定当地的一个工厂对象。

class PizzaStore
{
public:
  PizzaStore(Factory* factory)
  {
    m_factory = factory;
  }
  Pizza* orderPizza(string type)
  {
    Pizza* pizza = m_factory->createPizza(type);
    pizza->prepare();
    pizza->bake();
    pizza->cut();
    pizza->box();
    return pizza;
  }
private:
  Factory* m_factory;
};

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

受限于篇幅,上方对于抽象工厂的举例并不完全贴切。在实际工程中,抽象工厂模式最大的优势是能够管理整个“产品家族”(例如:一个纽约原料工厂能够同时生产纽约面团、纽约番茄酱和纽约奶酪,而不需要分别建立独立的面团厂、酱料厂)。这种设计能够严格保证配套产品之间的一致性,避免“混搭”问题。若需深入理解抽象工厂的精髓,强烈建议阅读原书。

你的各个店铺对做披萨有了更多见解,每个店有着自己的特色,不想通过外部工厂的方式来获取披萨,而是想要自己做。为了能够继续方便管理我们的店铺,我们设计一个店铺的接口,让每个店铺都实现createPizza(string type),让每个店铺自己决定披萨该怎么做。

class PizzaStore
{
public:
  virtual Pizza* createPizza(string type) = 0;
};
class NYPizzaStore: public PizzaStore
{
public:
  Pizza* orderPizza(string type)
  {
    Pizza* pizza = createPizza(type);
    pizza->prepare();
    pizza->bake();
    pizza->cut();
    pizza->box();
    return pizza;
  }
  Pizza* createPizza(string type) override
  {
    Pizza* pizza = nullptr;
    if (type == "cheese")
    {
      pizza = new CheesePizza();
    }
    else if (type == "greek")
    {
      pizza = new GreekPizza();
    }
    else if (type == "pepperoni")
    {
      pizza = new PepperoniPizza();
    }
    return pizza;
  }
};

这种允许子类做决定的方式就是工厂方法模式,给出定义:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

posted @ 2026-06-18 22:25  初五二十一  阅读(5)  评论(0)    收藏  举报