设计模式——工厂模式

《HeadFirst设计模式》读书笔记

 

封装创建对象的代码

工厂(factory)处理创建对象的细节。

 

简单工厂

简单工厂其实不是一个“真正的”设计模式,反而比较像是一种编程习惯。

设计模式——工厂模式

SimplePizzaFactory这个创建方法通常声明为静态。

class PizzaStore
{
public:
    PizzaStore();
    
    Pizza orderPizza(std::string type)
    {
        Pizza pizza;
        pizza = factory.createpizza(type);
        return pizza;
    }
    
private:
    SimplePizzaFactory factory;    //静态声明
};

 

工厂方法

所有工厂模式都用来封装对象的创建。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

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

工厂方法模式能够封装具体类型的实例化。如下面的类图,抽象的Creator提供了一个创建对象的方法的接口,也称为“工厂方法”。在抽象的Creator中,任何其他实现的方法,都可能用到这个方法所制造出来的产品,但只有子类真正实现这个工厂方法并创建产品。

工厂方法让子类决定要实例化的类是哪一个。所谓的“决定”,并不是指模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需要知道实际创建的产品是哪一个。选择使用哪个子类,自然就决定了实际创建的产品是什么。

设计模式——工厂模式

 

设计原则(依赖倒置原则)

要依赖抽象,不要依赖具体类。

  • 变量不可以持有具体类的引用。

如果使用new就会持有具体类的引用,可以用工厂来避开这样的做法。

  • 不要让类派生自具体类。

如果派生自具体类就会依赖具体类。

  • 不要覆盖基类中已实现的方法。

基类中已实现的方法应该由子类共享。

 

抽象工厂模式(使用了对象的组合)

抽象工厂模式定义了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。

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

设计模式——工厂模式

 

总结:

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

所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。

依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖抽象。

 

例子:PizzStore

创建者类(Creator)

设计模式——工厂模式

PizzaStore是抽象创建者类,它定义了一个抽象的工厂方法,让子类实现此方法制造产品。

创建者通常会包含依赖于抽象产品的代码,而这些抽象产品由子类制造,创建者不需要真的知道在制造哪种具体产品。

creatPizza()是抽象的工厂方法,子类可以继承并覆写。

 

产品类

设计模式——工厂模式

 

实现

//Pizza.h
#include <string>
#include <vector>
#include <iostream>

class Pizza
{
public:
    Pizza();

    virtual void prepare();
    virtual void bake();
    virtual void cut();
    virtual void box();
    virtual std::string& getName();

protected:
    std::string name;
    std::string dough;
    std::string sauce;
    std::vector<std::string> toppings;
};

//Pizza.cpp
#include "pizza.h"

Pizza::Pizza()
{

}

void Pizza::prepare()
{
    std::cout << "Preparing " << name << std::endl;
    std::cout << "Tossing dough..." << std::endl;
    std::cout << "Adding sauce..." << std::endl;
    std::cout << "Adding toppings: " << std::endl;
    for(std::vector<std::string>::size_type i=0; i<toppings.size(); ++i)
    {
        std::cout << "  " << toppings[i] << std::endl;
    }
}

void Pizza::bake()
{
    std::cout << "Bake for 25 minutes at 350" << std::endl;
}

void Pizza::cut()
{
    std::cout << "Cutting the pizza into diagonal slices" << std::endl;
}

void Pizza::box()
{
    std::cout << "Place pizza in official PizzaStore box" << std::endl;
}

std::string& Pizza::getName()
{
    return name;
}

//PizzaStore.h
#include <string>
#include "pizza.h"

class PizzaStore
{
public:
    PizzaStore();

    virtual Pizza *orderPizza(std::string type);
    //工厂方法
    virtual Pizza *createPizza(std::string type) = 0;
};

//PizzaStore.cpp
#include "pizzastore.h"

PizzaStore::PizzaStore()
{

}

Pizza *PizzaStore::orderPizza(std::string type)
{
    Pizza* pizza = createPizza(type);

    pizza->prepare();
    pizza->bake();
    pizza->cut();
    pizza->box();

    return pizza;
}

//ChicagoPizzaStore.h
#include "pizzastore.h"
#include "chicagostylecheesepizza.h"

class ChicagoPizzaStore : public PizzaStore
{
public:
    ChicagoPizzaStore();

    Pizza* createPizza(std::string type);
};

//ChicagoPizzaStore.cpp
#include "chicagopizzastore.h"

ChicagoPizzaStore::ChicagoPizzaStore()
{

}

Pizza *ChicagoPizzaStore::createPizza(std::string type)
{
    if (type == "cheese")
            return new ChicagoStyleCheesePizza;
}


//ChicagoStyleCheesePizza.h
#include "pizza.h"

class ChicagoStyleCheesePizza : public Pizza
{
public:
    ChicagoStyleCheesePizza();

    void cut();  //覆盖了cut方法
};

//ChicagoStyleCheesePizza.cpp
#include "chicagostylecheesepizza.h"

ChicagoStyleCheesePizza::ChicagoStyleCheesePizza()
{
    name = "Chicago Style Deep Fish Cheese Pizza";
    dough = "Extra Thick Crust Dough";
    sauce = "Plum Tomato Sauce";

    toppings.push_back("Shredded Mozzarella Cheese");
}

void ChicagoStyleCheesePizza::cut()
{
    std::cout << "Cutting the pizza into square slices" << std::endl;
}