《Head First 设计模式》 学习笔记,码云同步更新中
如有错误或不足之处,请一定指出,谢谢~
目录
查看其它设计模式笔记,点这里→设计模式笔记汇总
抽象工厂模式(Abstract Factory Pattern)
- 定义:
- 提供一个创建一系列相关或相互依赖对象的接口,用于创建相关或依赖对象的家族,而无须指定它们具体的类。
- 结构:
- AbstractFactory:抽象工厂
- ConcreteFactory:具体工厂
- AbstractProduct:抽象产品
- ConcreteProduct:具体产品
- 对比工厂方法和简单工厂:
- 工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
- 当抽象工厂模式中每一个具体工厂只创建一个产品对象,那抽象工厂模式就退化为工厂方法模式。
- 当工厂方法模式的抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,那工厂方法模式就退化为简单工厂。
- 优点:
- 新增加具体工厂和产品族很方便,符合“开闭”原则
- 符合“依赖倒置”原则
- 高层模块不需要关心低层模块的具体实现,只需要关心抽象,关心工厂。
- 抽象工厂可以约束产品族的特性(比如配比,芝士与奶油1:2)
- 缺点:
- 对于产品族的扩展非常困难。抽象工厂中定义了有可能会被创建的所有产品的方法。如果新增产品,就必须要修改抽象类和所有实现类。(“开闭原则”的倾斜性)
- 使用场景:
- 系统中有多个产品族,每次只使用其中某一族
- 系统需要约束属于同一产品族的产品必须在一起使用
- 案例:
- 简单工厂:顾客点单时,需要根据菜名创建出各种不同种类的披萨。这些披萨都源自同一个披萨基类,不过各自有自己的口味实现。而我们创建具体的披萨对象时,只需要提供名字,不需要知道它们是如何创建的。这时就可以用到简单工厂,传递一个参数给工厂类,返回一个相应的披萨对象。
- 工厂方法:这时我们披萨店要扩张了,但在各个省可能会有不同的制作方法。我们希望披萨在披萨口味上加盟店有自己的决定权。但在制作流程上要受到总店的控制,比如必须使用我们品牌的盒子来装披萨等等。
这时候就需要我们用工厂方法模式来改造了。 - ok,又有新需求了。有些加盟店会使用廉价的原料来增加利润。你想要更多的质量控制——建造一家原料工厂,将原料运送到加盟店。同时问题也出现了,各地加盟店的披萨口味不同,原料也是不一样的。这时候抽象工厂模式就有用武之地了。
- 代码:
/**
* 披萨原料抽象工厂
**/
public interface PizzaIngredientFactory {
Cheese createCheese();
Pepperoni createPepperoni();
}
/**
* 意大利香肠原料
**/
public interface Pepperoni {
// 略...
}
/**
* 芝士原料
**/
public interface Cheese {
// 略...
}
/**
* 上海用的芝士
**/
public class SHCheese implements Cheese {
// 略...
}
/**
* 上海用的香肠
**/
public class SHPepperoni implements Pepperoni {
// 略...
}
/**
* 披萨 抽象
**/
public abstract class Pizza {
String name;
public Cheese cheese;
public Pepperoni pepperoni;
/**
* 准备
* 申明为抽象方法,子类需自行实现原料准备
*/
public abstract void prepare();
/**
* 烘焙
*/
public void bake() {
System.out.println("烘焙中...");
}
/**
* 切片
*/
public void cut() {
System.out.println("切片中...");
}
/**
* 装盒
*/
public void box() {
System.out.println("装盒中...");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 芝士披萨
**/
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
/**
* 构造器注入工厂
*
* @param ingredientFactory
*/
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
/**
* pizza无需关心到底是什么类型的原料工厂,只要是原料工厂就行
*/
@Override
public void prepare() {
System.out.println("原料准备中");
// 为基类属性赋值
cheese = ingredientFactory.createCheese();
pepperoni = ingredientFactory.createPepperoni();
}
}
/**
* 披萨店 抽象
**/
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
// 把创建披萨方法从简单工厂拿回来
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
System.out.println(pizza.getName() + "制作完成");
return pizza;
}
/**
* 将实例化披萨的责任移到抽象方法中,这个方法就等同于一个工厂
* 子类通过这个方法来执行对象实例化逻辑,达到超类和子类解耦的目的
*/
abstract Pizza createPizza(String type);
}
/**
* 上海加盟店
**/
public class SHPizzaStore extends PizzaStore {
/**
* 上海披萨原料工厂
*/
private PizzaIngredientFactory ingredientFactory = new SHPizzaIngredientFactory();
private Pizza pizza;
@Override
protected Pizza createPizza(String type) {
if ("cheese".equals(type)) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("上海芝士披萨");
return pizza;
} else if ("veggie".equals(type)) {
// 略...
return null;
}
return null;
}
}
/**
* 测试类
**/
public class Test {
public static void main(String[] args) {
SHPizzaStore shPizzaStore = new SHPizzaStore();
shPizzaStore.orderPizza("cheese");
}
}
结果:
原料准备中
原料:上海芝士
原料:上海腊肠
烘焙中...
切片中...
装盒中...
上海芝士披萨制作完成
网友评论