定义
工厂方法模式定义了一个创建对象的接口, 但由子类决定要实例化的类是哪一个, 工厂方法让类把实例化推迟到子类
设计原则
- 依赖倒置原则: 要依赖抽象, 不要依赖具体类
依赖: 当你实例化一个对象时,就是在依赖他的具体类, 此案例中若是披萨店直接实例化披萨, 披萨店就依赖于披萨
高层组件与低层组件: 高层组件是由低层组件定义其行为的类, 比如此案例中披萨店属于高层组件, 因为它的行为是由披萨定义的
这个原则说明了: 不能让高层组件依赖于低层组件, 而且, 不管是高层还是低层, 两者都应该依赖于抽象
避免违背依赖倒置原则:
- 变量不可以持有具体类的引用
- 不要让类派生至具体类
- 不要覆盖基类中已实现的方法
工厂方法前结构:
工厂方法后:
案例
背景: 披萨店有很多种的pizza, 需要根据顾客的类型去制作相应类型的披萨, 后续加工的步骤是一样的, 需要设计出种类可拓展, 可能增加或者减少的披萨类
原本的披萨类, 增加或减少披萨种类, orderPizza方法都需要改变, 违背了对修改关闭的原则
public class PizzaStore {
private Pizza pizza;
public void orderPizza(String type) {
if ("cheese".equals(type)) {
pizza = new CheessePizza();
} else if ("clam".equals(type)) {
pizza = new ClamPizza();
}
pizza.prepare();
pizza.bake();
pizza.box();
}
}
简单工厂模式
改成简单工厂模式, 抽取出变化的部分(制造披萨实例, 且这部分抽取出来后可以被不止是披萨店用)
SimplePizzaFactory
public class SimplePizzaFactory {
public Pizza createPizza(String type) {
if ("cheese".equals(type)) {
return new CheessePizza();
} else if ("clam".equals(type)) {
return new ClamPizza();
}
return null;
}
}
PizzaStore, 还是通过持有factory实例, 实例可以通过构造方法传入
public class PizzaStore {
private SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory) {
this.factory = factory;
}
public void orderPizza(String type) {
Pizza pizza = factory.createPizza(type);
pizza.prepare();
pizza.bake();
pizza.box();
}
}
工厂方法模式
背景2: 现在有纽约的和芝加哥的披萨店, 制作的是披萨因地域不同
将PizzaStore中的createPizza改为抽象方法, 由子类不同的披萨工厂去实现, orderPizza只需调用pizza即可, 无需知道具体的类型
public abstract class PizzaStore {
public void orderPizza(String type) {
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.box();
}
protected abstract Pizza createPizza(String type);
}
NYPizzaFactory继承PizzaStore, 重写createPizza方法, 制作出自己地域的pizza
public class NYPizzaFactory extends PizzaStore {
@Override
protected Pizza createPizza(String type) {
if ("cheese".equals(type)) {
return new NYCheessePizza();
} else if ("clam".equals(type)) {
return new NYClamPizza();
}
return null;
}
}
工厂方法让子类决定要实例化的类是哪一个
抽象工厂模式
抽象工厂模式提供一个接口, 用于创建相关或依赖对象的家族, 而不需要明确指定具体类
背景3: 现在不同的工厂需要用不同的原料来制造披萨
PizzaIngredientFactory定义一个抽象工厂
public interface PizzaIngredientFactory {
Dough createDough();
Sauce createSauce();
}
NYIngredientFactory具体工厂来实现createDough(),createSauce()方法, 返回的Dough,Sauce都为抽象类型
public class NYIngredientFactory implements PizzaIngredientFactory {
@Override
public Dough createDough() {
return new NYDough();
}
@Override
public Sauce createSauce() {
return new NYSauce();
}
}
制作披萨则调用抽象工厂的创造原料的方法
public class NYClamPizza extends Pizza {
private PizzaIngredientFactory pizzaIngredientFactory;
public NYClamPizza(PizzaIngredientFactory pizzaIngredientFactory) {
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
@Override
public void prepare() {
// 工厂是抽象的, 可以根据传入工厂的不同, 使用不同工厂的制造方法
Dough dough = pizzaIngredientFactory.createDough();
Sauce sauce = pizzaIngredientFactory.createSauce();
}
}
工厂方法和抽象工厂的对比
- 本质对比
- 整个工厂方法模式, 只不过是通过子类来创建对象; 用这种做法, 客户只需要知道他们所使用的抽象类型就可以了, 而由子类来负责和决定具体类型, 即将客户从具体类型中解耦;
- 抽象工厂模式用来创建一个产品家族的抽象类型, 这个类型的子类定义了产品被产生的方法, 要使用这个工厂必须先实例化它, 同工厂方法一样, 也是将客户从使用的实际具体产品中解耦
2.实现方式
- 工厂方法使用继承, 把对象创建委托给子类, 子类实现工厂方法来创建对象
- 抽象工厂使用对象组合, 对象的创建被实现在工厂接口所暴露出来的方法中
3.使用场景
- 将客户代码从需要实例化的具体类中解耦, 或者目前还不知道将来要实例化哪些具体类时, 可以使用工厂方法模式
- 当需要创建产品家族和想让制造相关产品集合起来时, 可以使用抽象工厂模式