简单工厂模式、工厂方法模式、抽象工厂模式
我们现在需要建一个能够制作披萨的程序,这里面有不同口味的披萨,同时还有披萨的所有步骤,这里给出了四个步骤(准备,烘烤,切割,打包)。
我们在不使用简单工厂模式的时候
package com.factory.simplefactory.pizzastore.pizza; /** * 披萨抽象类 */ public abstract class Pizza { /** * 披萨的名字 */ protected String name; /** * 准备原材料,不同的披萨需要准备的原材料是不一样的,这里最好做成抽象方法 */ public abstract void prepare(); /** * 烘烤 */ public void bake() { System.out.println(name + " baking"); } /** * 切割 */ public void cut() { System.out.println(name + " cutting"); } /** * 打包 */ public void box() { System.out.println(name + " boxing"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.factory.simplefactory.pizzastore.pizza; public class GreekPizza extends Pizza { @Override public void prepare() { System.out.println("给制作希腊披萨准备原材料"); } }
package com.factory.simplefactory.pizzastore.pizza; public class CheesePizza extends Pizza { @Override public void prepare() { System.out.println("给制作奶酪披萨准备原材料"); } }
package com.factory.simplefactory.pizzastore.order; import com.factory.simplefactory.pizzastore.pizza.CheesePizza; import com.factory.simplefactory.pizzastore.pizza.GreekPizza; import com.factory.simplefactory.pizzastore.pizza.Pizza; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class OrderPizza { //创建一个构造器 public OrderPizza() { Pizza pizza=null; String orderType="";//订购的披萨类型 do { orderType=getType(); if("greek".equals(orderType)){ pizza=new GreekPizza(); pizza.setName("希腊披萨"); }else if("cheese".equals(orderType)){ pizza=new CheesePizza(); pizza.setName("奶酪披萨"); }else { break; } //输出披萨的制作过程 pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); }while (true); } //获取客户希望订购的披萨种类 private String getType(){ try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入您想订购的披萨种类:"); String str = bufferedReader.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return e.toString(); } } }
package com.factory.simplefactory.pizzastore.order; /** * 相当于一个客户端,发出订购 */ public class PizzaStore { public static void main(String[] args) { new OrderPizza(); } }
运行结果:
请输入您想订购的披萨种类: greek 给制作希腊披萨准备原材料 希腊披萨 baking 希腊披萨 cutting 希腊披萨 boxing 请输入您想订购的披萨种类: cheese 给制作奶酪披萨准备原材料 奶酪披萨 baking 奶酪披萨 cutting 奶酪披萨 boxing 请输入您想订购的披萨种类: yyy 订购披萨失败!!! 程序运行结束
分析一下这种方法的缺点
假设我们订购pizza的店铺有很多(说白了,在实际项目中,订购pizza的这个功能有很多系统都在调用)当我们需要增加一种pizza的时候,就会出现OrderPizza1、OrderPizza2、OrderPizza3等等类都需要修改(好比是好些个订阅pizza的系统都要因为你增加了一款pizza而修改自己系统的代码),这在实际项目开发中肯定是不现实的。当然这种写法也有他的好处就是:便于理解,仅此而已。
改进方式:把创建Pizza对象封装到一个类中,这样我们有新的Pizza种类时,只需要修改该类就可以了,其他有创建到Pizza对象的代码就不需要修改了,这就是简单工厂模式。
简单工厂模式
- 简单工厂模式属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例,简单工厂模式是工厂模式家族中最简单实用的模式。
- 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为。
- 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式。
对上面的程序进行改进:
package com.factory.simplefactory.pizzastore.order; import com.factory.simplefactory.pizzastore.pizza.CheesePizza; import com.factory.simplefactory.pizzastore.pizza.GreekPizza; import com.factory.simplefactory.pizzastore.pizza.PepperPizza; import com.factory.simplefactory.pizzastore.pizza.Pizza; /** * 简单工厂类 */ public class SimpleFactory { //传入orderType,返回对应的Pizza public Pizza createPizza(String orderType) { Pizza pizza = null; System.out.println("使用简单工厂模式"); if ("greek".equals(orderType)) { pizza = new GreekPizza(); pizza.setName("希腊披萨"); } else if ("cheese".equals(orderType)) { pizza = new CheesePizza(); pizza.setName("奶酪披萨"); } else if("pepper".equals(orderType)){ pizza = new PepperPizza(); pizza.setName("胡椒披萨"); } return pizza; } }
package com.factory.simplefactory.pizzastore.order; import com.factory.simplefactory.pizzastore.pizza.CheesePizza; import com.factory.simplefactory.pizzastore.pizza.GreekPizza; import com.factory.simplefactory.pizzastore.pizza.Pizza; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class OrderPizza { SimpleFactory simpleFactory = null; Pizza pizza = null; //添加构造方法 public OrderPizza(SimpleFactory simpleFactory) { setFactory(simpleFactory); } public void setFactory(SimpleFactory simpleFactory){ this.simpleFactory = simpleFactory;//设置简单工厂对象 String orderType = "";//用户输入的 do { orderType = getType(); pizza = this.simpleFactory.createPizza(orderType); //输出披萨的制作过程 if (null != pizza) { pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); }else { System.out.println("订购披萨失败!!!"); break; } } while (true); } //获取客户希望订购的披萨种类 private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入您想订购的披萨种类:"); String str = bufferedReader.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return e.toString(); } } }
我们再添加一个胡椒pizza
package com.factory.simplefactory.pizzastore.pizza; public class PepperPizza extends Pizza { @Override public void prepare() { System.out.println("给制作胡椒披萨准备原材料"); } }
package com.factory.simplefactory.pizzastore.order; import javax.sound.midi.Soundbank; /** * 相当于一个客户端,发出订购 */ public class PizzaStore { public static void main(String[] args) { new OrderPizza(new SimpleFactory()); System.out.println("程序运行结束"); } }
运行结果:
请输入您想订购的披萨种类: greek 使用简单工厂模式 给制作希腊披萨准备原材料 希腊披萨 baking 希腊披萨 cutting 希腊披萨 boxing 请输入您想订购的披萨种类: pepper 使用简单工厂模式 给制作胡椒披萨准备原材料 胡椒披萨 baking 胡椒披萨 cutting 胡椒披萨 boxing 请输入您想订购的披萨种类: cheese 使用简单工厂模式 给制作奶酪披萨准备原材料 奶酪披萨 baking 奶酪披萨 cutting 奶酪披萨 boxing 请输入您想订购的披萨种类: yyy 使用简单工厂模式 订购披萨失败!!! 程序运行结束
简单工厂模式也叫做静态工厂模式。
当然也可以对上面的简单工厂模式换一种静态的方式来体现。
package com.factory.simplefactory.pizzastore.order; import com.factory.simplefactory.pizzastore.pizza.Pizza; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class OrderPizza2 { Pizza pizza = null; //添加构造方法 public OrderPizza2() { String orderType = "";//用户输入的 do { orderType = getType(); pizza = SimpleFactory.createPizza2(orderType); //输出披萨的制作过程 if (null != pizza) { pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); }else { System.out.println("订购披萨失败!!!"); break; } } while (true); } //获取客户希望订购的披萨种类 private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入您想订购的披萨种类:"); String str = bufferedReader.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return e.toString(); } } }
package com.factory.simplefactory.pizzastore.order; import com.factory.simplefactory.pizzastore.pizza.CheesePizza; import com.factory.simplefactory.pizzastore.pizza.GreekPizza; import com.factory.simplefactory.pizzastore.pizza.PepperPizza; import com.factory.simplefactory.pizzastore.pizza.Pizza; /** * 简单工厂类 */ public class SimpleFactory { //传入orderType,返回对应的Pizza public static Pizza createPizza2(String orderType) { Pizza pizza = null; System.out.println("使用简单工厂模式2"); if ("greek".equals(orderType)) { pizza = new GreekPizza(); pizza.setName("希腊披萨"); } else if ("cheese".equals(orderType)) { pizza = new CheesePizza(); pizza.setName("奶酪披萨"); } else if("pepper".equals(orderType)){ pizza = new PepperPizza(); pizza.setName("胡椒披萨"); } return pizza; } }
package com.factory.simplefactory.pizzastore.order; import javax.sound.midi.Soundbank; /** * 相当于一个客户端,发出订购 */ public class PizzaStore { // public static void main(String[] args) { // new OrderPizza(); // } public static void main(String[] args) { new OrderPizza2(); System.out.println("程序运行结束"); } }
运行结果:
请输入您想订购的披萨种类: greek 使用简单工厂模式2 给制作希腊披萨准备原材料 希腊披萨 baking 希腊披萨 cutting 希腊披萨 boxing 请输入您想订购的披萨种类: cheese 使用简单工厂模式2 给制作奶酪披萨准备原材料 奶酪披萨 baking 奶酪披萨 cutting 奶酪披萨 boxing 请输入您想订购的披萨种类: pepper 使用简单工厂模式2 给制作胡椒披萨准备原材料 胡椒披萨 baking 胡椒披萨 cutting 胡椒披萨 boxing 请输入您想订购的披萨种类: yyy 使用简单工厂模式2 订购披萨失败!!! 程序运行结束
工厂方法模式:
看一个新的需求:客户在点披萨的时,可以点不同口味的披萨,比如北京的奶酪pizza、北京的胡椒pizza或者是伦敦的奶酪pizza、路通的胡椒pizza。
思路1;
使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactory、LDPizzaSimpleFactory等等,从当前这个案例来说,也是可的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好。
思路2:
使用工厂方法模式。
工厂方法模式:
工厂方法模式介绍
工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
工厂方法模式:定义了一个创建对象的抽象方法,由于子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
package com.factory.factorymethod.pizzasotre; /** * 披萨抽象类 */ public abstract class Pizza { /** * 披萨的名字 */ protected String name; /** * 准备原材料,不同的披萨需要准备的原材料是不一样的,这里最好做成抽象方法 */ public abstract void prepare(); /** * 烘烤 */ public void bake() { System.out.println(name + " baking"); } /** * 切割 */ public void cut() { System.out.println(name + " cutting"); } /** * 打包 */ public void box() { System.out.println(name + " boxing"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.factory.factorymethod.pizzasotre; public class LDPepperPizza extends Pizza { @Override public void prepare() { setName("伦敦的胡椒pizza"); System.out.println("伦敦胡椒披萨准备"); } }
package com.factory.factorymethod.pizzasotre; public class LDCheesePizza extends Pizza { @Override public void prepare() { setName("伦敦的奶酪pizza"); System.out.println("伦敦奶酪披萨准备"); } }
package com.factory.factorymethod.pizzasotre; public class BJPepperPizza extends Pizza { @Override public void prepare() { setName("北京的胡椒pizza"); System.out.println("北京胡椒披萨准备"); } }
package com.factory.factorymethod.pizzasotre; public class BJCheesePizza extends Pizza { @Override public void prepare() { setName("北京的奶酪pizza"); System.out.println("北京奶酪披萨准备"); } }
package com.factory.factorymethod.order; import com.factory.factorymethod.pizzasotre.BJCheesePizza; import com.factory.factorymethod.pizzasotre.BJPepperPizza; import com.factory.factorymethod.pizzasotre.Pizza; public class BJOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza=null; if("cheese".equals(orderType)){ pizza=new BJCheesePizza(); }else if("pepper".equals(orderType)){ pizza=new BJPepperPizza(); } return pizza; } }
package com.factory.factorymethod.order; import com.factory.factorymethod.pizzasotre.*; public class LDOrderPizza extends OrderPizza { @Override Pizza createPizza(String orderType) { Pizza pizza=null; if("cheese".equals(orderType)){ pizza=new LDCheesePizza(); }else if("pepper".equals(orderType)){ pizza=new LDPepperPizza(); } return pizza; } }
package com.factory.factorymethod.order; public class PizzaStore { public static void main(String[] args) { //创建北京口味的各种pizza new BJOrderPizza(); //创建伦敦口味的各种pizza // new LDOrderPizza(); } }
运行结果;
请输入您想订购的披萨种类: cheese 北京奶酪披萨准备 北京的奶酪pizza baking 北京的奶酪pizza cutting 北京的奶酪pizza boxing 请输入您想订购的披萨种类: pepper 北京胡椒披萨准备 北京的胡椒pizza baking 北京的胡椒pizza cutting 北京的胡椒pizza boxing 请输入您想订购的披萨种类: greek 订购披萨失败!!!
抽象工厂模式 基本介绍 1)抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类。 2)抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。 3)从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者成为进一步的抽象)。 4)将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,跟利于代码的维护和扩展。
在这个基础上,我们又新增了地址信息的分类,即有北京口味的pizza 和 伦敦口味的pizza。
package com.factory.absfactory.pizzastore.pizza; /** * 披萨抽象类 */ public abstract class Pizza { /** * 披萨的名字 */ protected String name; /** * 准备原材料,不同的披萨需要准备的原材料是不一样的,这里最好做成抽象方法 */ public abstract void prepare(); /** * 烘烤 */ public void bake() { System.out.println(name + " baking"); } /** * 切割 */ public void cut() { System.out.println(name + " cutting"); } /** * 打包 */ public void box() { System.out.println(name + " boxing"); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
package com.factory.absfactory.pizzastore.pizza; public class LDPepperPizza extends Pizza { @Override public void prepare() { setName("伦敦的胡椒pizza"); System.out.println("伦敦胡椒披萨准备"); } }
package com.factory.absfactory.pizzastore.pizza; public class LDCheesePizza extends Pizza { @Override public void prepare() { setName("伦敦的奶酪pizza"); System.out.println("伦敦奶酪披萨准备"); } }
package com.factory.absfactory.pizzastore.pizza; public class BJPepperPizza extends Pizza { @Override public void prepare() { setName("北京的胡椒pizza"); System.out.println("北京胡椒披萨准备"); } }
package com.factory.absfactory.pizzastore.pizza; public class BJCheesePizza extends Pizza { @Override public void prepare() { setName("北京的奶酪pizza"); System.out.println("北京奶酪披萨准备"); } }
package com.factory.absfactory.pizzastore.order; import com.factory.absfactory.pizzastore.pizza.Pizza; /** * 一个抽象工厂模式的抽象层 */ public interface AbsFactory { //让下面的工厂子类来具体实现 public Pizza createPizza(String orderType); }
package com.factory.absfactory.pizzastore.order; import com.factory.absfactory.pizzastore.pizza.BJCheesePizza; import com.factory.absfactory.pizzastore.pizza.BJPepperPizza; import com.factory.absfactory.pizzastore.pizza.Pizza; /** * 这是工厂类的子类 */ public class BJFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { System.out.println("使用的是抽象工厂模式"); Pizza pizza=null; if("cheese".equals(orderType)){ pizza=new BJCheesePizza(); }else if("pepper".equals(orderType)){ pizza=new BJPepperPizza(); } return pizza; } }
package com.factory.absfactory.pizzastore.order; import com.factory.absfactory.pizzastore.pizza.*; /** * 这是工厂类的子类 */ public class LDFactory implements AbsFactory { @Override public Pizza createPizza(String orderType) { System.out.println("使用的是抽象工厂模式"); Pizza pizza=null; if("cheese".equals(orderType)){ pizza=new LDCheesePizza(); }else if("pepper".equals(orderType)){ pizza=new LDPepperPizza(); } return pizza; } }
package com.factory.absfactory.pizzastore.order; import com.factory.absfactory.pizzastore.pizza.Pizza; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; /** * 订购pizza */ public class OrderPizza { AbsFactory factory=null; public OrderPizza(AbsFactory factory){ setFactory(factory); } private void setFactory(AbsFactory factory){ Pizza pizza=null; String orderType="";//用户输入 this.factory=factory; do { orderType=getType(); //factory 可能是北京的工厂子类,也可能是伦敦的工厂子类 pizza = factory.createPizza(orderType); if(null!=pizza){ pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); }else { System.out.println("订购失败"); break; } }while (true); } //获取客户希望订购的披萨种类 private String getType() { try { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入您想订购的披萨种类:"); String str = bufferedReader.readLine(); return str; } catch (IOException e) { e.printStackTrace(); return e.toString(); } } }
package com.factory.absfactory.pizzastore.order; public class PizzaStore { public static void main(String[] args) { new OrderPizza(new BJFactory()); //当然也可以穿伦敦工厂 } }
运行结果:
请输入您想订购的披萨种类: cheese 使用的是抽象工厂模式 北京奶酪披萨准备 北京的奶酪pizza baking 北京的奶酪pizza cutting 北京的奶酪pizza boxing 请输入您想订购的披萨种类: pepper 使用的是抽象工厂模式 北京胡椒披萨准备 北京的胡椒pizza baking 北京的胡椒pizza cutting 北京的胡椒pizza boxing 请输入您想订购的披萨种类: he 使用的是抽象工厂模式 订购失败
工厂模式小结;
1) 工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提供项目的扩展和维护性。
2) 三种工厂模式(简单工厂模式、工厂方法模式、抽象工厂模式)
3) 设计模式的依赖抽象原则
>创建对象实例时,不要直接new类,而是把这个new类的动作放在一个工厂的方法中,并返回。有的书上说,变量不要指直接持有具体类的引用。
>不要让类继承具体类,而是继承抽象类或者是实现interface(接口)
>不要覆盖基类中已经实现的方法。