设计模式之工厂模式(上篇)
为了面向接口编程,而不是面向实现编程,所以此时我么就不能再直接使用new了,因
为当看到“new”时,我们就会想到“具体”。
下面来看一个例子,假如你有一个披萨店,你的代码可能这么写:
1 pizza orderpizza(){ 2 pizza pizza = new pizza(); 3 4 pizza.prepare(); 5 pizza.bake(); 6 pizza.cut(); 7 pizza.box(); 8 9 return pizza; 10 }
但是此时你需要更多披萨类型,所以你就要修改代码,如下所示:
1 pizza orderpizza(string type){ 2 pizza pizza = new pizza(); 3 4 if (type.equals("cheese")) { 5 pizza = new cheesepizza(); 6 } else if (type.equals("pepperoni")) { 7 pizza = new pepperonipizza(); 8 } else if (type.equals("clam")) { 9 pizza = new clampizza(); 10 } else if (type.equals("veggie")) { 11 pizza = new veggiepizza(); 12 } 13 14 pizza.prepare(); 15 pizza.bake(); 16 pizza.cut(); 17 pizza.box(); 18 19 return pizza; 20 }
但是此时由于产业竞争问题,你想加入一些其他口味的pizza或者删除某几种pizza,那么
你就不得不修改orderpizza(string type)里的4-12行,所以随着时间的推移,这个类就必
须一改再改,这毫无疑问是不好的!所以我们现在来把创建对象的代码封装起来,如下所
示:
这时我们称这个新对象(simplepizzafactory)为“工厂”,用来处理创建对象的细节。
现在让我们创建一个简单的披萨工厂:
先从工厂本身开始,封装创建对象的代码(simplepizzafactory.java):
1 public class simplepizzafactory { 2 public pizza createpizza(string type) { 3 pizza pizza = null; 4 5 if (type.equals("cheese")) { 6 pizza = new cheesepizza(); 7 } else if (type.equals("pepperoni")) { 8 pizza = new pepperonipizza(); 9 } else if (type.equals("clam")) { 10 pizza = new clampizza(); 11 } else if (type.equals("veggie")) { 12 pizza = new veggiepizza(); 13 } 14 return pizza; 15 } 16 }
重做pizzastore(pizzastore.java):
1 public class pizzastore { 2 simplepizzafactory factory; 3 4 public pizzastore(simplepizzafactory factory) { 5 this.factory = factory; 6 } 7 8 public pizza orderpizza(string type) { 9 pizza pizza; 10 11 pizza = factory.createpizza(type); 12 13 pizza.prepare(); 14 pizza.bake(); 15 pizza.cut(); 16 pizza.box(); 17 18 return pizza; 19 } 20 }
测试类(main.java):
1 public class main { 2 3 public static void main(string[] args) { 4 simplepizzafactory factory = new simplepizzafactory(); 5 pizzastore store = new pizzastore(factory); 6 7 pizza pizza = store.orderpizza("cheese"); 8 system.out.println("we ordered a " + pizza.getname() + "\n"); 9 system.out.println(pizza); 10 11 pizza = store.orderpizza("veggie"); 12 system.out.println("we ordered a " + pizza.getname() + "\n"); 13 system.out.println(pizza); 14 } 15 }
结果展示:
好啦,这个示例完成了,这个其实叫做简单工厂,他其实不是一个设计模式,而更像是一
种编程习惯。这里只列举了这个项目的关键代码,至于这个简单工厂的完整代码,读者可
到:https://github.com/stray-kite/design-pattern/tree/master/src/headfirst/designpatterns/factory/pizzas
下载。
好了,下载聊完了简单工厂,那么让我们进入正题,聊一聊两个重量级的模式,他们都是
工厂!
现在我们要建立几个加盟店。
有了这个图,你开始有一个想法啦,那就是:
1 nypizzafactory nyfactory = new nypizzafactory(); 2 pizzastore nystore = new pizzastore(nyfactory); 3 nystore.orderpizza("veggie"); 4 5 chicagepizzafactory chicagefactory = new chicagepizzafactory(); 6 pizzastore chicagestore = new pizzastore(chicagofactory); 7 chicagostore.orderpizza("veggie");
但是,你想要多一些质量控制:在推广simplefactory时,你发现加盟店的确是采用你的工
厂创建披萨,但是其他部分,却开始采用他们自创的流程:烘烤的做法有些差异、不要切片
、使用其他厂商的盒子。
再想想这个问题,你真的希望能够建立一个框架,把加盟店和创建披萨捆绑在一起的同时又
保持一定的弹性。
所以开始使用框架啦:
首先,看看pizzastore(pizzastore.java)所做的改变;喔嚯,变成抽象的了,也就是把创
建对象的工作移交给子类做决定了:
1 public abstract class pizzastore { 2 abstract pizza createpizza(string item); 3 4 public pizza orderpizza(string type) { 5 pizza pizza = createpizza(type); 6 system.out.println("--- making a " + pizza.getname() + " ---"); 7 pizza.prepare(); 8 pizza.bake(); 9 pizza.cut(); 10 pizza.box(); 11 return pizza; 12 } 13 }
接下来,轮到子类给pizzastore做决定了!(nypizzastore.java和chicagepizzastore.java
,这是两个披萨店):
1 public class chicagopizzastore extends pizzastore { 2 pizza createpizza(string item) { 3 if (item.equals("cheese")) { 4 return new chicagostylecheesepizza(); 5 } else if (item.equals("veggie")) { 6 return new chicagostyleveggiepizza(); 7 } else if (item.equals("clam")) { 8 return new chicagostyleclampizza(); 9 } else if (item.equals("pepperoni")) { 10 return new chicagostylepepperonipizza(); 11 } else return null; 12 } 13 }
1 public class nypizzastore extends pizzastore{ 2 pizza createpizza(string item) { 3 if (item.equals("cheese")) { 4 return new nystylecheesepizza(); 5 } else if (item.equals("veggie")) { 6 return new nystyleveggiepizza(); 7 } else if (item.equals("clam")) { 8 return new nystyleclampizza(); 9 } else if (item.equals("pepperoni")) { 10 return new nystylepepperonipizza(); 11 } else return null; 12 } 13 }
差点忘记了,我们还得写一个比萨本身(pizza.java):
1 import java.util.arraylist; 2 3 public abstract class pizza { 4 string name; 5 string dough; 6 string sauce; 7 arraylist<string> toppings = new arraylist<string>(); 8 9 void prepare() { 10 system.out.println("prepare " + name); 11 system.out.println("tossing dough..."); 12 system.out.println("adding sauce..."); 13 system.out.println("adding toppings: "); 14 for (string topping : toppings) { 15 system.out.println(" " + topping); 16 } 17 } 18 19 void bake() { 20 system.out.println("bake for 25 minutes at 350"); 21 } 22 23 void cut() { 24 system.out.println("cut the pizza into diagonal slices"); 25 } 26 27 void box() { 28 system.out.println("place pizza in official pizzastore box"); 29 } 30 31 public string getname() { 32 return name; 33 } 34 35 public string tostring() { 36 stringbuffer display = new stringbuffer(); 37 display.append("---- " + name + " ----\n"); 38 display.append(dough + "\n"); 39 display.append(sauce + "\n"); 40 for (string topping : toppings) { 41 display.append(topping + "\n"); 42 } 43 return display.tostring(); 44 } 45 }
然后还剩下,一些具体的子类:定义两个不同的店的芝士披萨
nystylecheesepizza.java:
1 public class nystylecheesepizza extends pizza { 2 public nystylecheesepizza() { 3 name = "ny style sauce and cheese pizza"; 4 dough = "thin crust dough"; 5 sauce = "marinara sauce"; 6 7 toppings.add("grated reggiano cheese"); 8 } 9 }
chicagostylecheesepizza.java:
1 public class chicagostylecheesepizza extends pizza { 2 public chicagostylecheesepizza() { 3 name = "chicago style deep dish cheese pizza"; 4 dough = "extra thick crust dough"; 5 sauce = "plum tomato sauce"; 6 7 toppings.add("shredded mozzarella cheese"); 8 } 9 10 void cut() { 11 system.out.println("cutting the pizza into square slices"); 12 } 13 }
最后来一组测试类(main.java):
1 public class main { 2 3 public static void main(string[] args) { 4 pizzastore nystore = new nypizzastore(); 5 pizzastore chicagostore = new chicagopizzastore(); 6 7 pizza pizza = nystore.orderpizza("cheese"); 8 system.out.println("ethan ordered a " + pizza.getname() + "\n"); 9 10 pizza = chicagostore.orderpizza("cheese"); 11 system.out.println("joel ordered a " + pizza.getname() + "\n"); 12 13 pizza = nystore.orderpizza("clam"); 14 system.out.println("ethan ordered a " + pizza.getname() + "\n"); 15 16 pizza = chicagostore.orderpizza("clam"); 17 system.out.println("joel ordered a " + pizza.getname() + "\n"); 18 19 pizza = nystore.orderpizza("pepperoni"); 20 system.out.println("ethan ordered a " + pizza.getname() + "\n"); 21 22 pizza = chicagostore.orderpizza("pepperoni"); 23 system.out.println("joel ordered a " + pizza.getname() + "\n"); 24 25 pizza = nystore.orderpizza("veggie"); 26 system.out.println("ethan ordered a " + pizza.getname() + "\n"); 27 28 pizza = chicagostore.orderpizza("veggie"); 29 system.out.println("joel ordered a " + pizza.getname() + "\n"); 30 } 31 }
结果展示(部分结果):
此段代码地址:
好了,现在然我们看一下工厂模式的定义吧!
工厂模式:定义一个创建对象的接口,但由子类决定要实例化的是哪一个。工厂方法让类把
实例化推迟到了子类。
重点:简单工厂和工厂方法的区别:
子类的确看起来很像简单工厂。简单工程把全部的事情,在一个地方都处理完了,然而工厂方
法却是创建了一个框架,让子类决定要如何实现。比方说,在工厂方法中,orderpizza()方法提供了
一个一般的框架,以便创建披萨,orderpizza()方法依赖工厂方法创建具体类,并制造出实际的披萨
。可通过继承pizzastore()类,决定实际制造出的披萨是什么。简单工厂的做法,可以将对象创建封
装起来,但是简单工厂不具备工厂方法的弹性,因为简单工程不能变更正在创建的产品。
未完待续......
上一篇: Python【列表 字典 元组】
下一篇: 浅谈 Flask 框架