Head First设计模式四-----工厂模式

除了使用new操作符之外,还有更多制造对象的方法,比如使用工厂模式封装实例化的行为。工厂模式在辅助面向接口编程时很有作用,它用来封装对象的创建。

本章从简单工厂开始讲起,并逐步深入了解工厂方法(Factory Method)和抽象工厂模式(Abstract Factory),从严格意义上来说简单工厂并不是一个设计模式,但对理解后两者有帮助。以Pizza店为例子,贯穿整章,Pizza店生产各款各式的Pizza,有Clam、Veggie Pizza、Greek Pizza、Cheese Pizza


Pizza orderPizza(String type){
    Pizza pizza;
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();
    }
    
    pizza.prepare();
    pizza.bake();
    pizza.cut();
    pizza.box();
    pizza.pizza();
}

上述代码看似可以将具体实现与接口分离,但是有个新的问题是当要加入新的Pizza品种或移动时就得修改该代码,这违背了设计原则----Encapsulate what varies,我们得把创建Pizza这一块代码封装起来,于是乎有了简单工厂的出现

一、简单工厂:
package headfirst.factory.pizzas;

//简单工厂类
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;
	}
}

//Pizza店
package headfirst.factory.pizzas;

public class PizzaStore {
	SimplePizzaFactory factory;
 
	public PizzaStore(SimplePizzaFactory factory) { 
		this.factory = factory;
	}
 
	public Pizza orderPizza(String type) {     //订购Pizza
		Pizza pizza;
 
		pizza = factory.createPizza(type);//得到Pizza
 
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();

		return pizza;
	}

}


简单工厂类图:
Head First设计模式四-----工厂模式_第1张图片

基于以上实现可以满足生产不同的种类的Pizza,如Clam蛤蜊比萨)、Veggie Pizza(素食比萨)、Greek Pizza(希腊比萨)、Cheese Pizza(奶酪比萨),但是对于不同的地区,必然有地区口味的差别,如纽约和芝加哥口味,那我们就需要加多两个生产纽约和芝加哥口味的工厂,而不是用上述的简单工厂来生产,于是会出现像下面的代码

//纽约风味的VeggiePizza
NYPizzaFactory nyFactory = new NYPizzaFactory();
PizzaStore nyStore = new PizzaStore(nyFactory);
nyStore.order("Veggie");

//芝加哥风味的VeggiePizza
ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory ();
PizzaStore nyStore = new PizzaStore(chicagoFactory );
nyStore.order("Veggie");


新的问题又一次出现,PizzaStore提供了标准的Pizza制作过程,如准备、烘烤、切片、装箱,但是有些地方可能不切片,或是用他们自己的盒子装箱,那么这样的设计就不能满足了,它只提供了不能口味的生产,但是使用了统一的加工制作过程。为此,工厂方法Factory Method出现了

二、工厂方法模式(Factory Method)

package headfirst.factory.pizzafm;


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

package headfirst.factory.pizzafm;

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


//与实现了自己的工厂方法的各个工厂类对应的Pizza
package headfirst.factory.pizzafm;

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 headfirst.factory.pizzafm;

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



The Factory Method Pattern:定义了一个生产对象的接口,但由子类决定生产哪些实例对象

Pizza的工厂方法设计模式图
Head First设计模式四-----工厂模式_第2张图片

工厂方法设计模式图
Head First设计模式四-----工厂模式_第3张图片

设计原则:
Head First设计模式四-----工厂模式_第4张图片

Pizza总公司为了确保每家加盟店使用高质量的原料,打算建造多家生产原料的工厂,为每家分店提供的做比萨饼的原料。于是有

package headfirst.factory.pizzaaf;

//抽象工厂接口,定义了如何生产一组产品的方法
public interface PizzaIngredientFactory {
 
	public Dough createDough();
	public Sauce createSauce();
	public Cheese createCheese();
	public Veggies[] createVeggies();
	public Pepperoni createPepperoni();
	public Clams createClam();
 
}

//纽约Pizza店的原料加工厂
package headfirst.factory.pizzaaf;

//具体工厂
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();
	}
}

//
package headfirst.factory.pizzaaf;

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

//Pizza店
package headfirst.factory.pizzaaf;

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



三、抽象工厂模式(Abstract Factory)
定义:抽象工厂模式提供了一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类
上述例子中的原料加工厂用的就是抽象工厂的设计模式

抽象工厂模式类图
Head First设计模式四-----工厂模式_第5张图片

Pizza店例子的抽象工厂设计模式图
Head First设计模式四-----工厂模式_第6张图片
在上图中,ChicagoPizzaIngredidentFactory依赖于ThickCustDough、PlumTomatoSauce、Mozzarella Cheese、FrozenClams,而Pizza类只依赖于原料的接口Dough、Sauce、Cheese、Clams,这样当这些原料的具体类的改动时,只是影响到ChicagoPizzaIngredidentFactory,而Pizza类不会受影响,这很好的体现了设计原则:依赖倒置原则.
遵循下列指导方针可避免设计中的违反依赖倒置的原则
1、变量不可以持有具体类的引用
2、不要让类派生自具体类
3、不要覆盖基类中已实现的方法


总结:
工厂方法(Factory Method)VS抽象工厂(Abstract Factory)的比较
不同点:
1、工厂方法用于生产一个对象,而抽象工厂用于生成一组相关的对象
2、工厂方法的抽象基类已经使用了子类将要创建的具体对象,而抽象工厂只负责创建,具体创建的对象的使用由装配了该工厂的类决定。
相同点:
1、同样都是封装了对象的创建和保持应用程序的对具体实现的松散耦合

你可能感兴趣的:(设计模式,编程,制造)