设计模式——工厂模式
《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;
}