当看到new时,就会想到具体这个词。java
是的,当使用new时,确实是在实例化一个具体累,因此用的确实是实现,而不是接口。针对接口编程,能够隔离掉之后系统可能发生的一大堆改变。由于若是代码是针对接口编写的,那么经过多态,可使用任何接口的实现类。编程
除了使用new操做符以外,还有更多制造对象的方法。实例化这个活动不该该老是公开地进行。设计模式
假设有一个披萨店,须要一个披萨管理系统。ide
咱们决定使用面向对象的方式来实现这个系统,通过分析后,代码可能会这么写:函数
/** * 这里一个披萨店的实现类。 * */ public class PizzaStore { /** * 订购披萨的方法,返回一个披萨饼对象。 * */ public Pizza orderPizza() { // 建立一个披萨饼对象。 Pizza pizza = new Pizza("披萨饼"); return pizza; } }
作法是定义一个Pizza类,有一个name字段,重写toString()方法。测试
接着编写一个PizzaStore类,该类有一个orderPizza()方法,用于订购披萨。this
最后编写main函数进行测试。spa
通过一段时间后,披萨店有了更多种类的披萨饼,简单的一个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方法,经过类型来决定建立具体的披萨:code
/** * 这里一个披萨店的实现类。 * */ 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类,并设计称一个具体类。这样一来,就能够被工厂建立,并返回给客户。
到这里简单工厂的介绍就差很少了,多谢它为咱们暖身。接下来登场的是两个重量级的模式,它们都是工厂。