zoukankan      html  css  js  c++  java
  • 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客户端时,通过工厂构建报文中格式化数据的对象。

  • 相关阅读:
    Mybatis Plus3.4.0打印SQL至控制台
    234 saltstack安装配置与使用
    CentOS7.9二进制方式安装mysql5.7
    查锁杀锁
    Oracle搭建DG
    MySQL 恢复
    数据库克隆(克隆的主机只需要安装软件不需要安装实例)
    MySQL单表恢复
    Properties实现文件存储
    大易之磁盘操作
  • 原文地址:https://www.cnblogs.com/mmzs/p/7753636.html
Copyright © 2011-2022 走看看