【设计模式——学习笔记(上)】23种设计模式——工厂模式Factory(原理讲解+应用场景介绍+案例介绍+Java代码实现)

简介: 【设计模式——学习笔记】23种设计模式——工厂模式Factory(原理讲解+应用场景介绍+案例介绍+Java代码实现)

工厂模式

需求了解

看一个披萨的项目:要便于披萨种类的扩展,要便于维护

  • 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
  • 披萨的制作有 prepare(准备材料),bake(烘焙),cut(切割),box(打包)
  • 完成披萨店订购功能

传统方式实现

实体类
package com.atguigu.factory.tradition.pizza;
/**
 * 将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 void setName(String name) {
        this.name = name;
    }
}
package com.atguigu.factory.tradition.pizza;
public class CheesePizza extends Pizza {
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      System.out.println(" 准备CheesePizza ");
   }
}
package com.atguigu.factory.tradition.pizza;
public class GreekPizza extends Pizza {
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      System.out.println("准备GreekPizza");
   }
}
package com.atguigu.factory.tradition.pizza;
public class PepperPizza extends Pizza {
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      System.out.println("准备PepperPizza");
   }
}
package com.atguigu.factory.tradition.pizza;
public class PepperPizza extends Pizza {
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      System.out.println("准备PepperPizza");
   }
}
订购类
pac
package com.atguigu.factory.tradition.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.tradition.pizza.CheesePizza;
import com.atguigu.factory.tradition.pizza.GreekPizza;
import com.atguigu.factory.tradition.pizza.PepperPizza;
import com.atguigu.factory.tradition.pizza.Pizza;
public class OrderPizza {
   public OrderPizza() {
      Pizza pizza = null;
      String orderType; // 订购披萨的类型
      do {
         orderType = getType();
         if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName(" greek pizza ");
         } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName(" cheese pizza ");
         } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName(" pepper pizza ");
         } else {
            break;
         }
         //输出pizza 制作过程
         pizza.prepare();
         pizza.bake();
         pizza.cut();
         pizza.box();
      } while (true);
   }
   /**
    * 写一个方法,可以获取客户希望订购的披萨种类
    * @return
    */
   private String getType() {
      try {
         BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
         System.out.println("input pizza type:");
         String str = strin.readLine();
         return str;
      } catch (IOException e) {
         e.printStackTrace();
         return "";
      }
   }
}
客户端
package com.atguigu.factory.tradition.order;
//相当于一个客户端,发出订购
public class PizzaStore {
    public static void main(String[] args) {
        new OrderPizza();
    }
}
分析
  • 优点是比较好理解,简单易操作
  • 缺点是违反了设计模式的ocp原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码
  • 比如我们这时要新增加一个Pizza的种类(Cheese披萨),我们需要做如下修改

改进
  • 修改代码可以接受,但是如果我们在其它的地方也有创建Pizza的代码,就意味着,也需要修改,而创建pizza的代码,往往有多处
  • 把创建Pizza对象封装到一个类中,这样我们有新的Pizza种类时,只需要修改该类就可,其它有创建Pizza对象的代码就不需要修改了(简单工厂模式)

简单工厂模式

介绍
  • 简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
  • 简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
  • 在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式

实现
简单工厂模式

【工厂类】

package com.atguigu.factory.simplefactory.pizzastore.order;
import com.atguigu.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
//简单工厂类
public class SimpleFactory {
    /**
     * 根据orderType 返回对应的Pizza 对象
     *
     * @param orderType
     * @return
     */
    public Pizza createPizza(String orderType) {
        Pizza pizza = null;
        System.out.println("使用简单工厂模式");
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName(" 希腊披萨 ");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName(" 奶酪披萨 ");
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }
}

【订购类】

package com.atguigu.factory.simplefactory.pizzastore.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
public class OrderPizza {
    /**
     * 定义一个简单工厂对象,这里使用的是聚合关系,如果想换成组合关系的话,直接new就行
     */
    SimpleFactory simpleFactory;
    Pizza pizza = null;
    //构造器
    public OrderPizza(SimpleFactory simpleFactory) {
        setFactory(simpleFactory);
    }
    public void setFactory(SimpleFactory simpleFactory) {
        //用户需要预定什么pizza,用户输入
        String orderType = "";
        //设置简单工厂对象
        this.simpleFactory = simpleFactory;
        do {
            orderType = getType();
            pizza = this.simpleFactory.createPizza(orderType);
            //输出pizza
            if (pizza != null) {
                //--if--订购成功
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println(" 订购披萨失败 ");
                break;
            }
        } while (true);
    }
    /**
     * 写一个方法,可以获取客户希望订购的披萨种类
     *
     * @return
     */
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

【主类】

package com.atguigu.factory.simplefactory.pizzastore.order;
//相当于一个客户端,发出订购
public class PizzaStore {
   public static void main(String[] args) {
      //使用简单工厂模式
      new OrderPizza(new SimpleFactory());
      System.out.println("~~退出程序~~");
   }
}

【运行】

input pizza type:
greek
使用简单工厂模式
 给希腊披萨 准备原材料 
 希腊披萨  baking;
 希腊披萨  cutting;
 希腊披萨  boxing;
input pizza type:
cheese
使用简单工厂模式
 给制作奶酪披萨 准备原材料 
 奶酪披萨  baking;
 奶酪披萨  cutting;
 奶酪披萨  boxing;
input pizza type:
静态工厂模式(简单工厂模式的另外一种实现方式)

【工厂类】

package com.atguigu.factory.simplefactory.pizzastore.order;
import com.atguigu.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
//简单工厂类
public class SimpleFactory {
    /**
     * 简单工厂模式 也叫 静态工厂模式(使用静态方法)
     * @param orderType
     * @return
     */
    public static Pizza createPizza2(String orderType) {
        Pizza pizza = null;
        System.out.println("使用简单工厂模式2");
        if (orderType.equals("greek")) {
            pizza = new GreekPizza();
            pizza.setName(" 希腊披萨 ");
        } else if (orderType.equals("cheese")) {
            pizza = new CheesePizza();
            pizza.setName(" 奶酪披萨 ");
        } else if (orderType.equals("pepper")) {
            pizza = new PepperPizza();
            pizza.setName("胡椒披萨");
        }
        return pizza;
    }
}

【订购类】

package com.atguigu.factory.simplefactory.pizzastore.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.simplefactory.pizzastore.pizza.Pizza;
public class OrderPizza2 {
    Pizza pizza = null;
    String orderType = "";
    public OrderPizza2() {
        do {
            orderType = getType();
            //调用静态方法,类.方法名
            pizza = SimpleFactory.createPizza2(orderType);
            if (pizza != null) {
                //--if--  订购成功
                pizza.prepare();
                pizza.bake();
                pizza.cut();
                pizza.box();
            } else {
                System.out.println(" 订购披萨失败 ");
                break;
            }
        } while (true);
    }
    /**
     * 写一个方法,可以获取客户希望订购的披萨种类
     *
     * @return
     */
    private String getType() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
            System.out.println("input pizza 种类:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}

【主类】

package com.atguigu.factory.simplefactory.pizzastore.order;
//相当于一个客户端,发出订购
public class PizzaStore {
   public static void main(String[] args) {
      new OrderPizza2();
   }
}

工厂方法模式

新需求

披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪pizza、北京的胡椒pizza、或者是伦敦的奶略pizza、伦敦的胡椒pizza。(即不只是有Pizza种类的区别,还有地点的区别)

【思路一】

使用简单工厂模式,创建不同的简单工厂类,比如BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等,从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好(需要创建一堆类,不好管理)

【思路二】

使用工厂方法模式

介绍
  • 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
  • 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类
实现
Pizza实现

【实体类】

package com.atguigu.factory.factorymethod.pizzastore.pizza;
//将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 void setName(String name) {
        this.name = name;
    }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class BJCheesePizza extends Pizza {
    @Override
    public void prepare() {
        setName("北京的奶酪pizza");
        System.out.println(" 北京的奶酪pizza 准备原材料");
    }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class BJPepperPizza extends Pizza {
   @Override
   public void prepare() {
      setName("北京的胡椒pizza");
      System.out.println(" 北京的胡椒pizza 准备原材料");
   }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class LDCheesePizza extends Pizza{
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      setName("伦敦的奶酪pizza");
      System.out.println(" 伦敦的奶酪pizza 准备原材料");
   }
}
package com.atguigu.factory.factorymethod.pizzastore.pizza;
public class LDPepperPizza extends Pizza{
   @Override
   public void prepare() {
      // TODO Auto-generated method stub
      setName("伦敦的胡椒pizza");
      System.out.println(" 伦敦的胡椒pizza 准备原材料");
   }
}

【工厂类】

package com.atguigu.factory.factorymethod.pizzastore.order;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;
/**
 * 抽象类
 */
public abstract class OrderPizza {
   /**
    * 定义一个抽象方法,createPizza , 让各个工厂子类自己实现
    * @param orderType
    * @return
    */
   abstract Pizza createPizza(String orderType);
   /**
    * 构造器
    */
   public OrderPizza() {
      Pizza pizza = null;
      // 订购披萨的类型
      String orderType;
      do {
         orderType = getType();
         //直接调用抽象方法,由工厂子类完成
         pizza = createPizza(orderType);
         //输出pizza 制作过程
         pizza.prepare();
         pizza.bake();
         pizza.cut();
         pizza.box();
      } while (true);
   }
   /**
    * 写一个方法,可以获取客户希望订购的披萨种类
    * @return
    */
   private String getType() {
      try {
         BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));
         System.out.println("input pizza 种类:");
         String str = strin.readLine();
         return str;
      } catch (IOException e) {
         e.printStackTrace();
         return "";
      }
   }
}
package com.atguigu.factory.factorymethod.pizzastore.order;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.LDCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.LDPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;
/**
 * 工厂子类:伦敦工厂
 */
public class LDOrderPizza extends OrderPizza {
   @Override
   Pizza createPizza(String orderType) {
      Pizza pizza = null;
      if(orderType.equals("cheese")) {
         pizza = new LDCheesePizza();
      } else if (orderType.equals("pepper")) {
         pizza = new LDPepperPizza();
      }
      return pizza;
   }
}
package com.atguigu.factory.factorymethod.pizzastore.order;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;
/**
 * 工厂子类:北京工厂
 */
public class BJOrderPizza extends OrderPizza {
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}
package com.atguigu.factory.factorymethod.pizzastore.order;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.atguigu.factory.factorymethod.pizzastore.pizza.Pizza;
/**
 * 工厂子类:北京工厂
 */
public class BJOrderPizza extends OrderPizza {
    @Override
    Pizza createPizza(String orderType) {
        Pizza pizza = null;
        if (orderType.equals("cheese")) {
            pizza = new BJCheesePizza();
        } else if (orderType.equals("pepper")) {
            pizza = new BJPepperPizza();
        }
        return pizza;
    }
}

【主类】

package com.atguigu.factory.factorymethod.pizzastore.order;
public class PizzaStore {
   public static void main(String[] args) {
      String loc = "bj";
      if (loc.equals("bj")) {
         //创建北京口味的各种Pizza
         new BJOrderPizza();
      } else {
         //创建伦敦口味的各种Pizza
         new LDOrderPizza();
      }
      // TODO Auto-generated method stub
   }
}

【运行】

input pizza 种类:
cheese
 北京的奶酪pizza 准备原材料
北京的奶酪pizza baking;
北京的奶酪pizza cutting;
北京的奶酪pizza boxing;
input pizza 种类:
pepper
 北京的胡椒pizza 准备原材料
北京的胡椒pizza baking;
北京的胡椒pizza cutting;
北京的胡椒pizza boxing;
input pizza 种类:
身份证创建

【需求】

输入人的姓名,创建身份证,并提供使用功能

【框架代码】

package com.atguigu.factory.factorymethod.Sample.framework;
public abstract class Product {
    public abstract void use();
}
package com.atguigu.factory.factorymethod.Sample.framework;
public abstract class Factory {
    public abstract Product createProduct(String owner);
}

【子类代码】

package com.atguigu.factory.factorymethod.Sample.idcard;
import com.atguigu.factory.factorymethod.Sample.framework.Product;
public class IDCard extends Product {
    private String owner;
    IDCard(String owner) {
        System.out.println("制作" + owner + "的ID卡。");
        this.owner = owner;
    }
    public void use() {
        System.out.println("使用" + owner + "的ID卡。");
    }
    public String getOwner() {
        return owner;
    }
}
package com.atguigu.factory.factorymethod.Sample.idcard;
import com.atguigu.factory.factorymethod.Sample.framework.*;
public class IDCardFactory extends Factory {
    public Product createProduct(String owner) {
        return new IDCard(owner);
    }
}
【主类】
p

【运行】

制作小明的ID卡。
制作小红的ID卡。
制作小刚的ID卡。
使用小明的ID卡。
使用小红的ID卡。
使用小刚的ID卡。

【类图】

【登场角色】

  • Product(产品)
  • Creator(创建者):负责生成 Product角色的抽象类,Creator角色对于实际负责生成实例的ConcreteCreator角色一无所知它唯一知道的就是,只要调用生成实例的方法(如上图4的factoryMethod方法)就可以生成Product的实例
  • ConcreteProduct(具体的产品):决定具体的产品是什么,有什么用途
  • ConcreteCreator(具体的创建者):生成具体的产品

【分析】

现在是生成身份证,如果要生成其他产品,只需要修改ConcreteProduct和ConcreteCreator即可,框架不用改变

【衍生问题】

package com.atguigu.factory.factorymethod.A2.idcard;
import com.atguigu.factory.factorymethod.A2.framework.Product;
public class IDCard extends Product {
    private String owner;
    private int serial;
    IDCard(String owner, int serial) {
        System.out.println("制作" + owner + "(" + serial + ")" + "的ID卡。");
        this.owner = owner;
        this.serial = serial;
    }
    public void use() {
        System.out.println("使用" + owner + "(" + serial + ")" + "的ID卡。");
    }
    public int getSerial() {
        return serial;
    }
}
package com.atguigu.factory.factorymethod.A2.idcard;
import com.atguigu.factory.factorymethod.A2.framework.*;
import java.util.HashMap;
public class IDCardFactory extends Factory {
    private HashMap database = new HashMap();
    private int serial = 100;
    protected synchronized Product createProduct(String owner) {
        return new IDCard(owner, serial++);
    }
    public HashMap getDatabase() {
        return database;
    }
}
目录
相关文章
|
15天前
|
Java 测试技术 应用服务中间件
常见 Java 代码缺陷及规避方式(下)
常见 Java 代码缺陷及规避方式(下)
43 0
|
17天前
|
Java
Java中ReentrantLock释放锁代码解析
Java中ReentrantLock释放锁代码解析
25 8
|
15天前
|
Java
代码的魔法师:Java反射工厂模式详解
代码的魔法师:Java反射工厂模式详解
26 0
|
15天前
|
监控 安全 Java
常见 Java 代码缺陷及规避方式(中)
常见 Java 代码缺陷及规避方式(中)
27 1
|
17天前
|
设计模式 算法 Java
23种设计模式,模板方法模式的概念优缺点以及JAVA代码举例
【4月更文挑战第10天】模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些特定步骤。
15 0
|
18天前
|
设计模式 Java
23种设计模式,状态模式的概念优缺点以及JAVA代码举例
【4月更文挑战第9天】状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,这个对象看起来似乎修改了它的类。
29 4
|
18天前
|
算法 安全 Java
java代码 实现AES_CMAC 算法测试
该代码实现了一个AES-CMAC算法的简单测试,使用Bouncy Castle作为安全提供者。静态变量K定义了固定密钥。`Aes_Cmac`函数接受密钥和消息,返回AES-CMAC生成的MAC值。在`main`方法中,程序对给定的消息进行AES-CMAC加密,然后模拟接收ECU的加密结果并进行比较。如果两者匹配,输出"验证成功",否则输出"验证失败"。辅助方法包括将字节转为16进制字符串和将16进制字符串转为字节。
|
设计模式 Java 程序员
【Java设计模式】用 披萨订购案例 详细讲解三种工厂模式(三)
【Java设计模式】用 披萨订购案例 详细讲解三种工厂模式(三)
【Java设计模式】用 披萨订购案例 详细讲解三种工厂模式(三)
|
设计模式 Java
【Java设计模式】用 披萨订购案例 详细讲解三种工厂模式(二)
【Java设计模式】用 披萨订购案例 详细讲解三种工厂模式(二)
【Java设计模式】用 披萨订购案例 详细讲解三种工厂模式(二)
|
4天前
|
安全 Java 调度
Java线程:深入理解与实战应用
Java线程:深入理解与实战应用
23 0