HeadFirst设计模式(四) - 工厂模式之2 - 工厂方法

加盟披萨店

    之前基于简单工厂的披萨店系统运行良好,那么继续进行拓展。

    由于披萨店经营有成,以至于大家都希望自家附近有加盟店出现,身为加盟公司的经营者,也就是PizzaStore对象,自然希望确保加盟店运行的质量,所以希望这些店都使用PizzaStore中经过时间考验的代码。

但是区域的差异不能视而不见,由于加盟店的地理位置不同(比方说纽约店、芝加哥店、加州店),所使用的披萨也不同。

我们已经有一个做法

    利用SimplePizzaFactory,修改它,写出三种不同的工厂,分别是NYPizzaFactory、ChicagoPizzaFactory、CaliforniaPizzaFactory,那么各地加盟店都有合适的工厂可以使用,这是一种做法。

但是你想要多一些的质量控制

    在推广SimpleFactory时,你发现加盟店的确是采用你的工厂创建比萨,但是其他部分,却开始采用他们自创的流程。烘烤的做法有些差异、不要切片、使用其他厂商的盒子等等。

    换句话说,加盟店只使用了工厂创建Pizza对象,然后不去调用Pizza对象的prepare()、bake()、cut()、box()方法。

给披萨店使用框架

    有个做法可以让比萨制作活动局限于PizzaStore类,而同时又能让这些加盟店依然可以自由的只做该地区的披萨。

    所要做的事情就是把createPizza()方法放回到PizzaStore中,不过要把它设置称“抽象方法”,然后为每个区域风味创建一个PizzaStore的子类。

    首先,先看看如何修改PizzaStore类:

/**
 * 这里一个披萨店的抽象类。
 * */
public abstract class PizzaStore {
	
	/**
	 * 订购披萨的方法,返回一个披萨饼对象。
	 * */
	public Pizza orderPizza(String type) {
		// 通过披萨工厂创建披萨。
		Pizza pizza = createPizza(type);
		
		// 擀面上料、烘烤、切片、装盒。
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		
		return pizza;
	}
	
	/**
	 * 根据披萨类型创建指定的披萨对象。
	 * */
	abstract Pizza createPizza(String type);
}

     现在已经有一个PizzaStore作为超类,让每个地区的加盟店都创建一个PizzaStore子类(NYPizzaStore、ChicagoPizzaStore、CaliforniaPizzaStore),每个子类各自决定如何制造披萨。让我们看看这要如何进行。

允许子类做决定

    各个区域比萨店之间的差异在于它们制作比萨时的习惯(纽约比萨的饼薄,芝加哥比萨的饼厚等),我们现在让createPizza()能够应对这些变化。

    做法如上图所示,让PizzaStore的子类负责定义自己的createPizza()方法,所以我们会得到一些PizzaStore具体的子类,每个子类都有自己的比萨实体生成方式,而仍然适合PizzaStore框架,饼使用已经写好的orderPizza方法()。下面看用代码如何实现:

public class NYStylePizzaStore extends PizzaStore {

	@Override
	Pizza createPizza(String type) {
		Pizza pizza;
		// 通过类型返回指定的披萨,但这些披萨都是纽约风味的。
		if ("cheese".equals(type)) {
			pizza = new NYStyleCheesePizza();
		} else if ("pepperoni".equals(type)) {
			pizza = new NYStylePepperoniPizza();
		} else if ("clam".equals(type)) {
			pizza = new NYStyleClamPizza();
		} else if ("veggie".equals(type)) {
			pizza = new NYStyleVeggiePizza();
		} else {
			return null;
		}

		return pizza;
	}

}
public class ChicagoStylePizzaFactory extends PizzaStore {

	@Override
	Pizza createPizza(String type) {
		Pizza pizza;
		// 通过类型返回指定的披萨,但这些披萨都是芝加哥风味的。
		if ("cheese".equals(type)) {
			pizza = new ChicagoStyleCheesePizza();
		} else if ("pepperoni".equals(type)) {
			pizza = new ChicagoStylePepperoniPizza();
		} else if ("clam".equals(type)) {
			pizza = new ChicagoStyleClamPizza();
		} else if ("veggie".equals(type)) {
			pizza = new ChicagoStyleVeggiePizza();
		} else {
			return null;
		}

		return pizza;
	}

}

声明一个工厂方法

    原本是一个对象负责所有具体类的实例化,现在通过对PizzaStore做一些小转变,变成由一群子类来负责实例化。让我们看的更仔细些:

PizzaStore nyStylePizzaStore = new NYStylePizzaStore();

1.建立一个NYStylePizzaStore的实例;

Pizza nyPizza = nyStylePizzaStore.orderPizza("veggie");

2.调用NYStylePizzaStore实例的orderPizza()方法,传递参数veggie,是告诉纽约披萨店我需要一个素食披萨(当然是纽约风格的素食比萨)。

Pizza pizza = createPizza(type);

3.orderPizza()方法去调用工厂方法——createPizza(),并将type传递给它。他返回一个纽约风格的素质比萨。

pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();

4.披萨店对比萨进行处理,返回给客户。不管那个地区的披萨店,都要进行这些处理,没有特别的,这样,之前所说的不进行切片,使用其他披萨店的盒子的问题就解决了!

认识工厂方法的时刻终于到来了

    所有工厂模式都用来封装对象的创建,工厂方法模式(Factory Method Pattern)通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。

    工厂方法模式能够封装具体类型的实例化。看看下面的类图:

对于简单工厂与工厂方法的差异

    他们看起来很类似,差别在于,在工厂方法中,返回比萨的类是子类(实现了PizzaStore的类)。具体解释一下,子类的确看起来像是一个简单工厂。

    差别在于简单工厂会把全部的事情都做好,在一个地方都处理完了。然而工厂方法却是创建一个框架,让子类决定要如何实现。比方说,在工厂方法中,orderPizza()方法提供了一般的框架,以便创建比萨,orderPizza()方法一来工厂方法创建的具体类,饼制造出实际的比萨。可通过继承PizzaStore类,决定实际制造出的披萨是什么。

    而简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

依赖倒置原则

    有一个OO设计原则就正式阐明了这一点:这个原则甚至还有一个又响亮又正式的名称:“依赖倒置原则”(Dependency Inversion Principle)。

    3通则如下:

设计原则

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

    下面的方针,能帮你避免在OO设计中违反依赖倒置原则:

  • 变量不可以持有具体类的引用;
  • 不要让类派生自具体类;
  • 不要覆盖基类中已实现的方法;

    但是,完全遵守这些似乎也不太可能,正如同许多原则一样,应该尽量去达到这个原则,而不是随时都要遵循这个原则。

    以上便是工厂方法的一些知识。

转载于:https://my.oschina.net/u/2450666/blog/685088

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值