HeadFirst设计模式(四) - 工厂模式之1 - 简单工厂

为什么要使用工厂?

    当看到new时,就会想到具体这个词。

    是的,当使用new时,确实是在实例化一个具体累,所以用的确实是实现,而不是接口。针对接口编程,可以隔离掉以后系统可能发生的一大堆改变。因为如果代码是针对接口编写的,那么通过多态,可以使用任何接口的实现类。

    除了使用new操作符之外,还有更多制造对象的方法。实例化这个活动不应该总是公开地进行。

使用一个披萨店的例子

假设有一个披萨店,需要一个披萨管理系统。

我们决定使用面向对象的方式来实现这个系统,经过分析后,代码可能会这么写:

/**
 * 这里一个披萨店的实现类。
 * */
public class PizzaStore {
	
	/**
	 * 订购披萨的方法,返回一个披萨饼对象。
	 * */
	public Pizza orderPizza() {
		// 创建一个披萨饼对象。
		Pizza pizza = new Pizza("披萨饼");
		return pizza;
	}
}

    做法是定义一个Pizza类,有一个name字段,重写toString()方法。

    接着编写一个PizzaStore类,该类有一个orderPizza()方法,用于订购披萨。

    最后编写main函数进行测试。

需要更多的披萨类型

    经过一段时间后,披萨店有了更多种类的披萨饼,简单的一个Pizza对象已经应付不来了。我们需要更多的披萨对象,为了让系统有弹性,我们把Pizza类定义为抽象的,让具体的披萨对象集成它。

/**
 * 披萨对象的抽象类,所有类型的披萨对象继承自该类。
 * */
public abstract class Pizza {
	
	public Pizza() { }

	public Pizza(String name) {
		this.name = name;
	}
	
	/**
	 * 对披萨进行前期处理。
	 * 擀面、加佐料等工艺。
	 * */
	public void prepare() {
		System.out.println(" ==> 对" + name + "进行前期处理...");
	}
	
	/**
	 * 烘培披萨。
	 * */
	public void bake() {
		System.out.println(" ==> 对" + name + "进行烘培处理...");
	}
	
	/**
	 * 切割披萨。
	 * */
	public void cut() {
		System.out.println(" ==> 对" + name + "进行切割处理...");
	}
	
	/**
	 * 包装处理。
	 * */
	public void box() {
		System.out.println(" ==> 对" + name + "进行包装处理...");
	}

	@Override
	public String toString() {
		return "披萨 [名称=" + name + "]";
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	private String name;
}
/**
 * 芝士披萨对象,继承自披萨抽象类。
 * */
public class CheesePizza extends Pizza { 
	public CheesePizza() {
		super.setName("芝士披萨");
	}
}

/**
 * 希腊披萨,继承自披萨抽象类。
 * */
public class GreekPizza extends Pizza { 
	public GreekPizza() {
		super.setName("希腊披萨");
	}
}


/**
 * 意大利香肠披萨,继承自披萨抽象类。
 * */
public class PepperoniPizza extends Pizza { 
	public PepperoniPizza() {
		super.setName("意大利香肠披萨");
	}
}

    我们有了具体的披萨类型,接着重写orderPizza方法,通过类型来决定创建具体的披萨:

/**
 * 这里一个披萨店的实现类。
 * */
public class PizzaStore {
	
	/**
	 * 订购披萨的方法,返回一个披萨饼对象。
	 * */
	public Pizza orderPizza(String type) {
		Pizza pizza;
		// 通过类型来确定返回哪种披萨。
		if("cheese".equals(type)) {
			pizza = new CheesePizza();
		} else if ("greek".equals(type)) {
			pizza = new GreekPizza();
		} else if ("pepperoni".equals(type)) {
			pizza = new PepperoniPizza();
		} else {
			return null;
		}
		
		// 擀面上料、烘培、切片、装盒。
		pizza.prepare();
		pizza.bake();
		pizza.cut();
		pizza.box();
		
		return pizza;
	}
}

     进行测试:

    通过披萨类型订购了两种不同的披萨,非常方便,但是……

压力来自于增加更多的披萨类型

    经过了一段时间,有出现了披萨新种类,比如海鲜蛤哩披萨和素食披萨等等,披萨店也学会了这些披萨的做法并要把它们加入到系统中。同时,希腊风味披萨卖得不太好,要将它从系统中移除。

    很明显,如果实例化“某些”具体类,每次都要去修改PizzaStore类源码,因为要修改orderPizza()方法中的语句。

    还有一点,这段创建披萨的代码放在了PizzaStore中的ordarPizza () 方法,与pizza的处理方法写到了一起。如果有一天披萨店的菜单对象也需要创建披萨,则需要拷贝orderPizza()方法中创建披萨的那段if-else代码到菜单对象。修改时就要修改两处,如果有20个地方用到了创建披萨的这段代码呢?

    是时候将创建披萨的代码封装起来了!

    我们需要将if-else的代码搬到另一个对象中,这个新对象只管如何创建披萨。如果任何对象想要创建披萨,找它就对了。我们称这个新对象为“工厂”(factory)。创建这个工厂,并修改现有代码:

    首先修改PizzaStore类中的orderPizza()方法,将new披萨的那段if-else代码从方法中移除:

    接下来创建新对象,披萨工厂:

/**
 * SimplePizzaFactory是披萨的工厂类,它只做一件事,就是创建披萨。
 */
public class SimplePizzaFactory {
	
	/**
	 * 通过类型来确定返回哪种披萨。
	 * */
	public static Pizza createPizza(String type) {
		Pizza pizza;
		// 通过类型来确定返回哪种披萨。
		if ("cheese".equals(type)) {
			pizza = new CheesePizza();
		} else if ("pepperoni".equals(type)) {
			pizza = new PepperoniPizza();
		} else if ("clam".equals(type)) {
			pizza = new ClamPizza();
		} else if ("veggie".equals(type)) {
			pizza = new VeggiePizza();
		} else {
			return null;
		}
		return pizza;
	}
}

    最后,在PizzaStore类的orderPizza()方法中,通过工厂来创建披萨:

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

    测试结果如下:


定义简单工厂

    简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。但由于经常被使用,所以也归纳到了工厂方法中。不要因为简单工厂不是一个“真正的”模式,就忽略了它的用法。让我们来看看现在披萨管理系统的类图:

    PizzaStore是工厂的“客户”。PizzaStore现在通过SimplePizzaFactory取得披萨实例。

    SimplePiazzaFactory是工厂方法,用来创建披萨。

    Pizza是“产品”的抽象类,每个具体产品必须拓展抽象的Pizza类,并设计称一个具体类。这样一来,就可以被工厂创建,并返回给客户。

    到这里简单工厂的介绍就差不多了,多谢它为我们暖身。接下来登场的是两个重量级的模式,它们都是工厂。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值