论坛首页 Java版 设计模式

设计模式入门学习之工厂模式(抽象工厂模式)

浏览 936 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2008-02-02 关键字: 设计模式

当你直接实例化一个对象时,就是在依赖它的具体类.很清楚地,代码里减少对于具体类的依赖是件"好事".
依赖倒置原则:
         要依赖抽象,不要依赖具体类.

这个原则说明了:不能让高层组件依赖低层组件,而且,不管高层或低层组件,两者都应该依赖于抽象.现在我们通过这个原则来重写披萨代码以便我们依赖抽象类而不依赖具体类.
下面的几个指导方针,能帮你避免在OO设计中违反依赖倒置原则:
1.变量不可以持有具体类的引用
2.不要让类派生自具体类
3.不要覆盖基类中已经实现的方法.
在工厂方法模式中,非常依赖披萨店的主要问题在于:它依赖每个披萨类型,因为它是在自己的orderPizza()方法中实例化这些具体类型的.如何在orderPizza()方法中将这些实例化对象的代码独立出来?我们继续以披萨店为例来说明.披萨店成功的关键在于新鲜.高质量的原则,但是有些加盟店使用低价原料来增加利润,你必须采取一些手段,确保加盟店都使用高质量的原料,以免毁了披萨店的品牌,让我们看的更仔细些:

//我们建造一个工厂来生产原料,开始为工厂定义一个接口,这个接口负责创建所有的原料:
public interface PizzaIngredientFactory {
	//在接口中,每个原料都有一个对应的方法创建该原料
	public Dough createDough();
	public Sauce createSauce();
	public Cheese createCheese();
	public Veggies[] createVeggies();
	public Pepperoni createPepperoni();
	public Clams createClam(); 
	//这里有许多新类,每个原料都是一个类,这里我就不写出来了
}
//再来创建纽约原料工厂,必须实现此接口,芝加哥原料工厂差不多
public class NYPizzaIngredientFactory implements PizzaIngredientFactory {
	//对于原料家族内的每一种原料,我们都提供了纽约版本
	public Dough createDough() {
		return new ThinCrustDough();
	}
	public Sauce createSauce() {
		return new MarinaraSauce();
	}
	public Cheese createCheese() {
		return new ReggianoCheese();
	}
	//这里我们可以写的更好点,先用这个简单做法好了
	public Veggies[] createVeggies() {
		Veggies veggies[] = { new Garlic(), new Onion(), new Mushroom(), new RedPepper() };
		return veggies;
	}
	public Pepperoni createPepperoni() {
		return new SlicedPepperoni();//这是切片的意式腊肠
	}
	public Clams createClam() {
		return new FreshClams();//新鲜的蛤俐
	}
}
//工厂已经就绪,我们来重做披萨
public abstract class Pizza {
	//每个披萨都持有一组在准备时会用到的原料
	String name;
	Dough dough;
	Sauce sauce;
	Veggies veggies[];
	Cheese cheese;
	Pepperoni pepperoni;
	Clams clam;
	//现在把prepare声明成抽象,在这个方法中我们需要收集披萨所需的原料,而这些原料当然来自原料工厂了
	abstract void prepare();
	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");
	}
	void setName(String name) {
		this.name = name;
	}
	String getName() {
		return name;
	}
	public String toString() {}
}
//现在已经有了一个抽象披萨,可以开始创建纽约和芝加哥风味的披萨了,从今以后,加盟店必须直接从工厂取得原料,下面是CheesePizza:
public class CheesePizza extends Pizza {
	PizzaIngredientFactory ingredientFactory;
	//要制作披萨,需要工厂提供原料,所以每个披萨类都需要从构造器参数中得到一个工厂,并把这个工厂存放在一个实例变量中
	public CheesePizza(PizzaIngredientFactory ingredientFactory) {
		this.ingredientFactory = ingredientFactory;
	}
	//神奇的事情发生在这里,每当需要原料时,就跟工厂要
	void prepare() {
		System.out.println("Preparing " + name);
		dough = ingredientFactory.createDough();
		sauce = ingredientFactory.createSauce();
		cheese = ingredientFactory.createCheese();
	}
}
//再来看看蛤俐披萨
public class ClamPizza extends Pizza {
	PizzaIngredientFactory ingredientFactory;
	//原料工厂
	public ClamPizza(PizzaIngredientFactory ingredientFactory) {
		this.ingredientFactory = ingredientFactory;
	}
	//要做出蛤俐披萨,prepare方法就必须从本地工厂取得正确的原料
	void prepare() {
		System.out.println("Preparing " + name);
		dough = ingredientFactory.createDough();
		sauce = ingredientFactory.createSauce();
		cheese = ingredientFactory.createCheese();
		clam = ingredientFactory.createClam();
	}
}
//我们快完工了,再到加盟店短暂巡视一下,确认他们使用了正确的披萨,也需要让他们能和本地的原料工厂搭上线
public class NYPizzaStore extends PizzaStore {
	protected Pizza createPizza(String item) {
		Pizza pizza = null;
		//纽约店由纽约披萨原料工厂负责生产所有纽约风味披萨所需的原料
		PizzaIngredientFactory ingredientFactory = 
			new NYPizzaIngredientFactory();
		//对于每一种披萨,我们实例化一个新的披萨,并传进该种披萨所需的工厂
		if (item.equals("cheese")) {
			//把工厂传递给每个披萨,以便披萨能从工厂中取得原料
			pizza = new CheesePizza(ingredientFactory);
			pizza.setName("New York Style Cheese Pizza");
  
		} else if (item.equals("veggie")) {
			pizza = new VeggiePizza(ingredientFactory);
			pizza.setName("New York Style Veggie Pizza");
 
		} else if (item.equals("clam")) {
			pizza = new ClamPizza(ingredientFactory);
			pizza.setName("New York Style Clam Pizza");
 
		} else if (item.equals("pepperoni")) {
			pizza = new PepperoniPizza(ingredientFactory);
			pizza.setName("New York Style Pepperoni Pizza");
 
		} 
		return pizza;
	}
}

 

一连串的代码改变,我们到底做了什么?我们引入了新的抽象工厂来创建原料家族.通过抽象工厂提供的接口书写代码,我们的代码将从实际工厂解耦,以便在不同上下文中实现各式各样的工厂,制作出各种不同的产品.
我们又在设计模式家族中新增了抽象工厂模式.抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类.
工厂方法和抽象工厂有什么区别呢?
   
最后更新时间:2008-03-08
呵呵,我这几天也在看HEAD FIRST的DESIGN PATTERN这本书。浅显易懂,生动有趣,可读性很强:)

不过在介绍SINGLETON模式的时候,这本书里漏了一个技术问题:书中在介绍多线程环境下的高性能(减少线程同步的开销)SINGLETON的时候,使用了double-checked locking。
事实上,对于java而言这是不合适的,好像是因为java的内存模型支持无序写造成的吧。
   
0 请登录后投票
论坛首页 Java版 设计模式

跳转论坛:
JavaEye推荐