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

加盟披萨店

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

    因为披萨店经营有成,以致于你们都但愿自家附近有加盟店出现,身为加盟公司的经营者,也就是PizzaStore对象,天然但愿确保加盟店运行的质量,因此但愿这些店都使用PizzaStore中通过时间考验的代码。框架

可是区域的差别不能视而不见,因为加盟店的地理位置不一样(比方说纽约店、芝加哥店、加州店),所使用的披萨也不一样。ide

咱们已经有一个作法

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

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

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

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

给披萨店使用框架

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

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

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

/**
 * 这里一个披萨店的抽象类。
 * */
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),每一个子类各自决定如何制造披萨。让咱们看看这要如何进行。ci

容许子类作决定

    各个区域比萨店之间的差别在于它们制做比萨时的习惯(纽约比萨的饼薄,芝加哥比萨的饼厚等),咱们如今让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设计中违反依赖倒置原则:

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

    可是,彻底遵照这些彷佛也不太可能,正如同许多原则同样,应该尽可能去达到这个原则,而不是随时都要遵循这个原则。

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

相关文章
相关标签/搜索