(四)详解工厂模式

编程入门 行业动态 更新时间:2024-10-27 20:28:31

(四)<a href=https://www.elefans.com/category/jswz/34/1770044.html style=详解工厂模式"/>

(四)详解工厂模式

一.为什么需要工厂模式

当我们在拥有了大量类的时候,一旦我们需要具体对象,就需要手动控制new出不同的对象。我们可以针对这一步骤抽象化,创建一个根据要求返回我们需要的具体对象的工厂。这样就能通过统一的方式获得不同的对象

二.不用工厂模式

假设我们拥有一个披萨店,我们需要根据客户不同的订单提供不同的披萨。首先不使用工厂模式,我们就能得到这样的代码

#include <iostream>
#include <string>class Pizza {public:virtual void prepare() = 0;virtual void bake() = 0;virtual void cut() = 0;virtual void box() = 0;
};//不同种类的披萨
class CheesePizza: public Pizza {void prepare(){std::cout << "准备芝士" << std::endl;};void bake(){std::cout << "烤芝士" << std::endl;};void cut(){std::cout << "切芝士" << std::endl;};void box(){std::cout << "装盒" << std::endl;};
};class GreekPizza: public Pizza {void prepare(){std::cout << "。。。" << std::endl;};void bake(){std::cout << "。。。" << std::endl;};void cut(){std::cout << "。。。" << std::endl;};void box(){std::cout << "。。。" << std::endl;};
};class PepperoniPizza: public Pizza {void prepare(){std::cout << "。。。" << std::endl;};void bake(){std::cout << "。。。" << std::endl;};void cut(){std::cout << "。。。" << std::endl;};void box(){std::cout << "。。。" << std::endl;};
};std::unique_ptr<Pizza> orderPizza(std::string type)
{std::unique_ptr<Pizza> pizza = nullptr;if (type == "cheese"){pizza = std::make_unique<CheesePizza>();}else if (type == "greek"){pizza = std::make_unique<GreekPizza>();}else if (type == "pepperoni"){pizza = std::make_unique<PepperoniPizza>();}pizza->prepare();pizza->bake();pizza->cut();pizza->box();return pizza;
};

三.使用简单工厂模式

能看到假若我们想要对具体类型的披萨进行调整是很困难的。我们将工厂引入,单独用一个函数创建对象。就可以得到这样的代码。通过统一的createPizza函数获得不同的披萨对象

#include "Pizza.hpp"
#include <string>class SimplePizzaFactory
{public:std::unique_ptr<Pizza> createPizza(const std::string& type){std::unique_ptr<Pizza> pizza = nullptr;if (type == "cheese"){pizza = std::make_unique<CheesePizza>();}else if (type == "pepperoni"){pizza = std::make_unique<PepperoniPizza>();}else if (type == "clam"){pizza = std::make_unique<ClamPizza>();}else if (type == "veggie"){pizza = std::make_unique<VeggiePizza>();}return pizza;}};

这样结合工厂模式就可以得到如下的披萨店的代码。

#include "SimplePizzaFactory.hpp"
#include "Pizza.hpp"
#include <string>class PizzaStore
{SimplePizzaFactory factory;public:PizzaStore(SimplePizzaFactory factory){this->factory = factory;}std::unique_ptr<Pizza> orderPizza(std::string type){std::unique_ptr<Pizza> pizza = nullptr;pizza = factory.createPizza(type);if (pizza != nullptr){pizza->prepare();pizza->bake();pizza->cut();pizza->box();}else{std::cout << "不是可提供的披萨" << std::endl;}return pizza;}};

这样就可以通过字符串自动判断并生成对应的对象。也有利于我们增加新的披萨种类。但是对于更改已有披萨的设计仍然不是很方便。

四.工厂模式

我们想让每种不同的披萨对象拥有更多的弹性。我们可以将这一弹性功能下放到PizzaStore实现。也就是让子类运行时根据输入决定做什么披萨,怎么做披萨。我们需要提供多种不同类型的PizzaStore,并根据不同的方法创建不同的披萨类型。

首先提供披萨店的接口和披萨的接口

#include "Pizza.hpp"
#include <string>class PizzaStore
{public:std::unique_ptr<Pizza> orderPizza(std::string type);virtual std::unique_ptr<Pizza> makePizza(std::string type) = 0;};
class Pizza
{public:std::string name;std::string dough;std::string sauce;std::vector<std::string> toppings;const std::string& getName() const{return this->name;}virtual void prepare() const{std::cout << "准备 " + getName() << std::endl;std::cout << "准备面团..." << std::endl;std::cout << "添加酱汁..." << std::endl;std::cout << "添加配料: " << std::endl;for (auto& topping : this->toppings){std::cout << "  " + topping + "\n";}}virtual void bake() const{std::cout << "350 度 烤 25 分钟 "<< std::endl;}virtual void cut() const{std::cout << "切分披萨"<< std::endl;}virtual void box()  const{std::cout << "披萨装盒" << std::endl;}virtual ~Pizza() = default;};

有了披萨店的接口和披萨的接口,我们就能创建出不同种类的披萨商店贩卖不同种类的披萨。

首先创建出不同类型的披萨。并将其装载在披萨店内。

#include "Pizza.hpp"class NYStylePepperoniPizza: public Pizza
{
public:NYStylePepperoniPizza(){name = "NY style pepperoni pizza";dough = "。。。面";sauce = "。。。酱";toppings.push_back("。。。e");toppings.push_back("。。。");toppings.push_back("。。。");toppings.push_back("。。。");toppings.push_back("。。。");toppings.push_back("。。。");}};
#include "Pizza.hpp"
#include "PizzaStore.hpp"class NYPizzaStore: public PizzaStore
{public:std::unique_ptr<Pizza> makePizza(std::string type){std::unique_ptr<Pizza> pizza = nullptr;if (type == "cheese"){pizza = std::make_unique<NYStyleCheesePizza>();}else if (type == "pepperoni"){pizza = std::make_unique<NYStylePepperoniPizza>();}return pizza;}
};

这样披萨店的工厂会拥有更好的弹性,能更利于增加新的披萨,由于每个商店都拥有一个特有的披萨类,也利于披萨类本身的更改。

披萨本身和披萨店本身是平行的关系,披萨是产品类,披萨商店是创建者

工厂模式定义:定义了一个创建对象的接口,但让子类决定实例化哪个类。

本质就是工厂接口创建出工厂实例,调用产品接口实现出产品实例。

五.工厂模式应有的对象依赖关系

依赖抽象不依赖具体类,应该让依赖倒置。高层组件的类例如(pizzastore)依赖具体实现类例如(具体pizza类)。

六.抽象工厂模式

对于上面的工厂模式的披萨而言,原料都是固定好的,不利于修改,而抽象工厂模式利于提供大量家族相关对象,就比如上面的披萨原料。我们可以通过抽象工厂来改造披萨的原料。首先获得我们新的pizza虚接口,跟工厂模式没有什么变化。

class Pizza
{public:std::string name;Dough dough;Sauce sauce;std::vector<std::string> toppings;const std::string& getName() const{return this->name;}virtual void prepare() const            //抽象工厂的重点是这个函数{std::cout << "准备 " + getName() << std::endl;std::cout << "准备面团..." << std::endl;std::cout << "添加酱汁..." << std::endl;std::cout << "添加配料: " << std::endl;for (auto& topping : this->toppings){std::cout << "  " + topping + "\n";}}virtual void bake() const{std::cout << "350 度 烤 25 分钟 "<< std::endl;}virtual void cut() const{std::cout << "切分披萨"<< std::endl;}virtual void box()  const{std::cout << "披萨装盒" << std::endl;}virtual ~Pizza() = default;};

主要的变化是我们将用到工厂内的组件也就是工厂家族,具体的实现过程抽象工厂实现。首先看一下批量获取相关原料的工厂接口。

class PizzaIngredientFactory
{
public:virtual Dough CreatDough() = 0;virtual Cheese CreatCheese() = 0;...
};

 我们可以根据不同的披萨商店,形成不同的具体原材料工厂实例

class NYStylePepperoniPizza: public PizzaIngredientFactory
{Dough createDough(){return new ThinCrustDough();}Cheese createCheese(){return new MarinaraCheese();}...
}

我们用一个例子来实现。我们让披萨制作阶段运行时调整,通过原材料工厂获取不同的原材料

#include "Pizza.hpp"class NYStylePepperoniPizza: public Pizza
{PizzaIngredientFactory _ingFact;
public:NYStylePepperoniPizza(PizzaIngredientFactory ingFact)        //通过工厂元素获取原料{this._ingFact = ingFact;}void prepare()    //通过原料工厂批量获取对象{dough =  _ingFact.createDough();sauce = _ingFact.createsauce();cheese = _ingFact.createcheese();}};

最后我们需要更改披萨商店调用原材料工厂

#include "Pizza.hpp"
#include "PizzaStore.hpp"class NYPizzaStore: public PizzaStore
{public:std::unique_ptr<Pizza> makePizza(std::string type){std::unique_ptr<Pizza> pizza = nullptr;PizzaIngredientFactory idFact = new NYPizzaIngredientFactory ();    //拿到原材料工厂if (type == "cheese"){pizza = NYStyleCheesePizza(idFact);    //通过不同的工厂加工生成不同的披萨}else if (type == "pepperoni"){pizza = NYStylePepperoniPizza(idFact);}return pizza;}
};

这样就实现了不同工厂通过抽象工厂获得批量不同的元素,生成对应的披萨。

总结:通过引进一个抽象工厂提供了为披萨家族创建家族。此工厂提供接口,我们通过这个接口获取对象。我们可以通过更换工厂获得不同的行为。

抽象工厂提供一个接口来创建相关或依赖对象的家族,而不需要提供具体类

七.对比工厂模式和抽象工厂

抽象工厂通过对象组合创建对象,通过提供一个抽象接口,规定如何生产相关产品,工厂方法通过子类创建对象。

抽象工厂用于提供大批量相关产品家族。

工厂用于从具体的实例化解耦。

抽象工厂往往会在具体实例化使用工厂模式

抽象工厂缺点:添加新产品意味着改变接口。

总结:

抽象工厂提供一个接口,用于创建相关依赖对象的家族,而不必指定它们的具体类。依靠对象组合实现,子类创建在工厂接口暴露的方法中实现。抽象工厂的意图是创建相关对象家族,不必依赖具体类

工厂方法,定义一个创建对象的接口,但让子类决定哪个类实例化,工厂方法让一个类延迟实例化到子类。工厂方法依赖继承,对象创建被委托给子类,子类实现工厂方法来创建对象。工厂方法的意图是允许类延迟实例化

更多推荐

(四)详解工厂模式

本文发布于:2023-12-04 00:53:03,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1659275.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:详解   工厂   模式

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!