欢迎来到我的博客小站。  交流请加我微信好友: studyjava。  也欢迎关注公众号:Java学习之道 Fork me on GitHub

23种设计模式之六(工厂模式)

工厂模式:(提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例)

 

一、工厂模式的意义

  把对象实例化的动作提取出来,和主项目的过程或者方法的依赖关系进行解耦,通过这种方式来使整个项目、工程能够有更好的扩展性和维护性。

  通俗的说:工厂模式就是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

例子:

披萨的制作;

不使用工厂模式,单纯的一般实现:

通过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 }
Pizza
 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 }
PepperPizza
 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 }
GreekPizza
 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 }
ChinesePizza
 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 }
CheesePizza
收到Pizza订单,
 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 }
OrderPizza

 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 }
PizzaStroe
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 }
SimplePizzaFactory
在OrderPizza中使用创建的SimplePizzaFactory对象调用CreatePizza判断需要制作的Pizza:
 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 }
OrderPizza

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 }
PizzaStroe

结果:

  方便了披萨品种的扩展、便于维护和运行时扩展。

  也可将简单工厂模式(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 }
LDCheesePizza
 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 }
LDPepperPizza
 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 }
NYCheesePizza
 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 }
NYPepperPizza

当披萨项目需要增加加盟店时,将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 }
OrderPizza
 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 }
LDOrderPizza
 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 }
NYOrderPizza

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 }
PizzaStroe
结果:
  将披萨项目里的披萨对象实例化功能抽象成抽象方法,在不同加盟店具体实现功能。 
       1)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。 
       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 }
AbsFactory

子类工厂:

 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 }
LDFactory
 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 }
NYFactory

在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 }
OrderPizza

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 }
PizzaStroe

结果:

  用不同的工厂创建不同的产品。

    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客户端时,通过工厂构建报文中格式化数据的对象。

posted @ 2017-10-30 13:33  淼淼之森  阅读(688)  评论(0编辑  收藏  举报
  👉转载请注明出处和署名