设计模式之工厂模式(简单工厂、工厂方法、抽象工厂模式)

素颜马尾好姑娘i 2023-01-22 09:49 168阅读 0赞

工厂模式

文章目录

  • 工厂模式
    • 一、前言
    • 二 、简单工厂模式
        1. 结构
        1. 实现
        1. 静态工厂
    • 三、工厂方法模式
        1. 结构
        1. 实现
    • 四、抽象工厂模式
        1. 结构
        1. 实现

一、前言

需要设计一个咖啡店点餐系统,需要创建的类有:

  • 咖啡类(Coffee)

    • 子类美式咖啡(AmericanCoffee)
    • 子类拿铁咖啡(LatteCoffee)
  • 咖啡店类(CoffeeStore)

    • 具有点餐功能(orderCoffee)

具体的UML类图如下所示:

image-20210510181742449

这种设计结构的缺点:

在咖啡店类的点餐方法中创建对象的时候直接new对象,就会对该对象耦合严重,如果要新增一种咖啡的品种,就需要修改点餐方法,违背了软件设计的开闭原则。

由此引入了工厂模式,目的是为了解耦合,工厂模式分为三种:

  • 简单工厂模式(不属于23种经典设计模式)
  • 工厂方法模式
  • 抽象工厂模式

二 、简单工厂模式

简单工厂不是一种设计模式,反而比较像是一种编程习惯

1. 结构

简单工厂包含如下角色:

  • 抽象产品 :定义产品的规范,描述产品的主要特性和功能
  • 具体产品 :实现或者继承抽象产品的子类
  • 具体工厂 :提供创建产品的方法,调用者通过该方法来获取产品

    • 在工厂中创建具体的咖啡实现类

2. 实现

使用简单工厂模式对上面的案例进行改进,类图如下:

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80OTM0MzE5MA_size_16_color_FFFFFF_t_70

  • 抽象的Coffee类

    1. public abstract class Coffee {
    2. //抽象方法,需要子类去实现
    3. public abstract String getName();
    4. //加糖
    5. public void addsugar() {
    6. System.out.println("加糖");
    7. }
    8. //加奶
    9. public void addMilk() {
    10. System.out.println("加奶");
    11. }
    12. }
  • 美式咖啡子类

    1. public class AmericanCoffee extends Coffee {
    2. @Override
    3. public String getName() {
    4. return "美式咖啡";
    5. }
    6. }
  • 拿铁咖啡子类

    1. public class LatteCoffee extends Coffee {
    2. @Override
    3. public String getName() {
    4. return "拿铁咖啡";
    5. }
    6. }
  • 咖啡工厂类

    1. public class SimpleCoffeeFactory {
    2. public Coffee createCoffee(String type) {
    3. //声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象
    4. Coffee coffee = null;
    5. if("american".equals(type)) {
    6. coffee = new AmericanCoffee();
    7. } else if("latte".equals(type)) {
    8. coffee = new LatteCoffee();
    9. } else {
    10. throw new RuntimeException("对不起,您所点的咖啡没有");
    11. }
    12. return coffee;
    13. }
    14. }
  • 咖啡店类

    1. public class CoffeeStore {
    2. //调用工厂中生产具体咖啡的方法
    3. public Coffee orderCoffee(String type) {
    4. //创建工厂对象
    5. SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
    6. //调用生产咖啡的方法
    7. Coffee coffee = factory.createCoffee(type);
    8. //加配料
    9. coffee.addMilk();
    10. coffee.addsugar();
    11. return coffee;
    12. }
    13. }
  • 进行使用

    1. public class Client {
    2. public static void main(String[] args) {
    3. //创建咖啡店类对象
    4. CoffeeStore store = new CoffeeStore();
    5. Coffee coffee = store.orderCoffee("latte");
    6. System.out.println(coffee.getName());
    7. //加奶
    8. //加糖
    9. //拿铁咖啡
    10. }
    11. }
  • 优点

    • CoffeeStore类解除了和Coffee实现类的耦合
    • 当新增咖啡品种时,只需要修改工厂类的代码,而不用去修改CoffeeStore类的代码

      • 工厂类的客户端可能有很多(CoffeeStore算一个),其他还有出售咖啡的甜品店等,当咖啡品种发生变化的时候,只需要修改工厂类的代码,而无需去每个客户端中修改代码,提高效率
  • 缺点

    • 产生了新的耦合,CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合,工厂对象和Coffee实现类的耦合
    • 当新增咖啡品种时,需要修改工厂类的代码,违反了开闭原则

3. 静态工厂

在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的,这个就是静态工厂模式,它也不是23种设计模式中的,代码如下:

  1. public class SimpleCoffeeFactory {
  2. public static Coffee createCoffee(String type) {
  3. //省略工厂中的方法
  4. }
  5. }

相比简单工厂模式,此方式的好处是在不同的客户端中无需创建不同的工厂对象

三、工厂方法模式

  • 工厂方法模式完全遵循开闭原则,可以解决简单工厂模式的缺陷
  • 工厂方法模式使一个产品类的实例化延迟到其工厂的子类中

1. 结构

工厂方法模式的主要角色:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂(抽象工厂的子类)的工厂方法来创建产品
  • 具体工厂(ConcreteFactory):实现抽象工厂中的抽象方法,完成具体产品的创建
  • 抽象产品(Product):定义产品的规范,描述了产品的主要特性和功能
  • 具体产品(ConcreteProduct):实现抽象产品所定义的接口,由具体工厂来创建,它与具体工厂之间是一对一的关系

2. 实现

使用工厂方法模式对上面的案例进行改进,类图如下:

image-20210510190403721

  • 抽象工厂类

    1. public interface CoffeeFactory {
    2. //创建咖啡对象的方法
    3. Coffee createCoffee();
    4. }
  • 两个具体工厂类

    1. public class AmericanCoffeeFactory implements CoffeeFactory {
    2. @Override
    3. public Coffee createCoffee() {
    4. return new AmericanCoffee();
    5. }
    6. }
    7. public class LatteCoffeeFactory implements CoffeeFactory {
    8. @Override
    9. public Coffee createCoffee() {
    10. return new LatteCoffee();
    11. }
    12. }
  • 咖啡店类

    1. public class CoffeeStore {
    2. private CoffeeFactory factory;
    3. //创建咖啡店类时指定具体工厂
    4. public CoffeeStore(CoffeeFactory factory) {
    5. this.factory = factory;
    6. }
    7. //点咖啡功能
    8. public Coffee orderCoffee() {
    9. Coffee coffee = factory.createCoffee();
    10. //加配料
    11. coffee.addMilk();
    12. coffee.addsugar();
    13. return coffee;
    14. }
    15. }
  • 进行使用

    1. public class Client {
    2. public static void main(String[] args) {
    3. //创建咖啡店对象,使用创建拿铁咖啡的具体工厂
    4. CoffeeStore store = new CoffeeStore(new LatteCoffeeFactory());
    5. //点咖啡
    6. Coffee coffee = store.orderCoffee();
    7. System.out.println(coffee.getName());
    8. //加奶
    9. //加糖
    10. //拿铁咖啡
    11. }
    12. }
  • 优点

    • 如果新添加一种咖啡,只需要创建一个咖啡工厂的子实现类即可,无需修改原有代码,降低耦合度,满足开闭原则
  • 缺点

    • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这样会增加系统的复杂度

四、抽象工厂模式

  • 前面介绍的工厂方法模式中考虑的是一类产品的生产,即具体工厂只生产对应的那一类产品,比如畜牧场工厂类只生产动物、电视生产商工厂类只生产电视机
  • 这些工厂只生产同种类产品,同种类产品称为同等级产品,也就是说,工厂方法模式只考虑生产同等级的产品
  • 抽象工厂模式采用多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族

    • 华为生产的荣耀手机、小米生产的红米手机属于同等级产品
    • 华为生产的游戏本电脑、小米生产的轻薄本电脑属于同等级产品
    • 华为生产的荣耀手机和游戏本电脑称为产品族
  • 抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品

    • 也就是工厂类原来只能创建同等级产品,现在可以创建产品族(多个方法创建不同等级的产品)

1. 结构

抽象工厂模式的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品
  • 具体工厂(Concrete Factory):实现抽象工厂中的多个抽象方法,完成具体产品的创建
  • 抽象产品(Product):定义产品的规范,描述了产品的主要特性和功能
  • 具体产品(ConcreteProduct):实现抽象产品所定义的接口,由具体工厂来创建,它与具体工厂之间是多对一的关系

2. 实现

咖啡店业务发生改变,不仅要生产咖啡还要生产甜点,如提拉米苏、抹茶慕斯等,要是按照工厂方法模式,需要定义提拉米苏类、抹茶慕斯类、提拉米苏工厂、抹茶慕斯工厂、甜点工厂类,很容易发生类爆炸情况。

其中拿铁咖啡、美式咖啡属于同等级产品,都是咖啡;提拉米苏、抹茶慕斯也属于同等级产品,都是甜点。

拿铁咖啡和提拉米苏是同一产品族(都属于意大利风味工厂制造),美式咖啡和抹茶慕斯是同一产品族(都属于美式风味工厂制造)。

此案例通过抽象工厂模式实现的UML类图如下:

image-20210510212815393

  • 抽象工厂类

    1. public interface DessertFactory {
    2. Coffee createCoffee();
    3. Dessert createDessert();
    4. }
  • 两个具体工厂

    1. //美式甜点工厂
    2. public class AmericanDessertFactory implements DessertFactory {
    3. public Coffee createCoffee() {
    4. return new AmericanCoffee();
    5. }
    6. public Dessert createDessert() {
    7. return new MatchaMousse();
    8. }
    9. }
    10. //意大利风味甜点工厂
    11. public class ItalyDessertFactory implements DessertFactory {
    12. public Coffee createCoffee() {
    13. return new LatteCoffee();
    14. }
    15. public Dessert createDessert() {
    16. return new Tiramisu();
    17. }
    18. }
  • 进行使用

    1. public class Client {
    2. public static void main(String[] args) {
    3. //创建的是意大利风味甜品工厂对象
    4. ItalyDessertFactory factory = new ItalyDessertFactory();
    5. //获取拿铁咖啡和提拉米苏甜品
    6. Coffee coffee = factory.createCoffee();
    7. Dessert dessert = factory.createDessert();
    8. }
    9. }
  • 优点

    • 相比工厂方法模式修改的类更少,代码耦合度更低
    • 适用于当需要创建的对象是一系列相互关联或相互依赖的产品族时,比如格力工厂中的电视机、洗衣机、空调等

发表评论

表情:
评论列表 (有 0 条评论,168人围观)

还没有评论,来说两句吧...

相关阅读