Java设计模式:工厂(Factory)模式
1.问题分析
-
首先,给出一个不够合理的披萨店设计
public class OldStore { Pizza orderPizza(){ Pizza pizza = new Pizza(); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
-
如果我们需要更多不同种类的pizza,那么我们就要增加代码来确定pizza的类型,然后才能制造pizza,那么,披萨店的设计代码就可能变成下面这样:
public class OldStore { Pizza orderPizza(String type){ Pizza pizza = new Pizza(); //-----不停变化的部分----- if(type.equals("cheese")){ pizza = new ChessePizza(); } else if (type.equals(”greek”)) { pizza = new GreekPizza(); } else if (type.equals(”other”)) { //other type } //---------------------- pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
我们可以发现,如果要增加不同的种类,那么,我们就必须去修改oderPizza()方法里的代码,这样,oderPizza()无法对修改关闭,所以我们需要进一步使用封装。下面给出三种类型的工厂模式。
2.简单工厂
-
如果需要让oderPizza()方法对修改关闭,我们应该如何设计呢?那便是将不停变化的部分,即确定披萨类型的部分抽离出来,放到另一个类里,如SimplePizzaFactory,OldStore类只需要负责从SimplePizzaFactory里获取披萨,然后进行后续操作即可。
public class SimplePizzaFactroy { public Pizza createPizza(String type) { Pizza pizza = null; if (type.equals(”cheese”)) { pizza = new CheesePizza(); } else if (type.equals(”greek”)) { pizza = new GreekPizza(); } else if (type.equals(”other”)) { // other type. } return pizza; } }
-
对应的,将OldStore重做为PizzaStore类,代码如下:
public class PizzaStore { SimplePizzaFactory factory; //加入一个对SimplePizzaFactory的引用 //构造需要一个工厂作为参数 public PizzaStore(SimplePizzaFactory factory) { this.factory = factory; } public Pizza orderPizza(String type) { Pizza pizza; //该方法通过简单传入订单类型来使用工厂创建披萨 pizza = factory.createPizza(type); // new操作符被换为工厂对象创建方法 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
3.工厂方法
-
加盟披萨店 要求披萨店的各个加盟店能够提供不同风味的披萨,并复用代码,以使得披萨的 流程能够一致不变。利用 SimplePizzaFactory 的一般实现如下:
即以SimplePizzaFactory为父类,派生不同的工厂类。当我们希望能够建立一个框架,把加盟店和创建披萨捆绑在一起,保持披萨的质量控制,同时使得代码具有一定的弹性。我们应该怎么做呢?NYPizzaFactory nyFactory = new NYPizzaFactory(); PizzaStore nyStore = new PizzaStore(nyFactory); nyStore.orderPizza(”Veggie”) ; ChicagoPizzaFactory chicagoFactory = new ChicagoPizzaFactory(); PizzaStore nyStore = new PizzaStore(chicagoFactory); nyStore.orderPizza(”Veggie”) ;
-
给披萨店使用的框架采用如下框架可以使得披萨制作活动局限于 PizzaStore 类,而同时又能 让这些加盟店依然可以自由的制作该区域的风味。
public abstract class PizzaStore { public Pizza OrderPizza(String type) { Pizza pizza; // createPizza()方法从工厂对象中回到PizzaStore pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } // PizzaStore里的工厂方法是抽象的 abstract Pizza createPizza(String type); }
我们可以看到,我们将原本放在工厂中实现的创建pizza操作,放回到了PizzaStore里,我们现在只需要以PizzaStore为父类,让每个区域的不同pizza店继承,各自实现createPizza()方法就行。createPizza() 方法是个抽象方法,所有任何具体的加盟店必须实现这个方法,从而个性化加盟 店的披萨风味。例如,NYPPizzaStore的实现。
public class NYPizzaStore extends PizzaStore { @Override Pizza createPizza(String type) { if (type.equals(”cheese”)) { return new NYStyleCheesePizza(); } else if (type.equals(”veggie”)) { return new NYStyleVeggiePizza(); } else if (type.equals(”other”)) { // other type. } else return null; } }
- 原来是在简单工厂中是由一个对象负责所有具体类的实例化,现在通过对 PizzaStore 作改变,使得由一群子类来负责实例化。 工厂方法用来处理对象的创建,并将这样的行为封装在子类中,这样客户程序中关于超类的 代码就和子类对象创建代码解耦。
- 工厂方法是抽象
- 工厂方法必须返回一个产品,超类中定义的方法,通常会用到工厂方法的返回值
-
工厂方法将客户(即超类中的代码,如 orderPizza())和实际创建具体产品的代码分隔开。
4.抽象工厂
-
工厂方法模式从设计角度考虑存在一定的问题:类的创建依赖工厂类。也就是说,如果想要 拓展程序,必须对工厂类进行修改,这违背了闭包原则。 所以,可以使用抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的 工厂类就可以了,不需要修改之前的代码。参考示例的4.3类图,该示例包含一个消息发送者接口 (Sender) 和一个抽象工厂接口(Provider)。
相关代码如下:
File: Sender.java
package ouc.cs.course.java.test.abstractfactory; public interface Sender { public void Send(); }
File: Provider.java
package ouc.cs.course.java.test.abstractfactory; public interface Provider { public Sender produce(); }
File: MailSender.java
package ouc.cs.course.java.test.abstractfactory; public class MailSender implements Sender { public void Send() { System.out.println(”this is mailsender!”); } }
File: SmsSender.java
package ouc.cs.course.java.test.abstractfactory; public class SmsSender implements Sender { public void Send() { System.out.println(”this is smssender!”); } }
File: SendMailFactory.java
package ouc.cs.course.java.test.abstractfactory; public class SendMailFactory implements Provider { @Override public Sender produce() { return new MailSender(); } }
File: SendSmsFactory.java
package ouc.cs.course.java.test.abstractfactory; public class SendSmsFactory implements Provider { @Override public Sender produce() { return new SmsSender(); } }
File: Test.java
package test.abstractfactory; import ouc.cs.course.java.test.abstractfactory.Provider; import ouc.cs.course.java.test.abstractfactory.SendMailFactory; import ouc.cs.course.java.test.abstractfactory.Sender; public class Test { public static void main(String[] args) { Provider provider = new SendMailFactory(); Sender sender = provider.produce(); sender.Send(); } }
当你想要扩展产品种类时,只需要增加对应的工厂类和产品类即可,比如我要增加一个QQSender类,只需要新建一个QQSender类实现Sender接口和SendQQFactory类实现Provider接口即可扩展产品种类。