• 【设计模式】工厂模式(Factory Pattern)


    1. 概述

    工厂模式(Factory Pattern)是最常用的设计模式之一,它属于创建类型的设计模式。它提供了一种创建对象的最佳方式,在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过一个共同的接口来指向新创建的对象。

    工厂模式(Factory Pattern)是 3 种工厂模式的总称 —— 简单工厂模式(Simple Factory)工厂方法模式(Factory Method)抽象工厂模式(Abstract Factory)

    这 3 种模式从上到下逐步抽象,并且具有一般性。用一下案例来理解工厂模式:

    (1)在没有工厂的时代,如果用户需要一款宝马车,那么就需要用户自己去创建一款宝马车,即用户自己去执行创建一款宝马车所需要的一系列的复杂的操作,然后才能拿来用;
    (2)简单工厂模式:后来出现了工厂,用户不再需要去创建宝马车,由工厂进行创建,即由工厂来执行创建宝马车的一些列复杂的操作,用户不用关心复杂的创建过程,用户想要什么车,直接通过工厂创建就可以了。比如,想要320i系列车,工厂就创建这个系列的车;
    (3)工厂方法模式:为了满足不同用户的需求,宝马车推出了越来越多的车系以满足不同用户的需求,如320i系列、523i等等系列。原先一个工厂无法创建所有的宝马车系,于是又单独分出来多个具体的工厂,每个工厂创建一种车系,即具体工厂类只能创建一个具体产品。但是宝马工厂还是个抽象,用户需要指定某个具体的工厂才能生产出他所需要的车。例如,客户需要宝马320i系列的车,那么他就需要执行生产宝马320i系列车的工厂生产一辆他所需要的车;
    (4)抽象工厂模式:随着客户要求越来越高,宝马车必须配置空调,于是这个工厂开始生产宝马车和所需要的空调。用户只要提出他需要宝马320i空调车,宝马工厂就直接给他提供宝马320i空调车,而不用自己去创建宝马320i空调宝马车。

     

    2. 简单工厂模式

    简单工厂模式的核心是定义一个创建对象的接口,讲对象的创建和本身的业务逻辑分离,降低系统的耦合度,使得两个修改起来相对容易些,当以后实现改变时,只需要修改工厂类即可。

    如果不使用工厂,用户将需要自己创建宝马车。

    public class BMW320 {
        public BMW320() {
            System.out.println("制造-->BMW320");
        }
    }
    
    public class BMW523 {
        public BMW523() {
            System.out.println("制造-->BMW523");
        }
    }
    
    public class Customer {
        public static void main(String[] args) {
            // 不适用简单工厂模式时,用户需要宝马车,则需要自己去创建
            BMW320 bmw320 = new BMW320();
            BMW523 bmw523 = new BMW523();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    用户需要知道怎么创建一款车,这样客户和车就紧密耦合在一起了,为了降低耦合性,就出现了简单工厂模式,把创建宝马车的操作细节都放到了工厂里,而客户直接使用工厂的创建方法,传入想要的宝马车型号就行了,而不必去知道创建的细节。

    UML类图

    • 工厂类角色:该模式的核心,用来创建产品,含有一定的商业逻辑和判断逻辑
    • 抽象产品角色:它一般是具体产品集成的父类或者实现的接口
    • 具体产品角色:工厂类所创建的对象就是次角色的实例,在JAVA中由一个具体的类实现

    代码实现

    产品类

    public abstract class BMW {
    
        protected String type;
    
        public BMW() {
        }
    
        abstract public String getBMWType();
    }
    
    public class BMW320 extends BMW {
        public BMW320() {
            System.out.println("制造-->BMW320");
            type = "BMW320";
        }
    
        @Override
        public String getBMWType() {
            return type;
        }
    }
    
    public class BMW523 extends BMW {
        public BMW523() {
            System.out.println("制造-->BMW523");
            type = "BMW523";
        }
    
        @Override
        public String getBMWType() {
            return type;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    工厂类

    public class BMWFactory {
        public BMW createBMW(String type) {
            switch (type) {
                case "320":
                    return new BMW320();
                case "523":
                    return new BMW523();
                default:
                    break;
            }
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Customer类

    public class Customer {
        public static void main(String[] args) {
            BMWFactory bmwFactory = new BMWFactory();
            BMW bmw = bmwFactory.createBMW("320");
            System.out.println("BMW type: " + bmw.getBMWType());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    测试

     

    简单工厂模式优缺点

    优点
    简单工厂模式提供专门的工厂类用于创建对象,实现了对象创建和使用的职责分离,客户端不需知道所创建的具体产品类的类名以及创建过程,只需要知道具体产品类所对应的参数即可。通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

    缺点
    缺点在于不符合设计模式的 “开闭原则”(对扩展开放,对修改关闭),每次添加新的产品就需要修改工厂类。在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展维护,并且工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要收到影响。

    为了解决简单工厂模式的问题,出现了工厂方法模式。

     

    3. 工厂方法模式

    UML图

    • 抽象工厂 AbstractFactory:工厂方法模式的核心,是具体工厂角色必须实现的接口或者必须继承的父类,在JAVA中它由接口或者抽象类来实现;
    • 具体工厂 Factory:被应用程序调用以创建具体产品的对象,含有和具体业务逻辑有关的代码;
    • 抽象产品 AbstractProduct:是具体产品类继承的父类或实现的接口,在JAVA中一般由抽象类或者接口来实现;
    • 具体产品 Product:具体工厂角色所创建的对象就是此角色的实例。
       

    代码实现

    产品类

    public abstract class BMW {
    
        protected String type;
    
        public BMW() {
        }
    
        abstract public String getBMWType();
    }
    
    public class BMW320 extends BMW {
        public BMW320() {
            System.out.println("制造-->BMW320");
            type = "BMW320";
        }
    
        @Override
        public String getBMWType() {
            return type;
        }
    }
    
    public class BMW523 extends BMW {
        public BMW523() {
            System.out.println("制造-->BMW523");
            type = "BMW523";
        }
    
        @Override
        public String getBMWType() {
            return type;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    工厂类

    public interface BMWFactory {
        BMW createBMW();
    }
    
    public class BMW320Factory implements BMWFactory  {
        @Override
        public BMW createBMW() {
            System.out.println("BMW320 工厂生产 BMW320");
            return new BMW320();
        }
    }
    
    public class BMW523Factory implements BMWFactory  {
        @Override
        public BMW createBMW() {
            System.out.println("BMW523 工厂生产 BMW523");
            return new BMW523();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    Consumer类

    public class Consumer {
        public static void main(String[] args) {
            // 用户指定具体的生产工厂
            BMWFactory bmwFactory= new BMW523Factory();
            // 由指定的工厂生产产品
            BMW bmw = bmwFactory.createBMW();
            System.out.println("BMW type: " + bmw.getBMWType());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试

     

    工厂方法模式的优缺点

     

    4. 抽象工厂模式

    在工厂方法模式中,我们使用一个工厂创建一个产品,一个具体的工厂对应一个具体产品。但我们有时希望一个工厂能够提供多个产品对象,而不是单一的产品对象,这个时候就需要抽象工厂模式。

    在了解抽象工厂模式之前,需要先理清楚 产品等级结构产品族 两个概念:

    • 产品等级结构
      产品等级结构指的是产品的继承结构,例如一个空调抽象类,它有海尔空调、隔离空调、美的空调等一系列的子类,那么这个空调抽象类和它的子类就构成了一个产品等级结构;

    • 产品族
      产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。例如,海尔工厂生产海尔空调、海尔冰箱,那么海尔空调、海尔冰箱就位于海尔产品族中。

    抽象工厂主要用于创建相关对象的家族,当一个产品族中需要被设计在一起工作时,通过抽象工厂模式,能够保证客户端始终只使用一个产品族中的对象;并且通过隔离具体类的生产,使得客户端不需要明确指定具体生成类;所有的具体工厂都实现了抽象工厂中定义的公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

    但该模式的缺点在于添加新的行为时比较麻烦,如果需要添加一个新的产品族对象时,需要更改接口及其下所有子类,这必然会带来很大的麻烦。

     

    UML图

    • 抽象工厂 AbstractFactory:定义了一个接口,这个接口包含了一组方法用来生产产品,所有的具体工厂都必须实现此接口;
    • 具体工厂 ConcreteFactory:用于生产不同的产品族,要创建一个产品,用户只需使用其中一个工厂进行获取,完全不需要实例化任何产品对象;
    • 抽象产品 AbstractProduct:这是一个产品家族,每一个具体工厂都能够生产一整组产品;
    • 具体产品 Product

     

    代码实现

    通过抽象工厂模式,我们可以实现以下的效果:比如宝马320系列使用空调型号A和发动机型号A,而宝马523系列使用空调型号B和发动机型号B,在为320系列生产相关配件时,就无需指定配件的型号,它会自动根据车型生产对应的配件型号A。

    也就是说,当每个抽象产品都有多余一个具体子类的时候(空调有型号A和B两种,发动机也有型号A和B两种),工厂角色怎么知道实例化哪一个子类呢?抽象工厂模式提供两个具体工厂角色(宝马320系列工厂和宝马523系列工厂),分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化,每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。

    产品类

    // Engine
    public abstract class AbstractEngine {
        /**
         * 引擎的型号
         */
        protected String type;
        abstract public String getType();
    }
    
    public class EngineA extends AbstractEngine {
        public EngineA() {
            this.type = "Engine A";
        }
        @Override
        public String getType() {
            return this.type;
        }
    }
    
    public class EngineB extends AbstractEngine {
        public EngineB() {
            this.type = "Engine B";
        }
        @Override
        public String getType() {
            return this.type;
        }
    }
    
    
    // AirConditioner
    public abstract class AbstractAirConditioner {
        /**
         * 空调的型号
         */
        protected String type;
        abstract public String getType();
    }
    
    public class AirConditionerA extends AbstractAirConditioner {
        public AirConditionerA() {
            this.type = "AirConditioner A";
        }
        @Override
        public String getType() {
            return this.type;
        }
    }
    
    public class AirConditionerB extends AbstractAirConditioner {
        public AirConditionerB() {
            this.type = "AirConditioner B";
        }
        @Override
        public String getType() {
            return this.type;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    工厂类

    public interface BMWFactory {
        AbstractEngine createEngine();
        AbstractAirConditioner createAirConditioner();
    }
    
    public class BMW320Factory implements BMWFactory {
        @Override
        public AbstractEngine createEngine() {
            System.out.println("制造 Engine A");
            return new EngineA();
        }
        @Override
        public AbstractAirConditioner createAirConditioner() {
            System.out.println("制造 AirConditioner A");
            return new AirConditionerA();
        }
    }
    
    public class BMW523Factory implements BMWFactory {
        @Override
        public AbstractEngine createEngine() {
            System.out.println("制造 Engine B");
            return new EngineB();
        }
        @Override
        public AbstractAirConditioner createAirConditioner() {
            System.out.println("制造 AirConditioner B");
            return new AirConditionerB();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    Consumer类

    public class Consumer {
        public static void main(String[] args) {
            BMWFactory bmwFactory = new BMW523Factory();
            AbstractEngine engine = bmwFactory.createEngine();
            AbstractAirConditioner airConditioner = bmwFactory.createAirConditioner();
            System.out.println("Engine型号: " + engine.getType());
            System.out.println("AirConditioner型号: " + airConditioner.getType());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    测试

     

    5. 工厂模式小结

    工厂方法模式与抽象工厂模式的区别在于:

    1)工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类,每个具体工厂类只能创建一个具体产品类的实例;

    2)抽象工厂模式拥有多个产品类(产品族)和一个抽象工厂类,每个抽象产品类可以派生出多个具体产品类;抽象工厂类也可以派生出多个具体工厂类,同时每个具体工厂类可以创建多个具体产品类的实例。

     

    参考文献

    [1] https://blog.csdn.net/a745233700/article/details/120253639?spm=1001.2014.3001.5506

  • 相关阅读:
    为什么 Spring的构造器注入不需要 @Autowired 注解
    Vue {{}}里面不同内容
    【Rust日报】2022-11-29 Wirefish:基于 Tauri 的跨平台数据包嗅探器
    Android 编译插桩操纵字节码
    sqlserver修改decimal类型的长度
    oracle,CLOB转XML内存不足,ORA-27163: out of memory ORA-06512: at “SYS.XMLTYPE“,
    [论文阅读] 颜色迁移-梯度保护颜色迁移
    【个人成长】001- 4 个步骤提升你的复盘能力
    [正式学习java①]——java项目结构,定义类和创建对象,一个标准javabean的书写
    GPT接入企微应用 - 让工作快乐起来
  • 原文地址:https://blog.csdn.net/qq_27198345/article/details/126433647