设计模式要求我们不应该针对实现编程,是为了降低耦合度,提高可维护性。当程序中出现“new”的时候,就证明程序在实例化一个具体类,所以用的是实现,而不是接口。如果代码绑着具体的类会导致代码更加脆弱,缺乏弹性。比如,需要创建一“个鸡蛋饼”这个对象,首先需要创建一个饼,然后创建一个鸡蛋,再然后把鸡蛋摊在饼上边,然后给饼翻翻,几分钟后就出炉了....(有点饿)。在这种情况下,新对象的建立是一个过程,如果我们需要在这个饼上边抹点辣椒酱,那肯定需要对类进行修改,违反了“对扩展开放,对修改关闭”的设计原则。这样就出现了一个问题:
如何让客户直接构造出对象的实例,而不用在乎构造对象实例的具体细节?(就比如说,我想吃鸡蛋饼,直接就能买到,不需要知道这个鸡蛋饼如何做出来的)
具体实现:
首先,我们需要知道,工厂模式包含了三种:简单工厂(静态工厂)、工厂方法、抽象工厂。但是简单工厂并不属于GOF的23种设计模式
下边会用制作Pizza的例子来对三个模式进行说明:
假设你有一个Pizza店,并且你有很多种类型的Pizza,那么你会这样写代码:
<span style="font-size:18px;"><span style="font-size:14px;">Pizza orderPizza(String type){ Pizza pizza; if(type.equals("chesse")){ pizza = new CheesePizza(); }else if(type.equals("greek")){ pizza = new GreekPizza(); }else if(type.equals("pepperoni")){ pizza = new PepperoniPizza(); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; }</span></span>根据参数传入类型type的不同,实例化不同的Pizza。
但是,你的竞争对象已经在菜单中加入了其它流行风味Pizza:ClamPizza(蛤蜊披萨)、VeggiePizza(素食披萨)。如果你想要赶上他们你就必须在自己的菜单中加入这些风味的披萨,而GreekPizza(希腊披萨)因为卖的不好所以去掉:
很明显的,orderPizza()方法不能够使得对修改关闭,但是我们已经知道哪些会改变,哪些不会改变,就可以使用封装了。
一、简单工厂模式:
要把创建Pizza的代码移动到另一个对象中,由这个新对象专职创建Pizza:
<span style="font-size:18px;"><span style="font-size:14px;">public class SimplePizzaFactory { public Pizza createPizza(String type) { Pizza pizza = null; if (type.equals("cheese")) { pizza = new CheesePizza(); } else if (type.equals("pepperoni")) { pizza = new PepperoniPizza(); } else if (type.equals("clam")) { pizza = new ClamPizza(); } else if (type.equals("veggie")) { pizza = new VeggiePizza(); } return pizza; } }</span></span>问题:这么做似乎是把问题搬到另一个对象罢了?似乎没有什么好处?
答:SimplePizzaFactory可以有许多的客户,虽然目前仅仅只有orderPizza()方法是它的客户,但是在以后的扩展过程中可能会有很多个客户(但是如果把createPizza()这个方法放入到orderPizza()方法中的话,它只可能为orderPizza()一个服务)。所以,把创建Pizza的代码包装进一个类后,当以后实现改变的话,只需要修改这个类即可。我们正需要做的就是把实例化的过程,从客户的代码中删除。
缺点:因为是静态的,不能够通过继承来改变创建方法的行为。
下边,我们把其它的类写出来:
PizzaStore:是SimplePizzaFactory工厂类的“客户”,PizzaStor通过工厂类取得Pizza的实例
<span style="font-size:18px;"><span style="font-size:14px;">public class PizzaStore { SimplePizzaFactory factory; public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; } public Pizza orderPizza(String type) { Pizza pizza; pizza = factory.createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }</span></span>Pizza:工厂的产品
<span style="font-size:18px;"><span style="font-size:14px;">abstract public class Pizza { String name; String dough; String sauce; ArrayList<String> toppings = new ArrayList<String>(); public String getName() { return name; } public void prepare() { System.out.println("Preparing " + name); } public void bake() { System.out.println("Baking " + name); } public void cut() { System.out.println("Cutting " + name); } public void box() { System.out.println("Boxing " + name); } public String toString() { StringBuffer display = new StringBuffer(); display.append("---- " + name + " ----\n"); display.append(dough + "\n"); display.append(sauce + "\n"); for (int i = 0; i < toppings.size(); i++) { display.append(toppings.get(i) + "\n"); } return display.toString(); } } </span></span>CheesePizza:
<span style="font-size:18px;"><span style="font-size:14px;">public class CheesePizza extends Pizza { public CheesePizza() { name = "Cheese Pizza"; dough = "Regular Crust"; sauce = "Marinara Pizza Sauce"; toppings.add("Fresh Mozzarella"); toppings.add("Parmesan"); } }</span></span>VeggiePizza:
<span style="font-size:18px;"><span style="font-size:14px;">public class VeggiePizza extends Pizza { public VeggiePizza() { name = "Veggie Pizza"; dough = "Crust"; sauce = "Marinara sauce"; toppings.add("Shredded mozzarella"); toppings.add("Grated parmesan"); toppings.add("Diced onion"); toppings.add("Sliced mushrooms"); toppings.add("Sliced red pepper"); toppings.add("Sliced black olives"); } }</span></span>ClamPizza:
<span style="font-size:18px;"><span style="font-size:14px;">public class ClamPizza extends Pizza { public ClamPizza() { name = "Clam Pizza"; dough = "Thin crust"; sauce = "White garlic sauce"; toppings.add("Clams"); toppings.add("Grated parmesan cheese"); } }</span></span>
写一个Main类:PizzaTestDrive
<span style="font-size:18px;"><span style="font-size:14px;">public class PizzaTestDrive { public static void main(String[] args) { SimplePizzaFactory factory = new SimplePizzaFactory(); PizzaStore store = new PizzaStore(factory); Pizza pizza = store.orderPizza("cheese"); System.out.println("We ordered a " + pizza.getName() + "\n"); pizza = store.orderPizza("veggie"); System.out.println("We ordered a " + pizza.getName() + "\n"); } }</span></span>
二、工厂方法模式
特点:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类
现在,大家都希望能够在自家附近加盟你开的披萨店(其实就是想用你的招牌在他们那里开店啦)。但是,每个区域都会有差异,每家加盟店都想要提供不同风味的比萨(比方说纽约、芝加哥、加州),你想这样做:
<span style="font-size:18px;"><span style="font-size:14px;">//纽约风味的素食Pizza NYPizzaFactory nyFactory = new NYPizzaFactory(); PizzaStore nyStore = new PizzaStore(nyFactory); nyStore.orderPizza("Veggie"); //芝加哥风味的素食Pizza ChicagePizzaFactory chicagoFactory = new ChicagePizzaFactory(); PizzaStore chicagoStore = new PizzaStore(chicagoFactory); chicagoStore.orderPizza("Veggie");</span></span>问题:但是,在推广你的方法的时候,别的加盟店的确是采用你的工厂创建比萨,但是其他部分却开始此采用他们自创的流程:烘烤的做法有差异、不要切片、使用其他厂商的盒子等等。
有一种做法可以让比萨制作活动局限于PizzaStore类,而同时又能让这些加盟店依然可以自由的制作本地区域的风味:
把createPizza()方法放回到PizzaStore中,不过要把它设置成“抽象方法”:(原本是由一个对象负责所有具体类的实例化,现在通过对PizzaStor做一些转变,变成由一群子类来负责实例化)
声明一个工厂类:
<span style="font-size:18px;"><span style="font-size:14px;">public abstract class PizzaStore { //把createPizza()方法设置成抽象的,由子类做决定 abstract Pizza createPizza(String item); public Pizza orderPizza(String type) { Pizza pizza = createPizza(type); System.out.println("--- Making a " + pizza.getName() + " ---"); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }</span></span>然后声明两个具体工厂类:NYPizzaStore、ChicagoPizzaStore:
<span style="font-size:18px;"><span style="font-size:14px;">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; } }</span></span>
<span style="font-size:18px;"><span style="font-size:14px;">public class ChicagoPizzaStore extends PizzaStore { Pizza createPizza(String item) { 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; } }</span></span>我们需要建立一个Pizza实体类:
<span style="font-size:18px;"><span style="font-size:14px;">public abstract class Pizza { String name; //名称 String dough; //面团类型 String sauce; //酱料 ArrayList<String> toppings = new ArrayList<String>(); //作料 void prepare() { System.out.println("准备 " + name); System.out.println("揉面团..."); System.out.println("添加酱料..."); System.out.println("添加作料: "); for (int i = 0; i < toppings.size(); i++) { System.out.println(" " + toppings.get(i)); } } void bake() { System.out.println("烘烤25分钟"); } void cut() { System.out.println("把Pizza对角切片"); } void box() { System.out.println("把Pizza装盒子"); } public String getName() { return name; } }</span></span>然后需要一些具体的子类,下边定义两个子类:纽约风味的芝士披萨(NYStyleCheesePizza)、芝加哥风味的芝士披萨(ChicageStyleCheesePizza)
<span style="font-size:18px;"><span style="font-size:14px;">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"); } }</span></span>
<span style="font-size:18px;"><span style="font-size:14px;">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"); } //可以覆盖cut()方法 void cut() { System.out.println("Cutting the pizza into square slices"); } }</span></span>
如果我们需要一个纽约风味的芝士披萨,我们应该怎么做:
(1) 需要一个纽约比萨店:PizzaStore nyPizzaStore = new NYPizzaStore();
(2) 下订单:nyPizzaStore.orderPizza("cheese");
(3) orderPizza()方法调用createPizza()方法:Pizza pizza = createPizza("cheese");
(4) 最后经过:pizza.prepare()、pizza.bake()、pizza.cut()、pizza.box()才能完成Pizza
抽象工厂(放在了下一篇)
原文地址:http://blog.csdn.net/u010800530/article/details/45801353