工厂模式:(提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例)
一、工厂模式的意义
把对象实例化的动作提取出来,和主项目的过程或者方法的依赖关系进行解耦,通过这种方式来使整个项目、工程能够有更好的扩展性和维护性。
通俗的说:工厂模式就是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
例子:
披萨的制作;
不使用工厂模式,单纯的一般实现:
通过Pizza接口实现Pizza族,
1 package com.java.mmzs.pizzastore.pizza; 2 3 public abstract class Pizza { 4 protected String name; 5 6 public abstract void prepare(); 7 public void bake() 8 { 9 System.out.println(name+" baking;"); 10 } 11 public void cut() 12 { 13 System.out.println(name+" cutting;"); 14 } 15 public void box() 16 { 17 System.out.println(name+" boxing;"); 18 } 19 public void setname(String name) 20 { 21 this.name=name; 22 } 23 }
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class PepperPizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("PepperPizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class GreekPizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("GreekPizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class ChinesePizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("ChinesePizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class CheesePizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("CheesePizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
1 package com.java.mmzs.pizzastore; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 7 import com.java.mmzs.pizzastore.pizza.CheesePizza; 8 import com.java.mmzs.pizzastore.pizza.ChinesePizza; 9 import com.java.mmzs.pizzastore.pizza.GreekPizza; 10 import com.java.mmzs.pizzastore.pizza.PepperPizza; 11 import com.java.mmzs.pizzastore.pizza.Pizza; 12 13 public class OrderPizza { 14 15 public OrderPizza() { 16 Pizza pizza = null; 17 String ordertype; 18 19 do { 20 ordertype = gettype(); 21 22 if (ordertype.equals("cheese")) { 23 pizza = new CheesePizza(); 24 } else if (ordertype.equals("greek")) { 25 pizza = new GreekPizza(); 26 } else if (ordertype.equals("pepper")) { 27 pizza = new PepperPizza(); 28 } else if (ordertype.equals("chinese")) { 29 pizza = new ChinesePizza(); 30 } else { 31 break; 32 } 33 pizza.prepare(); 34 pizza.bake(); 35 pizza.cut(); 36 pizza.box(); 37 } while (true); 38 } 39 40 private String gettype() { 41 try { 42 BufferedReader strin = new BufferedReader(new InputStreamReader( 43 System.in)); 44 System.out.println("input pizza type:"); 45 String str = strin.readLine(); 46 47 return str; 48 } catch (IOException e) { 49 e.printStackTrace(); 50 return ""; 51 } 52 } 53 54 }
Pizza商店出售。
1 package com.java.mmzs.pizzastore; 2 3 4 5 public class PizzaStroe { 6 public static void main(String[] args) { 7 8 OrderPizza mOrderPizza; 9 mOrderPizza=new OrderPizza(); 10 11 } 12 13 14 15 }
1 input pizza type: 2 cheese 3 CheesePizza preparing; 4 CheesePizza baking; 5 CheesePizza cutting; 6 CheesePizza boxing;
这种设计方式当Pizza的种类增加时,会改动OrderPizza中的代码,违背了开发的中“对扩展的开放,对修改的关闭”原则。
二、三种工厂模式
1.简单工厂模式(定义了一个创建对象的类,由这个类来封装实例化对象的行为)
将OrderPizza中的if…else…的逻辑判断部分封装到一个单独的类的方法中:
1 package com.java.mmzs.pizzastore.simplefactory; 2 3 import com.java.mmzs.pizzastore.pizza.CheesePizza; 4 import com.java.mmzs.pizzastore.pizza.GreekPizza; 5 import com.java.mmzs.pizzastore.pizza.PepperPizza; 6 import com.java.mmzs.pizzastore.pizza.Pizza; 7 8 public class SimplePizzaFactory { 9 10 public Pizza CreatePizza(String ordertype) { 11 Pizza pizza = null; 12 13 if (ordertype.equals("cheese")) { 14 pizza = new CheesePizza(); 15 } else if (ordertype.equals("greek")) { 16 pizza = new GreekPizza(); 17 } else if (ordertype.equals("pepper")) { 18 pizza = new PepperPizza(); 19 } 20 return pizza; 21 22 } 23 24 }
1 package com.java.mmzs.pizzastore.simplefactory; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 7 import com.java.mmzs.pizzastore.pizza.CheesePizza; 8 import com.java.mmzs.pizzastore.pizza.GreekPizza; 9 import com.java.mmzs.pizzastore.pizza.PepperPizza; 10 import com.java.mmzs.pizzastore.pizza.Pizza; 11 12 public class OrderPizza { 13 SimplePizzaFactory mSimplePizzaFactory; 14 15 public OrderPizza(SimplePizzaFactory mSimplePizzaFactory) { 16 17 setFactory(mSimplePizzaFactory); 18 } 19 20 public void setFactory(SimplePizzaFactory mSimplePizzaFactory) { 21 Pizza pizza = null; 22 String ordertype; 23 24 this.mSimplePizzaFactory = mSimplePizzaFactory; 25 26 do { 27 ordertype = gettype(); 28 pizza = mSimplePizzaFactory.CreatePizza(ordertype); 29 if (pizza != null) { 30 pizza.prepare(); 31 pizza.bake(); 32 pizza.cut(); 33 pizza.box(); 34 } 35 36 } while (true); 37 38 } 39 40 private String gettype() { 41 try { 42 BufferedReader strin = new BufferedReader(new InputStreamReader( 43 System.in)); 44 System.out.println("input pizza type:"); 45 String str = strin.readLine(); 46 47 return str; 48 } catch (IOException e) { 49 e.printStackTrace(); 50 return ""; 51 } 52 } 53 54 }
Pizza商店出售。
1 package com.java.mmzs.pizzastore.simplefactory; 2 3 4 5 public class PizzaStroe { 6 public static void main(String[] args) { 7 SimplePizzaFactory mSimplePizzaFactory; 8 OrderPizza mOrderPizza; 9 mOrderPizza=new OrderPizza(new SimplePizzaFactory()); 10 11 } 12 13 14 15 }
结果:
方便了披萨品种的扩展、便于维护和运行时扩展。
也可将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。
2.工厂方法模式(定义了一个创建对象的抽象方法,由子类决定要实例化的类。 工厂方法模式将对象的实例化推迟到子类)
不同地方的不同的Pizza,
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class LDCheesePizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("LDCheesePizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class LDPepperPizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("LDPepperPizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class NYCheesePizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("NYCheesePizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
1 package com.java.mmzs.pizzastore.pizza; 2 3 public class NYPepperPizza extends Pizza { 4 5 @Override 6 public void prepare() { 7 // TODO Auto-generated method stub 8 super.setname("NYPepperPizza"); 9 10 System.out.println(name+" preparing;"); 11 } 12 13 }
当披萨项目需要增加加盟店时,将OrderPizza设计为抽象类;然后不同的地方实现不同的创建方式createPizza();
1 package com.java.mmzs.pizzastore.method; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 7 import com.java.mmzs.pizzastore.pizza.CheesePizza; 8 import com.java.mmzs.pizzastore.pizza.ChinesePizza; 9 import com.java.mmzs.pizzastore.pizza.GreekPizza; 10 import com.java.mmzs.pizzastore.pizza.PepperPizza; 11 import com.java.mmzs.pizzastore.pizza.Pizza; 12 13 public abstract class OrderPizza { 14 15 public OrderPizza() { 16 Pizza pizza = null; 17 String ordertype; 18 19 do { 20 ordertype = gettype(); 21 pizza = createPizza(ordertype); 22 23 pizza.prepare(); 24 pizza.bake(); 25 pizza.cut(); 26 pizza.box(); 27 } while (true); 28 } 29 30 abstract Pizza createPizza(String ordertype); 31 32 private String gettype() { 33 try { 34 BufferedReader strin = new BufferedReader(new InputStreamReader( 35 System.in)); 36 System.out.println("input pizza type:"); 37 String str = strin.readLine(); 38 39 return str; 40 } catch (IOException e) { 41 e.printStackTrace(); 42 return ""; 43 } 44 } 45 46 }
1 package com.java.mmzs.pizzastore.method; 2 3 import com.java.mmzs.pizzastore.pizza.CheesePizza; 4 import com.java.mmzs.pizzastore.pizza.GreekPizza; 5 import com.java.mmzs.pizzastore.pizza.LDCheesePizza; 6 import com.java.mmzs.pizzastore.pizza.LDPepperPizza; 7 import com.java.mmzs.pizzastore.pizza.PepperPizza; 8 import com.java.mmzs.pizzastore.pizza.Pizza; 9 10 public class LDOrderPizza extends OrderPizza { 11 12 @Override 13 Pizza createPizza(String ordertype) { 14 Pizza pizza = null; 15 16 if (ordertype.equals("cheese")) { 17 pizza = new LDCheesePizza(); 18 } else if (ordertype.equals("pepper")) { 19 pizza = new LDPepperPizza(); 20 } 21 return pizza; 22 23 } 24 25 }
1 package com.java.mmzs.pizzastore.method; 2 3 import com.java.mmzs.pizzastore.pizza.CheesePizza; 4 import com.java.mmzs.pizzastore.pizza.GreekPizza; 5 import com.java.mmzs.pizzastore.pizza.NYCheesePizza; 6 import com.java.mmzs.pizzastore.pizza.NYPepperPizza; 7 import com.java.mmzs.pizzastore.pizza.PepperPizza; 8 import com.java.mmzs.pizzastore.pizza.Pizza; 9 10 public class NYOrderPizza extends OrderPizza { 11 12 @Override 13 Pizza createPizza(String ordertype) { 14 Pizza pizza = null; 15 16 if (ordertype.equals("cheese")) { 17 pizza = new NYCheesePizza(); 18 } else if (ordertype.equals("pepper")) { 19 pizza = new NYPepperPizza(); 20 } 21 return pizza; 22 23 } 24 25 }
Pizza商店出售。
1 package com.java.mmzs.pizzastore.method; 2 3 4 5 public class PizzaStroe { 6 public static void main(String[] args) { 7 8 OrderPizza mOrderPizza; 9 mOrderPizza=new NYOrderPizza();//直接构建对应地方的OrderPizza 10 11 } 12 13 }
2)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
3)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
3.抽象工厂模式(定义了一个接口用于创建相关或有依赖关系的对象族,而无需明确指定具体类)
抽象工厂:
1 package com.java.mmzs.pizzastore.absfactory; 2 3 import com.java.mmzs.pizzastore.pizza.Pizza; 4 5 public interface AbsFactory { 6 public Pizza CreatePizza(String ordertype) ; 7 }
子类工厂:
1 package com.java.mmzs.pizzastore.absfactory; 2 3 import com.java.mmzs.pizzastore.pizza.LDCheesePizza; 4 import com.java.mmzs.pizzastore.pizza.LDPepperPizza; 5 import com.java.mmzs.pizzastore.pizza.Pizza; 6 7 public class LDFactory implements AbsFactory { 8 9 @Override 10 public Pizza CreatePizza(String ordertype) { 11 Pizza pizza = null; 12 13 if (ordertype.equals("cheese")) { 14 pizza = new LDCheesePizza(); 15 } else if (ordertype.equals("pepper")) { 16 pizza = new LDPepperPizza(); 17 } 18 return pizza; 19 20 } 21 22 }
1 package com.java.mmzs.pizzastore.absfactory; 2 3 import com.java.mmzs.pizzastore.pizza.NYCheesePizza; 4 import com.java.mmzs.pizzastore.pizza.NYPepperPizza; 5 import com.java.mmzs.pizzastore.pizza.Pizza; 6 7 public class NYFactory implements AbsFactory { 8 9 10 @Override 11 public Pizza CreatePizza(String ordertype) { 12 Pizza pizza = null; 13 14 if (ordertype.equals("cheese")) { 15 pizza = new NYCheesePizza(); 16 } else if (ordertype.equals("pepper")) { 17 pizza = new NYPepperPizza(); 18 } 19 return pizza; 20 21 } 22 23 }
在OrderPizza类中定义AbsFactory属性,根据传递的不同的AbsFactory的子类来进行实例化,
1 package com.java.mmzs.pizzastore.method; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 7 import com.java.mmzs.pizzastore.pizza.CheesePizza; 8 import com.java.mmzs.pizzastore.pizza.ChinesePizza; 9 import com.java.mmzs.pizzastore.pizza.GreekPizza; 10 import com.java.mmzs.pizzastore.pizza.PepperPizza; 11 import com.java.mmzs.pizzastore.pizza.Pizza; 12 13 public abstract class OrderPizza { 14 15 public OrderPizza() { 16 Pizza pizza = null; 17 String ordertype; 18 19 do { 20 ordertype = gettype(); 21 pizza = createPizza(ordertype); 22 23 pizza.prepare(); 24 pizza.bake(); 25 pizza.cut(); 26 pizza.box(); 27 } while (true); 28 } 29 30 abstract Pizza createPizza(String ordertype); 31 32 private String gettype() { 33 try { 34 BufferedReader strin = new BufferedReader(new InputStreamReader( 35 System.in)); 36 System.out.println("input pizza type:"); 37 String str = strin.readLine(); 38 39 return str; 40 } catch (IOException e) { 41 e.printStackTrace(); 42 return ""; 43 } 44 } 45 46 }
Pizza商店出售时,需要传递工厂类型,来进行适宜当地口味特色的披萨。
1 package com.java.mmzs.pizzastore.method; 2 3 4 5 public class PizzaStroe { 6 public static void main(String[] args) { 7 8 OrderPizza mOrderPizza; 9 mOrderPizza=new NYOrderPizza();//直接构建对应地方的OrderPizza 10 11 } 12 13 14 15 }
结果:
用不同的工厂创建不同的产品。
1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。
2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。
3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。
4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。
三、依赖抽象原则
1)、变量不要持有具体类的引用 pizza=new CheesePizza(依赖关系比较强);而是等于某个创建对象方法的返回值;
2)、不要让类继承自具体类,要继承自抽象类或接口;
3)、不要覆盖基类中已实现的方法;
区别:
工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。
工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个(根据传递不同的工厂对象)。
优点:
1、可以一定程度上解耦,消费者和产品实现类隔离开,只依赖产品接口(抽象产品),产品实现类如何改动与消费者完全无关。
2、可以一定程度增加扩展性,若增加一个产品实现,只需要实现产品接口,修改工厂创建产品的方法,消费者可以无感知(若消费者不关心具体产品是什么的情况)。
3、可以一定程度增加代码的封装性、可读性。清楚的代码结构,对于消费者来说很少的代码量就可以完成很多工作。
等等……
另外,抽象工厂才是实际意义的工厂模式,工厂方法只是抽象工厂的一个比较常见的情况。
缺点:
1、简单工厂模式:因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。系统扩展困难,一旦添加新产品就不得不修改工厂逻辑(如果要增加一个产品,则需要修改工厂类,增加if/else分支,或者增加一个case分支),有可能造成工厂逻辑过于复杂,违背了"开放--封闭"原则(OCP).另外,简单工厂模式通常使用静态工厂方法,这使得无法由子类继承,造成工厂角色无法形成基于继承的等级结构。
2、工厂方法模式:不易于维护,假如某个具体产品类需要进行一定的修改,很可能需要修改对应的工厂类。当同时需要修改多个产品类的时候,对工厂类的修改会变得相当麻烦(对号入座已经是个问题了)。
3、抽象工厂模式:抽象工厂模式在于难于应付“新对象”的需求变动。难以支持新种类的产品。难以扩展抽象工厂以生产新种类的产品。这是因为抽象工厂几乎确定了可以被创建的产品集合,支持新种类的产品就需要扩展该工厂接口,这将涉及抽象工厂类及其所有子类的改变。
欢迎加群一起交流:603654340
应用场景:
消费者不关心它所要创建对象的类(产品类)的时候。
消费者知道它所要创建对象的类(产品类),但不关心如何创建的时候。
等等……
例如:hibernate里通过sessionFactory创建session、通过代理方式生成ws客户端时,通过工厂构建报文中格式化数据的对象。