设计原则6:要依赖抽象,不要依赖具体类。(又称依赖倒置原则Dependency Inversion Principle)
不能让高层组件依赖低层组件,而且,不管高层组件或低层组件,两者都应该依赖于抽象。
如何避免在OO设计中违反依赖倒置原则:
- 变量不可以持有具体类的引用。
如果使用new,就会持有具体类的引用。可以改用工厂来避开这样的作法
- 不要让类派生自具体类。
如果派生自具体类,就会依赖具体类。请派生自一个抽象。
- 不要覆盖基类中已实现的方法。
如果覆盖基类已实现的方法,那么基类就不是一个真正适合被继承的抽象。基类中已实现的方法,应该由所有的子类共享。
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
工厂方法模式将产品的“实现”从“使用”中解耦。如果增加产品或者改变产品的实现,Creator并不会收到影响。
#include <iostream>
#include <vector>
using namespace std;
定义产品类
class Pizza {
public:
std::string name;
std::string dough;
std::string sauce;
std::vector<std::string> toppings;
void prepare() {
printf("Preparing %s\n",name.c_str());
printf("Tossing dough...\n");
printf("Adding sauce...\n");
printf("Adding toppings:\n");
for (int i = 0; i < toppings.size(); i++) {
printf(" %s\n", toppings[i].c_str());
}
}
void bake() {
printf("Bake for 25 minutes at 350\n");
}
void cut() {
printf("Cutting the pizza into diagonal slices\n");
}
void box() {
printf("Place pizza in offical PizzaStore box\n");
}
std::string getName() {
return name;
}
};
class CheesePizza :public Pizza {
public:
CheesePizza() {
name = "Cheese Pizza";
dough = "Regular Crust";
sauce = "Marinara Pizza Sauce";
toppings.push_back("Fresh Mozzarella");
toppings.push_back("Parmesan");
}
};
class NYStyleCheesePizza :public Pizza {
public:
NYStyleCheesePizza() {
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.push_back("Grated Reggiano Cheese");
}
};
class ChicagoStyleCheesePizza :public Pizza {
public:
ChicagoStyleCheesePizza() {
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.push_back("Shredded Mozzarella Cheese");
}
void cut() {
printf("Cutting the pizza into square slices\n");
}
};
class PepperoniPizza :public Pizza {
public:
PepperoniPizza() {
name = "Pepperoni Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.push_back("Sliced Pepperoni");
toppings.push_back("Sliced Onion");
toppings.push_back("Grated parmesan cheese");
}
};
class NYStylePepperoniPizza :public Pizza {
public:
NYStylePepperoniPizza() {
name = "NY Style Sauce and Pepperoni Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.push_back("Sliced Pepperoni");
toppings.push_back("Sliced Onion");
toppings.push_back("Grated parmesan cheese");
}
};
class ChicagoStylePepperoniPizza :public Pizza {
public:
ChicagoStylePepperoniPizza() {
name = "Chicago Style Deep Dish Pepperoni Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.push_back("Sliced Pepperoni");
toppings.push_back("Sliced Onion");
toppings.push_back("Grated parmesan cheese");
}
};
class ClamPizza :public Pizza {
public:
ClamPizza() {
name = "Clam Pizza";
dough = "Thin crust";
sauce = "White garlic sauce";
toppings.push_back("Clams");
toppings.push_back("Grated parmesan cheese");
}
};
class NYStyleClamPizza :public Pizza {
public:
NYStyleClamPizza() {
name = "NY Style Clam Pizza";
dough = "Thin crust";
sauce = "White garlic sauce";
toppings.push_back("Clams");
toppings.push_back("Grated parmesan cheese");
}
};
class ChicagoStyleClamPizza :public Pizza {
public:
ChicagoStyleClamPizza() {
name = "Chicago Style Clam Pizza";
dough = "Thin crust";
sauce = "White garlic sauce";
toppings.push_back("Clams");
toppings.push_back("Grated parmesan cheese");
}
};
class VeggiePizza :public Pizza {
public:
VeggiePizza() {
name = "Veggie Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.push_back("Shredded mozzarella");
toppings.push_back("Grated parmesan");
toppings.push_back("Diced onion");
toppings.push_back("Sliced mushrooms");
toppings.push_back("Sliced red pepper");
toppings.push_back("Sliced black olives");
}
};
class NYStyleVeggiePizza :public Pizza {
public:
NYStyleVeggiePizza() {
name = "NY Style Veggie Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.push_back("Shredded mozzarella");
toppings.push_back("Grated parmesan");
toppings.push_back("Diced onion");
toppings.push_back("Sliced mushrooms");
toppings.push_back("Sliced red pepper");
toppings.push_back("Sliced black olives");
}
};
class ChicagoStyleVeggiePizza :public Pizza {
public:
ChicagoStyleVeggiePizza() {
name = "Chicago Style Veggie Pizza";
dough = "Crust";
sauce = "Marinara sauce";
toppings.push_back("Shredded mozzarella");
toppings.push_back("Grated parmesan");
toppings.push_back("Diced onion");
toppings.push_back("Sliced mushrooms");
toppings.push_back("Sliced red pepper");
toppings.push_back("Sliced black olives");
}
};
定义创建者类
抽象创建者:抽象创建者通常会包含依赖于抽象产品的代码,而这些抽象产品由子类制造,创建者不需要真的知道在制造哪种具体产品。
class PizzaStore {
public:
Pizza* orderPizza(std::string type) {
//Pizza* pizza = factory->createPizza(type);
Pizza* pizza = createPizza(type);
pizza->prepare();
pizza->bake();
pizza->cut();
pizza->box();
return pizza;
}
virtual Pizza* createPizza(std::string type) = 0;
};
具体创建者
class NYPizzaStore :public PizzaStore {
public:
Pizza* createPizza(std::string type) {
if (type._Equal("cheese")) {
return new NYStyleCheesePizza();
}
else if (type._Equal("pepperoni")) {
return new NYStylePepperoniPizza();
}
else if (type._Equal("clam")) {
return new NYStyleClamPizza();
}
else if (type._Equal("veggie")) {
return new NYStyleVeggiePizza();
}
else {
return NULL;
}
}
};
class ChicagoPizzaStore :public PizzaStore {
public:
Pizza* createPizza(std::string type) {
if (type._Equal("cheese")) {
return new ChicagoStyleCheesePizza();
}
else if (type._Equal("pepperoni")) {
return new ChicagoStylePepperoniPizza();
}
else if (type._Equal("clam")) {
return new ChicagoStyleClamPizza();
}
else if (type._Equal("veggie")) {
return new ChicagoStyleVeggiePizza();
}
else {
return NULL;
}
}
};
测试程序
void main() {
PizzaStore *nyStore = new NYPizzaStore();
PizzaStore *chicagoStore = new ChicagoPizzaStore();
Pizza* pizza = nyStore->orderPizza("cheese");
printf("Ethan ordered a %s\n\n", pizza->getName().c_str());
pizza = chicagoStore->orderPizza("cheese");
printf("Joel ordered a %s\n\n", pizza->getName().c_str());
}
参考:
1. EricFreeman, FreemanElisabeth, 弗里曼, et al. Head First设计模式[M]. 中国电力出版社, 2007.