什么是工厂模式
工厂方法模式定义了一个创建对象的接口,但由子类来决定要实例化那个类。工厂方法让类把实例化推迟到了子类。
为什么要有工厂模式
书中以pizza店制作pizza为例子,假设不用工厂模式,在制作pizza阶段我们需要这样去实例化类:
Pizza orderPizza(String type) {
Pizza pizza;
// 基于pizza的类型,实例化具体的类,这里的每个pizza都需要实现Pizza接口
if (type.equals("cheess")) {
pizza = new CheesePizza();
} else if (type.equals("greek")) {
pizza = new GreekPizza();
}
// pizza的前期准备
pizza.prepare();
pizza.bake();
return pizza;
}
上述代码不符合开闭原则,一旦pizza店改变pizza的供应,则需要修改上述代码
简单工厂模式
简单工厂模式并不是一种设计模式,而是一种编程习惯,定义一个工厂类,这个类封装所有披萨的对象创建,pizza店客户端中不会进行实例化
代码如下:
// 简单工厂代码
public Pizza SimplePizzaFactory {
public Pizza createPizza(String type) {
Pizza pizza = null;
if (type.equals("cheess")) {
pizza = new CheesePizza();
} else if (type.equals("greek")) {
pizza = new GreekPizza();
}
}
}
// pizza店客户端代码
public class PizzaStore {
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = factory.createPizza(type);
// pizza的前期准备
pizza.prepare();
pizza.bake();
return pizza;
}
}
简单工厂模式的类图:
简单工厂模式的优点:
- 将变化的部分抽离出来独立形成工厂,避免在客户端直接创建
简单工厂模式的缺点:
- 简单工厂只是提供了封装对象创建的一种方式,但没有提供工厂方法的弹性,因为它没有办法改变正在创建的产品。
工厂模式
如果pizza店引入了加盟商,加盟商对于pizza需要有一些自己的定制化需求,而上面的简单工厂模式,则不符合这种需求,需要引入工厂模式。
具体代码:
1、定义pizza店接口
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
Pizza pizza;
pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
protected abstract Pizza createPizza(String type); // 交给子类进行实例化
}
2、 抽象pizza的制作流程
public abstract class Pizza {
String name;
String dough;
void prepare() {
System.out.println("prepare finish");
};
void bake() {
System.out.println("bake finish");
};
void cut() {
System.out.println("cut finish");
};
void box() {
System.out.println("box finish");
};
public String getName() {return name;};
}
3、定义加盟商的定制化需求
public class NYPizzaStore extends PizzaStore{
@Override
public Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
}else return null;
}
}
4、定义加盟商所使用的pizza材料
public class NYStyleCheesePizza extends Pizza{
public NYStyleCheesePizza() {
String name = "NY Style pizza";
String dough = "thin crust dough";
String sauce = "Marinara Sauce";
}
}
5、main函数执行
public class Main {
public static void main(String[] args) {
PizzaStore nyStore = new NYPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese");
}
}
执行结果:
prepare finish
bake finish
cut finish
box finish
工厂模式的类图:
工厂模式中引入的设计原则:
- 依赖倒置原则:依赖抽象,而不应该依赖具体类
遵循依赖倒置设计原则的指南:
- 变量不应该持有到具体类的引用
- 类不应该派生自具体类
- 方法不应该覆盖任何基类的已实现方法
(以上指南并不是铁律,要看具体的场景来遵守)
抽象工厂模式
抽象工厂模式提供一个接口来创建相关或依赖对象的家族,而并不需要指定具体的类
比较工厂方法与抽象工厂方法:
工厂方法:
抽象工厂方法:
区别:
- 工厂方法中只会提供一个抽象接口,接口的实现交给各个工厂去做,抽象类只会知道是制作一个pizza。
- 抽象工厂是把工厂方法中的接口给拆开了,提供抽象接口的组合。会感知到制作pizza的抽象信息。
- 抽象方法中对于每一个抽象接口的实现,利用了工厂方法的思路。