一、简单工厂
在这里的设计上,工厂通过组合的方式加入进PizzaStore,而不是继承,更能体现动态绑定的优势。
下面就是简单工厂的设计图
简单工厂,更像是一种编程习惯。还算不上设计模式,那接下来,我们再学习两个重量级的工厂模式,往下看。
二、继承的加盟店(工厂方法模式)
需求:
- 多一些质量控制
- 把加盟店和创建披萨捆绑在一起又要保持加盟店不同的风格。
做法:
- 把create披萨放回到PizzaStore中,但是设置成抽象方法,加盟店去继承PizzaSore,实现不同的create风味。
- 这就把
做决定
的行为,抛给了子类。
工厂方法模式:
定义了一个创建对象得接口,但由子类决定要实例化得类是哪一个。工厂方法让类把实例化得工作推迟到子类中。
代码
Pizza实体与其各自子类实现
package factory.pizza;
import java.util.ArrayList;
public abstract class Pizza {
//披萨名
String name;
//面团类型
String dough;
//酱料
String sauce;
//一套佐料
ArrayList toppings = new ArrayList();
public void prepare(){
System.out.println("Preparing " + name);
System.out.println("Tossing " + dough);
System.out.println("Adding sauce... " + sauce);
System.out.println("Adding toppings : " );
for (int i = 0; i < toppings.size();i++){
System.out.println(" " + toppings.get(i));
}
}
public void bake(){
System.out.println("Bake for 25 minutes at 350");
}
public void cut(){
System.out.println("Cutting the pizza into diagonal slices");
}
public void box(){
System.out.println("Place pizza in official PizzaStore box");
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Pizza{" +
"name='" + name + '\'' +
", dough='" + dough + '\'' +
", sauce='" + sauce + '\'' +
", toppings=" + toppings +
'}';
}
}
//芝加哥风味芝士披萨
public class ChicagoStyleCheesePizza extends Pizza {
public ChicagoStyleCheesePizza() {
name = "Chicago Style Deep Dish Cheese Pizza";
dough = "Extra Thick Crust Dough";
sauce = "Plum Tomato Sauce";
toppings.add("Shredded Mozzarella Cheese");
}
public void cut() {
System.out.println("Cutting the pizza into square slices");
}
}
//纽约风味芝士披萨
public class NYStyleCheesePizza extends Pizza {
public NYStyleCheesePizza() {
name = "NY Style Sauce and Cheese Pizza";
dough = "Thin Crust Dough";
sauce = "Marinara Sauce";
toppings.add("Grated Reggiano Cheese");
}
}
PizzaStore店与其各个具体子类加盟店
public abstract class PizzaStore {
//披萨得加工流程都是不变得
public Pizza orderPizza(String type){
Pizza pizza = null;
//依赖工厂方法创建具体类,并制造出实际得披萨
pizza = createPizza(type);
System.out.println("--- Making a " + pizza.getName());
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
//创建何种披萨需要子类去实现
abstract Pizza createPizza(String item);
}
public class NYPizzaStore extends PizzaStore {
Pizza createPizza(String item) {
if (item.equals("cheese")) {
return new NYStyleCheesePizza();
} else if (item.equals("veggie")) {
return new NYStyleVeggiePizza();
} else if (item.equals("clam")) {
return new NYStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new NYStylePepperoniPizza();
} else return null;
}
}
public class ChicagoPizzaStore extends PizzaStore {
@Override
public Pizza createPizza(String item) {
Pizza pizza = null;
if (item.equals("cheese")) {
return new ChicagoStyleCheesePizza();
} else if (item.equals("veggie")) {
return new ChicagoStyleVeggiePizza();
} else if (item.equals("clam")) {
return new ChicagoStyleClamPizza();
} else if (item.equals("pepperoni")) {
return new ChicagoStylePepperoniPizza();
} else return null;
}
}
快来使用这个工厂模式框架,点几份披萨
public class TestMain {
public static void main(String[] args) {
PizzaStore pizzaStore = new NYPizzaStore();
Pizza pizza01 = pizzaStore.orderPizza("cheese");
System.out.println("Jerry 得到一份披萨 : \n" + pizza01);
PizzaStore pizzaStore02 = new ChicagoPizzaStore();
Pizza pizza02 = pizzaStore02.orderPizza("cheese");
System.out.println("Tom 得到一份披萨 : \n"+ pizza02);
}
}
这样一来Jerry点到了一份纽约风味披萨,Tom点到一份芝加哥风味披萨。
PizzaStore并不知道是哪个加盟店在create披萨,Pizza也不知道到底是哪种Pizza。这都是由具体加盟店去操作的。
总结工厂方法模式:
- 将实例化的任务推迟到具体子类,抽象类中并不知情实际的产品是哪一个产品。
- 用户使用了哪一个子类,就创建了哪一个产品。
三、依赖倒置原则
- 设计原则:要依赖抽象,不要依赖具体类。
- 不能让高层组件依赖底层组件,并且,不管是高层还是底层,“两者” 都应该依赖于抽象。
- 这个原则告诉我们,要依赖于抽象类,而不应该依赖于具体类。
下面是上一节的设计图,可以发现这里还有一个问题 : 每个地区的原料是不同的。
也就是说,你可以发现纽约的酱料都是纽约风格的味道,但是到了芝加哥酱料就会变成当地统一的风格。
目前代码里,酱料的生成还是由具体披萨而定,披萨种类很多,不可能每个具体披萨一创建时就制造一遍本地酱料。
于是,我们委托工厂替我们制作酱料,纽约的加盟店就需要去纽约原料工厂制作酱料,芝加哥的加盟店就去芝加哥工厂。
如图所示,我们把对象的new操作局限在了具体的披萨加盟店,加盟店只需要委托一个当地工厂,然后工厂负责制造原料,加盟店以及具体披萨都不需要管披萨里的原料是什么。这是原料工厂才需要关心的事。
加盟店就只需负责create一个特定口味的披萨(原料已定制)、然后prepare,bake、cut、box.就完成了。