首页 > 代码库 > 工厂模式详解

工厂模式详解

在java中每当看到new 就会想到“具体”,代码绑定着具体的类导致代码脆弱尤其是不利于进行修改. new 关键字本身没有错,需要的是我们针对接口编程,从而隔离掉系统可能发生的一系列改变。重要设计原则:对扩展开放,对修改关闭。

Pizza orderPizza(String type) {	Pizza pizza;	if (type.equals(“cheese”)) {		pizza = new CheesePizza();	} else if (type.equals(“greek”) {		pizza = new GreekPizza();	} else if (type.equals(“pepperoni”) {		pizza = new PepperoniPizza();	} else if (type.equals(“clam”) {		pizza = new ClamPizza();	} else if (type.equals(“veggie”) {		pizza = new VeggiePizza();	}		pizza.prepare();		pizza.bake();		pizza.cut();		pizza.box();		return pizza;}


披萨预定系统上面所看到,if -else部分代码随着菜单改变需要经常变动,而下面部分代码是不需要改变的,知道哪些改变哪些不变,我们需要进行封装啦!

建立一个SimplePizzaFactory类,当需要披萨时就要工厂做一个,orderPizza()方法则不需要知道到底是什么类型披萨。

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;	}}

SimplePizzaFactory类只做一件事根据用户传进来的参数创建披萨,这样如果发生改变每次直接修改SimplePizzaFactory类,比先前写在用户代码中维护性要提高一些。

修改我们客户端代码为:

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;	}		// other methods here}

orderPizza()方法通过简单传入披萨类型使用工厂创建披萨。pizza = factory.createPizza(type);把new操作符替换为对象创建方法,这里不再使用具体实例化,解耦合。

定义简单工厂:上述用到的思想简单工厂其实不是一种设计模式,反而像是一种编程习惯,通过看上述披萨店的实现类图,能更好理解问题!

 

小概念:设计模式中,实现一个接口并不一定只是指 implement 实现某个java接口,而是泛指实现某个超类型(可以是类或接口)的某个方法。

现在需求是加盟披萨店:加盟店需要提供不同风味的披萨(纽约、芝加哥、加州。。。)现在样子会变成如下:

NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.order(“Veggie”);

ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory();
PizzaStore chicagoStore = new PizzaStore(chicagoFactory);
chicagoStore.order(“Veggie”);

现在想实现目标就是:加盟店和创建披萨在一起同时还能保持弹性。看看PizzaStore的改变

package factoryMethod;public abstract class PizzaStore {	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;	}}

abstract Pizza createPizza(String item);可以看到PizzaStore现在作为超类;让NYPizzaStore, ChicagoPizzaStore,CaliforniaPizzaStore都继承它,每个子类各自决定如何制造披萨。下图看到具体怎么进行


NYPizzaStore, ChicagoPizzaStore具体实现代码如下:

package factoryMethod;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 			System.out.println("parameter is wrong ");			return null;	}}

 

package factoryMethod;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;	}}


说了这么多,忽略了一件事就是披萨本身!

<strong>package factoryMethod;import java.util.ArrayList;public abstract class Pizza {	String name;	String dough;	String sauce;	ArrayList<String> toppings = new ArrayList<String>();	void prepare() {		System.out.println("Preparing " + name);		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));		}	}	void bake() {		System.out.println("Bake for 25 minutes at 350");	}	void cut() {		System.out.println("Cutting 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 (int i = 0; i < toppings.size(); i++) {			display.append((String) toppings.get(i) + "\n");		}		return display.toString();	}}</strong>

 

现在简单的列出一些具体披萨子类:

package factoryMethod;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");	}}


。。。子类实现还有很多。

现在开始正式认识工厂方法模式:

上图是创建者类图,下面给出产品类类图:

工厂模式的定义:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

这里披萨工厂模式完整的类图:

下面是一些重要的设计原则:

package net.dp.factory.factoryMethod;public class DependentPizzaStore { 	public Pizza createPizza(String style, String type) {		Pizza pizza = null;		if (style.equals("NY")) {			if (type.equals("cheese")) {				pizza = new NYStyleCheesePizza();			} else if (type.equals("veggie")) {				pizza = new NYStyleVeggiePizza();			} else if (type.equals("clam")) {				pizza = new NYStyleClamPizza();			} else if (type.equals("pepperoni")) {				pizza = new NYStylePepperoniPizza();			}		} else if (style.equals("Chicago")) {			if (type.equals("cheese")) {				pizza = new ChicagoStyleCheesePizza();			} else if (type.equals("veggie")) {				pizza = new ChicagoStyleVeggiePizza();			} else if (type.equals("clam")) {				pizza = new ChicagoStyleClamPizza();			} else if (type.equals("pepperoni")) {				pizza = new ChicagoStylePepperoniPizza();			}		} else {			System.out.println("Error: invalid type of pizza");			return null;		}		pizza.prepare();		pizza.bake();		pizza.cut();		pizza.box();		return pizza;	}}

上面这段代码我们可以清楚看到createPizza将依赖8个具体类,很清楚减少代码中的依赖是好事;设计原则:要依赖抽象,不要依赖具体类

应用上面的原则可以把createPizza将依赖8个具体类进行修正为如下图:

几个指导方针帮助遵循上述原则:

(1)变量不可以持有具体类的引用。(如果使用new 就会持有具体类的引用,可以改用工厂避开)

(2)不要让类派生自具体类。(如果派生自具体类,就会依赖具体类。请派生自一个抽象(前面说了抽象是广义指接口或者抽象类))

(3)不要覆盖基类中已实现的方法。

需要清楚的是要完全遵守这些指导方针是不可能的,只能说应该尽量去遵守这个原则,我们知道任何java程序都有违反指导方针的地方!

举例说,如果一个不太会改变的类,那么在代码中直接初始化没什么问题。想想实例化字符串对象。

这里是工厂模式代码免积分下载:http://download.csdn.net/detail/huruzun/7391259