【设计模式——学习笔记(上)】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;
    }
}
目录
相关文章
|
5天前
|
设计模式 测试技术
【设计模式系列笔记】工厂模式
工厂模式是一种创建型设计模式,其主要目的是将对象的创建过程抽象出来,以便在需要的时候由子类来实现。这种模式提供了一种方法,通过调用一个共同的接口来创建一组相关或依赖的对象,而无需指定其具体的类。
122 4
|
3天前
|
设计模式 Java
Java一分钟之-设计模式:工厂模式与抽象工厂模式
【5月更文挑战第17天】本文探讨了软件工程中的两种创建型设计模式——工厂模式和抽象工厂模式。工厂模式提供了一个创建对象的接口,延迟实例化到子类决定。过度使用或违反单一职责原则可能导致问题。代码示例展示了如何创建形状的工厂。抽象工厂模式则用于创建一系列相关对象,而不指定具体类,但添加新产品可能需修改现有工厂。代码示例展示了创建颜色和形状的工厂。根据需求选择模式,注意灵活性和耦合度。理解并恰当运用这些模式能提升代码质量。
14 2
|
5天前
|
设计模式 前端开发 API
写出易维护的代码|React开发的设计模式及原则
本文对React社区里出现过的一些设计模式进行了介绍,并讲解了他们遵循的设计原则。
|
5天前
|
设计模式 安全 Java
【设计模式学习】单例模式和工厂模式
【设计模式学习】单例模式和工厂模式
|
5天前
|
设计模式 消息中间件 Java
Java 设计模式:探索发布-订阅模式的原理与应用
【4月更文挑战第27天】发布-订阅模式是一种消息传递范式,被广泛用于构建松散耦合的系统。在 Java 中,这种模式允许多个对象监听和响应感兴趣的事件。
39 2
|
5天前
|
设计模式 算法 Java
Java 设计模式:深入模板方法模式的原理与应用
【4月更文挑战第27天】模板方法模式是一种行为设计模式,主要用于定义一个操作中的算法的框架,允许子类在不改变算法结构的情况下重定义算法的某些特定步骤。
23 1
|
5天前
|
设计模式 Java
Java 设计模式:工厂模式与抽象工厂模式的解析与应用
【4月更文挑战第27天】设计模式是软件开发中用于解决常见问题的典型解决方案。在 Java 中,工厂模式和抽象工厂模式是创建型模式中非常核心的模式,它们主要用于对象的创建,有助于增加程序的灵活性和扩展性。本博客将详细介绍这两种模式的概念、区别以及如何在实际项目中应用这些模式。
17 1
|
5天前
|
设计模式 存储 Java
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
C++从入门到精通:3.5设计模式——提升代码可维护性与可扩展性的关键
|
5天前
|
NoSQL Java Redis
Java代码实现记录接口调用次数
Java代码实现记录接口调用次数
|
5天前
|
Java
代码的魔法师:Java反射工厂模式详解
代码的魔法师:Java反射工厂模式详解
29 0