《Head First设计模式》读书笔记 -- (第四章)工厂模式

本章要点:

1.所有的工厂都是用来封装对象的创建。

2.简单工厂,虽然不是真正的设计模式,但仍不失为一个简单的方法,可以将客户程序从具体类解耦。

3.工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象。

4.抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中。

5.所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。

6.工厂方法允许类将实例化延迟到子类进行。

7.抽象工厂创建相关的对象家族,而不需要依赖它们的具体类。

8.依赖倒置原则,指导我们避免依赖具体类型,而要尽量依赖抽象。

9.工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。


----------------------------------------分割线 ----------------------------------------

简单工厂,简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。


现在有一个披萨店超类PizzaStore,其中有一个订披萨的方法orderPizza(),如果你选择用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;
	}
很明显,如果实例化某些具体类,会有很多问题。如果要加入新的披萨类型,或删除掉卖的不好的披萨类型,那么你就必须修改超类PizzaStore,这与我们第一个原则不符,我们必须对修改关闭。现在我们已经知道哪些会改变,哪些不会改变,该是使用封装的时候了。我们把改变的部分搬到另一个对象中,这个新对象只管如何创建披萨,我们称这个新对象为“工厂”。

建立一个简单披萨工厂

//这个简单工厂只做一件事情:帮客户创建披萨
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;
	}
}
重做PizzaStore
public class PizzaStore {
	//为PizzaStore加上一个对SimplePizzaFactory的引用
	SimplePizzaFactory factory;
	//PizzaStore的构造器,需要一个工厂作为参数
	public PizzaStore(SimplePizzaFactory factory) {
		this.factory = factory;
	}
	
	public Pizza orderPizza(String type){
		Pizza pizza;
		//使用工厂创建披萨,把new替换成工厂对象的创建方法,不再使用具体实例化
		pizza = factory.createPizza(type);
		
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}
}


定义工厂方法模式
 工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。


现在我们继续,来扩展一下业务。现在我们的披萨店(PizzaStore)经营有成,有很多加盟店。如果利用SimplePizzaFactory,写出三种不同的工厂,那么各地加盟店都有何时的工厂可以使用,这是一种做法。但是你发现加盟店的确是采用你的工厂创建披萨,但是其他部分,他们希望有自己的特点。我们希望能够建立一个框架,把加盟店和创建披萨捆绑在一起的同事又保持一定的

声明一个工厂方法,原本是由一个对象负责所有具体类的实例化,现在通过PizzaStore做一些小转变,变成由一群子类来负责实例化

public abstract class PizzaStore {
	//PizzaStore的子类在createPizza()中处理对象的实例化
	public Pizza orderPizza(String type){
		Pizza pizza;
		
		pizza = createPizza(type);
		
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		return pizza;
	}
	//现在,实例化的责任被移到一个方法中,此方法就如同是一个工厂
	protected abstract Pizza createPizza(String type);
}

披萨加盟店

public class NYPizzaStore extends PizzaStore {
	//返回一个Pizza对象,由子类负责实例化哪一个具体Pizza
	protected Pizza createPizza(String type) {
		if(type.equals("cheese")){
			return new NYStylePizza();
		} else if(type.equals("pepperoni")){
			return null;
		} else if(type.equals("clam")){
			return null;
		} else if(type.equals("veggie")){
			return null;
		}
		return null;
	}
}

实现披萨本身
//从一个抽象披萨开始,所有的具体披萨都必须派生自这个类
public abstract class Pizza {
	//每个披萨都具有名称等属性
	String name;
	String dough;
	String sauce;
	List<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 class NYStylePizza extends Pizza {
	public NYStylePizza() {
		name = "NY Style Sauce and Cheese Pizza";
		dough = "Thin Crust Dough";
		sauce = "Marinara Sauce";
		toppings.add("Grated Reggiano Cheese");
	}
}

public class ChicagoStylePizza extends Pizza {
	public ChicagoStylePizza() {
		name = "Chicago Style Deep Dish and Cheese Pizza";
		dough = "Extra Thick Crust Dough";
		sauce = "Plum Tomato Sauce";
		toppings.add("Shredded Mozzarella Cheese");
	}
	void cut(){
		System.out.println("Cutting the pizza into square slices");
	}
}
现在来测试一下
public class App {
	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");
	}
}
定义抽象工厂模式
 抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的具体产品是什么。这样一来, 客户就从具体的产品中被解耦。


继续扩展,现在我们要建造一个工厂来生产原料,这个工厂将负责创建原料家族中的每一种原料。



开始先为工厂定义一个接口,这个接口负责创建所有的原料
public interface PizzaIngredientFactory {
	//每个原料都一个对应的方法创建该原料
	public Dough createDough();
	public Sauce createSauce();
	public Cheese createCheese();
	public Veggies[] createVeggies();
	public Pepperoni createPepperoni();
	public Clams createClams();
}
创建各地原料工厂
//具体原料工厂必须实现这个接口
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 = {};
		return veggies;
	}
	public Pepperoni createPepperoni() {
		return new SlicedPepperoni();
	}
	public Clams createClams() {
		return new FreshClams();
	}
}
重做披萨
//从一个抽象披萨开始,所有的具体披萨都必须派生自这个类
public abstract class Pizza {
	//每个披萨都持有一组在准备时会用到的原料
	String name;
	Dough dough;
	Sauce sauce;
	Veggies[] veggies;
	Cheese cheese;
	Pepperoni pepperoni;
	Clams clams;
	//现在把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");
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}
继续重做披萨
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;
	}
	void prepare() {
		System.out.println("Preparing " + name);
		dough = ingredientFactory.createDough();
		sauce = ingredientFactory.createSauce();
		cheese = ingredientFactory.createCheese();
		clams = ingredientFactory.createClams();
	}
}
回到披萨店
public class NYPizzaStore extends PizzaStore {
	protected Pizza createPizza(String type) {
		Pizza pizza = null;
		//纽约店会用到纽约披萨原料工厂
		PizzaIngredientFactory ingredientFactory = new NYPizzaIngredientFactory();
		if(type.equals("cheese")){
			//把工厂传递给每一个披萨,以便披萨能从工厂中取得原料
			pizza = new CheesePizza(ingredientFactory);
			pizza.setName("New York Style Cheese Pizza");
		} else if(type.equals("pepperoni")){
			pizza = new PepperoniPizza(ingredientFactory);
			pizza.setName("New York Style Pepperoni Pizza");
		} else if(type.equals("clam")){
			pizza = new ClamPizza(ingredientFactory);
			pizza.setName("New York Style Clam Pizza");
		} else if(type.equals("veggie")){
			pizza = new VeggiePizza(ingredientFactory);
			pizza.setName("New York Style Veggie Pizza");
		}
		return pizza;
	}
}
比较工厂方法和抽象工厂

-------------------------------------------------------------------------------------------------------

总结新的设计原则(依赖倒置原则):

 依赖抽象,不要依赖具体类。


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

抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值