设计模式之工厂模式(二)
之前已经带大家稍微入门了工厂模式(即简单工厂模式)的方法,没看过的朋友可以移步去查看一番。。今天我们继续吃着披萨,学习着工厂模式的接下来部分吧。
加盟披萨店
我们先前的披萨店已经经营有成,击败了部分竞争者,接下来的计划就是开加盟店。作为经营者,你肯定希望确保加盟店运营的质量,所以希望这些店都是用你那些经过时间考验的代码。
但是每个地方可能需要不同口味的披萨(比如a地区、b地区、c地区等),这就是开店地点以及该地区披萨美食家口味的影像。
如果利用先前的简单工厂,那么就是需要创建多个不同的工厂可以使用。代码如下:
nypizzafactory nyfactory = new nypizzafactory(); pizzastore nystore = new pizzastore(nyfactory); nystore.orderpizza("veggie"); chicagopizzafactory chicagofactory = new chicagopizzafactory(); pizzastore nystore = new pizzastore(chicagofactory); nystore.orderpizza("veggie");
给披萨店使用的框架
在使用简单工厂的时候,我们发现加盟店的确是采用工厂创建披萨,但是其他部分,却开始采用自己的方式。有个做法可以让披萨制作活动局限于pizzastore类,而同时又能让这些加盟店可以*地制作该地区的风味。
所要做的事情呢,就是把之前createpizza()方法放回到pizzastore中,不过不是单纯的放回来,而是把它设置成抽象方法,然后每个区域创建一个pizzastore的子类即可。.放出部分代码来看看
public abstract class pizzastore { public pizza orderpizza(string type) { // 现在createpizza()方法从工厂对象中移回pizzastore pizza pizza = createpizza(type); ... return pizza; } // 现在把工厂对象移动到这个方法中 abstract pizza createpizza(string type); }
现在上面这个就作为超类;让每个域类型都继承这个pizzastore,每个子类各自决定如何制造披萨。
允许子类做决定
我们现在要让createpizza()能够应对各种变化创建正确种类的披萨。做法是让pizzastore的各个子类负责定义自己的createpizza()方法。所以,我们会得到一些pizzastore具体的子类,每个子类都有自己的披萨变体,而仍然适合pizzastore框架,并使用调试好的orderpizza()方法。
;
这时候会有人肯定纳闷了,pizzastore的子类终究是子类,如何能做决定呢?关于这个方面,要从pizzastore的orderpizza()方法观点来看,此方法在抽象的pizzastore内定义,但是只在子类中实现具体类型。
现在,更进一步地,orderpizza()方法对pizza对象做了许多事情,但由于pizza对象是抽象的,orderpizza()并不知道哪些实际的具体类参与进来了。换句话说,这就是解耦(decopule)。
当orderpizza()调用createpizza()时,就会由具体的披萨店来决定做哪一种披萨。那么,子类是实时做出这样的决定吗?不是,但从orderpizza()角度来看,如果选择在nystylepizzastore订购披萨,就是由这个子类决定。
让我们开一家披萨店吧
现在我们把加盟店开了。其实我们只需要继承pizzastore,然后提供createpizza()方法实现自己的披萨风味即可。比如纽约风味:
// nypizzastore扩展pizzastore,所以拥有orderpizza方法(以及其他方法) public class nypizzastore extends pizzastore { // createpizza()返回一个pizza对象,由子类全权负责该实例化哪一个具体的pizza 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; } }
工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这样,客户程序中关于超类的代码就和子类对象创建代码解耦了。
如何利用披萨工厂方法订购披萨
- 首先,需要取得披萨店的实例。a需要实例化一个chicagopizzastore,而b需要一个nypizzastore
- 有了各自的pizzastore,a和b分别调用orderpizza()方法,并传入他们所喜爱的披萨类型
- orderpizza()调用createpizza()创建披萨。其中nypizzastore实例化的是纽约风味披萨,而chicagopizzastore实例化的是芝加哥风味披萨。createpizza()会创建好的披萨当做返回值。
- orderpizza()并不知道真正创建的是哪一个披萨,只知道这是一个披萨,能够被准备、被烘烤、被切片、被装盒、然后提供给a和b
看看如何根据订单生产这些披萨
- 先看看a的订单,首先我们需要一个纽约披萨店:
// 建立一个nypizzastore的实例 pizzastore nypizzastore = new nypizzastore();
- 现在有了一个店,可以下订单了:
// 调用nypizzastore实例的orderpizza()方法 nypizzastore.orderpizza("cheese");
- orderpizza()方法于是调用cratepizza()方法
// 别忘了,工厂方法create-pizza()是在子类中实现的。在这个例子中,他会返回纽约芝士披萨 pizza pizza = createpizza("cheese");
- 最后,披萨必须经过下列的处理才算成功orderpizza();
pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box();
吃披萨咯
我们需要先有一个比萨,不然披萨店开起来了,结果没有产品,岂不是很尴尬。
// 从一个抽象披萨类开始,所有的具体披萨都必须派生自这个类 public abstract class pizza { string name; string dough; string sauce; arraylist<string> toppings = new arraylist<string>(); void prepare() { system.out.println("prepare " + name); system.out.println("tossing dough..."); system.out.println("adding sauce..."); system.out.println("adding toppings: "); for (string topping : toppings) { system.out.println(" " + topping); } } void bake() { system.out.println("bake for 25 minutes at 350"); } void cut() { system.out.println("cut the pizza into diagonal slices"); } void box() { system.out.println("place pizza in official pizzastore box"); } public string getname() { return name; } public string tostring() { stringbuffer display = new stringbuffer(); display.append("---- " + name + " ----\n"); display.append(dough + "\n"); display.append(sauce + "\n"); for (string topping : toppings) { display.append(topping + "\n"); } return display.tostring(); } }
我们来定义一些具体的子类,在这里,其实就是定义纽约和芝加哥风味的芝士披萨
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"); } }
public class chicagostyleclampizza extends pizza { public chicagostyleclampizza() { name = "chicago style clam pizza"; dough = "extra thick crust dough"; sauce = "plum tomato sauce"; toppings.add("shredded mozzarella cheese"); toppings.add("frozen clams from chesapeake bay"); } void cut() { system.out.println("cutting the pizza into square slices"); } }
好了等久了吧,马上来吃披萨了,这个时候刚好是下午4点左右,小编感觉已经饿的不行。
public class pizzatestdrive { public static void main(string[] args) { pizzastore nystore = new nypizzastore(); 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"); pizza = nystore.orderpizza("clam"); system.out.println("ethan ordered a " + pizza.getname() + "\n"); pizza = chicagostore.orderpizza("clam"); system.out.println("joel ordered a " + pizza.getname() + "\n"); pizza = nystore.orderpizza("pepperoni"); system.out.println("ethan ordered a " + pizza.getname() + "\n"); pizza = chicagostore.orderpizza("pepperoni"); system.out.println("joel ordered a " + pizza.getname() + "\n"); pizza = nystore.orderpizza("veggie"); system.out.println("ethan ordered a " + pizza.getname() + "\n"); pizza = chicagostore.orderpizza("veggie"); system.out.println("joel ordered a " + pizza.getname() + "\n"); } }
好了,至此我们已经开了纽约和芝加哥披萨店,并已经愉快的制作和吃上了披萨,而且这是通过我们的工厂方法模式创建并得到的。
关于认识工厂方法模式,因为这篇我们已经通过代码来了解了下,我将在下一篇进行解释并进一步认识这个模式,请大家敬请期待吧。
ps:因为工厂模式涉及的篇幅较大,几篇文章可能存在不合理的衔接,小编会尽快输出全部文章,让大家能一次了解,在此给大家道个歉。
github地址 headfirstdesign
上一篇: 绵羊撒谎
下一篇: window.open 防止浏览器拦截