
设计模式之工厂模式
简单工厂模式
初识需要变化的方面
假如你有一个比萨店,身为比萨店的主人,你的代码可能会这么写:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
|
public class Pizza {
private Pizza orderPizza() { Pizza pizza = new Pizza(); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }
private void box() { System.out.println("Packed Pizza"); }
private void cut() { System.out.println("Cut Pizza"); }
private void bake() { System.out.println("Bake Pizza"); }
private void prepare() { System.out.println("Prepare Pizza"); } }
|
假如你需要更多的比萨类型
所以需要增加一些代码,来决定适合的比萨类型,然后再制作比萨:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private Pizza orderPizza(String type) { Pizza pizza = null; if ("cheese".equals(type)) { pizza = new CheesePizza(); } else if ("greek".equals(type)) { pizza = new GreekPizza(); } else if ("pepperoni".equals(type)) { pizza = new PepperoniPizza(); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }
|
如果需要增加更多的类型比萨
此时,如果我们需要增加更多可口的比萨呢,就需要在代码中重新增加类型,随着时间的变化,类型会不断的改变,这无疑是个灾难。
这个时候,该是用封装的时候了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| private Pizza orderPizza(String type) { Pizza pizza = null; if ("cheese".equals(type)) { pizza = new CheesePizza(); } else if ("greek".equals(type)) { pizza = new GreekPizza(); } else if ("pepperoni".equals(type)) { pizza = new PepperoniPizza(); } else if ("clam".equals(type)) { pizza = new ClamPizza(); } else if ("veggie".equals(type)) { pizza = new VeggiePizza(); } return pizza; }
|
建立一个简单比萨工厂
先从工厂本身开始,我们要为所有比萨封装创建对象的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
public class SimplePizzaFactory { public Pizza createPizza(String type) { Pizza pizza = null; if ("cheese".equals(type)) { pizza = new CheesePizza(); } else if ("greek".equals(type)) { pizza = new GreekPizza(); } else if ("pepperoni".equals(type)) { pizza = new PepperoniPizza(); } else if ("clam".equals(type)) { pizza = new ClamPizza(); } else if ("veggie".equals(type)) { pizza = new VeggiePizza(); } return pizza; } }
|
设计比萨店类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public class PizzaStore { private final SimplePizzaFactory simplePizzaFactory; public PizzaStore(SimplePizzaFactory simplePizzaFactory) { this.simplePizzaFactory = simplePizzaFactory; }
private Pizza orderPizza(String type) { Pizza pizza = simplePizzaFactory.createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
|
让我们来定义简单工厂
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。
简单工厂模式类图

工厂方法模式
加盟比萨店
因为我们的比萨店经营有成,现在很多人想加盟我们的比萨店。但是不同区域是有差异的, 比如:纽约、芝加哥、加州等各地的加盟店之间口味也有差异。
改造我们的比萨店
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public abstract class PizzaStore { public Pizza orderPizza(String type) { Pizza pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box();
return pizza; }
protected abstract Pizza createPizza(String type); }
|
现在已经有一个PizzaStore
作为超类,让每个区域加盟比萨店(NewYorkPizzaStore、ChicagoPizzaStore
)都继承这个PizzaStore
,每个子类各自决定如何制造比萨。
让我们开一家纽约风味的比萨店吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class NewYorkPizzaStore extends PizzaStore { @Override protected Pizza createPizza(String type) { Pizza pizza = null; if ("cheese".equals(type)) { pizza = new NewYorkStyleCheesePizza(); } else if ("pepperoni".equals(type)) { pizza = new NewYorkStylePepperoniPizza(); } else if ("clam".equals(type)) { pizza = new NewYorkStyleClamPizza(); } else if ("veggie".equals(type)) { pizza = new NewYorkStyleVeggiePizza(); } return pizza; } }
|
让我们再开一家芝加哥风味的比萨店吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class ChicagoPizzaStore extends PizzaStore { @Override protected Pizza createPizza(String type) { Pizza pizza = null; if ("cheese".equals(type)) { pizza = new ChicagoStyleCheesePizza(); } else if ("pepperoni".equals(type)) { pizza = new ChicagoStylePepperoniPizza(); } else if ("clam".equals(type)) { pizza = new ChicagoStyleClamPizza(); } else if ("veggie".equals(type)) { pizza = new ChicagoStyleVeggiePizza(); } return pizza; } }
|
改造我们的比萨吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
public class Pizza {
protected String name; protected String dough; protected String sauce; protected ArrayList<String> toppings = new ArrayList<>();
public void box() { System.out.println("Place pizza in official PizzaStore box"); }
public void cut() { System.out.println("Cut the pizza into diagonal slices"); }
public void bake() { System.out.println("Bake for 25 minutes at 350"); }
public void prepare() { System.out.println("Prepare " + name +" Pizza"); System.out.println("Tossing dough..."); System.out.println("Adding sauce..."); System.out.println("Adding toppings: "); for (int i = 0; i < toppings.size(); i++) { System.out.println(" " + toppings.get(i)); } }
public String getName() { return name; } }
|
设计纽约风味的比萨
1 2 3 4 5 6 7 8 9
| public class NewYorkStyleCheesePizza extends Pizza { public NewYorkStyleCheesePizza() { super.name = "New York Style Sauce and Cheese Pizza"; super.dough = "Thin Crust Dough"; super.sauce = "Marinara Sauce"; super.toppings.add("Grated Reggiano Cheese"); } }
|
设计芝加哥风味的比萨
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class ChicagoStyleCheesePizza extends Pizza { public ChicagoStyleCheesePizza() { super.name = "Chicago Style Deep Dish Cheese Pizza"; super.dough = "Extra Thick Crust Dough"; super.sauce = "Plum Tomato Sauce"; super.toppings.add("Shredded Mozzarella Cheese"); } @Override public void cut() { System.out.println("Cutting the pizza into square slices"); } }
|
久等了,让我们来制作比萨吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class PizzaTestDrive { public static void main(String[] args) { PizzaStore nyStore = new NewYorkPizzaStore(); PizzaStore chicagoStore = new ChicagoPizzaStore();
Pizza pizza = nyStore.orderPizza("cheese"); System.out.println("Ethan ordered a " + pizza.getName() + "\n");
pizza = chicagoStore.orderPizza("cheese"); System.out.println("Joel ordered a " + pizza.getName() + "\n"); } }
|
认识工厂方法模式的时刻到了
所有工厂模式都用来封装对象的创建。工厂方法模式(Factory Method Pattern
)通过让子类来决定该创建的对象是什么,来达到将对象创建的过程封装的目的。
工厂方法模式类图

定义工厂方法模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| ### 抽象工厂模式
#### 设计原则
要依赖对象,不要依赖具体类
#### 依赖倒置原则
下面的指导方针,能帮助我们避免在OO设计中违反依赖倒置原则:
- 变量不可以持有具体类的引用 - 不要让类派生自具体类 - 不要覆盖基类中已实现的方法
#### 重新建造原料工厂
```java /** * 建造原料工厂 * @author Mr.zxb * @date 2020-08-15 10:05:27 */ public interface PizzaIngredientFactory { /** * 创建面团 * @return */ Dough createDough();
/** * 创建酱汁 * @return */ Sauce createSauce();
/** * 创建奶酪 * @return */ Cheese createCheese();
/** *创建蔬菜 * @return */ Veggies[] createVeggies();
/** *创建意大利辣香肠 * @return */ Peppernoi createPepperoni();
/** * 创建蛤蜊 * @return */ Clams createClam(); }
|
创建纽约原料工厂
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
|
public class NewYorkPizzaIngredientFactory implements PizzaIngredientFactory { @Override public Dough createDough() { return new ThinCrustDough(); }
@Override public Sauce createSauce() { return new MarinaraSauce(); }
@Override public Cheese createCheese() { return new ReggianoCheese(); }
@Override public Veggies[] createVeggies() { return new Veggies[]{ new Garlic(), new Onion(), new Mushroom(), new RedPepper() }; }
@Override public Peppernoi createPepperoni() { return new SlicedPeppernoi(); }
@Override public Clams createClam() { return new FreshClams(); } }
|
重做比萨··· ···
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| import java.util.Arrays;
public abstract class Pizza { protected String name; protected Dough dough; protected Sauce sauce; protected Veggies[] veggies; protected Cheese cheese; protected Peppernoi peppernoi; protected Clams clams;
abstract void prepare();
public void box() { System.out.println("Place pizza in official PizzaStore box"); }
public void cut() { System.out.println("Cut the pizza into diagonal slices"); }
public void bake() { System.out.println("Bake for 25 minutes at 350"); }
public void setName(String name) { this.name = name; }
public String getName() { return name; }
@Override public String toString() { return "Pizza{" + "name='" + name + '\'' + ", dough=" + dough + ", sauce=" + sauce + ", veggies=" + Arrays.toString(veggies) + ", cheese=" + cheese + ", peppernoi=" + peppernoi + ", clams=" + clams + '}'; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
public class CheesePizza extends Pizza {
private final PizzaIngredientFactory ingredientFactory;
public CheesePizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; }
@Override void prepare() { System.out.println("Preparing " + name); super.dough = ingredientFactory.createDough(); super.sauce = ingredientFactory.createSauce(); super.cheese = ingredientFactory.createCheese(); super.veggies = ingredientFactory.createVeggies(); super.clams = ingredientFactory.createClam(); super.peppernoi = ingredientFactory.createPepperoni(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class ClamPizza extends Pizza {
private final PizzaIngredientFactory ingredientFactory;
public ClamPizza(PizzaIngredientFactory ingredientFactory) { this.ingredientFactory = ingredientFactory; }
@Override void prepare() { System.out.println("Preparing " + name); super.dough = ingredientFactory.createDough(); super.sauce = ingredientFactory.createSauce(); super.cheese = ingredientFactory.createCheese(); } }
|
再回到比萨店
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
public abstract class PizzaStore { public Pizza orderPizza(String type) { Pizza pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }
protected abstract Pizza createPizza(String type); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
public class NewYorkPizzaStore extends PizzaStore { @Override protected Pizza createPizza(String type) { PizzaIngredientFactory ingredientFactory = new NewYorkPizzaIngredientFactory(); Pizza pizza = null; if ("cheese".equals(type)) { pizza = new CheesePizza(ingredientFactory); pizza.setName("New York Style Cheese Pizza"); } else if ("clam".equals(type)) { pizza = new ClamPizza(ingredientFactory); pizza.setName("New York Style Clam Pizza"); } return pizza; } }
|
让我们来制作新的比萨吧
1 2 3 4 5 6 7 8 9
| public class PizzaStoreTest { public static void main(String[] args) { PizzaStore nyPizzaStore = new NewYorkPizzaStore(); Pizza pizza = nyPizzaStore.orderPizza("cheese"); System.out.println(pizza); } }
|
定义抽象工厂模式
抽象工厂模式:提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。这样一来,客户就从具体的产品中解耦。
抽象工厂模式类图

总结
- 所有的工厂都是用来封装对象的创建
- 简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦
- 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
- 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中
- 所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合
- 工厂方法允许类将实例化延迟到子类进行
- 抽象工厂创建相关的对象家族,而不需要依赖它们的具体类
- 依赖倒置原则,指导我们避免依赖具体类型,而尽量依赖抽象
- 工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类的编程