• 每日一个设计模式之【工厂模式】


    每日一个设计模式之【工厂模式

    ☁️前言🎉🎉🎉

      大家好✋,我是知识汲取者😄,今天给大家带来一篇有关工厂模式的学习笔记。众所周知能够熟练使用设计模式是一个优秀程序猿的必备技能,当我们在项目中选择一个或多个合适的设计模式,不仅能大大提高项目的稳健性可移植性可维护性,同时还能让你的代码更加精炼,具备艺术美感

      在生活中资本家为了提高效率,将很多人组合到一起形成流水线,从而达到批量生产,于是工厂就诞生了。同样的,在代码的世界,有时候对象创建很频繁,为了提高效率,我们就会想着将对象的创建抽象出来形成一个类,这个类我们将其称之为工厂类。当然这就是工厂的粗略之谈,如果你想跟详细了解工厂模式,就请看完这篇文章吧,相信你一定能有所收获的😉,话不多说大家抓紧时间开搞。

    奥里给

    推荐阅读

    • 设计模式导学:🚪传送门
    • 每日一个设计模式系列专栏:🚪传送门
    • 设计模式专属Gitee仓库:✈启程
    • 设计模式专属Github仓库:🚀上路
    • 知识汲取者的个人主页:💓点我哦

    由于博主水平有限,如有纰漏、错误还请您能给予指正😊

    🌻工厂模式概述

    • 什么是工厂模式

      工厂模式(Factory Pattern)是一种创建型模式,它将对象创建的具体过程给屏蔽,将对象的创建交给工厂,工厂会根据条件创建不同的对象

    • 工厂模式的作用:将”类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,实现了解耦,即:使用者可直接消费产品而不需要知道其生产的细节

    • 工厂模式的优缺点

      • 优点

        • 让代码更加清晰。工厂模式将对象创建的细节进行了屏蔽,让开发者只需要关注对象创建的结果
        • 提高程序的扩展性。如果像增加一个对象,只需要扩展一个工厂即可,不需要去重构代码
        • 提高程序的灵活性。一个工厂可以生产出不同类型的对象
        • 降低了系统的耦合度。将对象的创建和本身的业务逻辑进行了分离,提高了可移植性、可维护性

        ……

      • 缺点:提高了系统的复杂度。没多一个对象,就需要多一个工厂类

    • 工厂模式的应用场景

      • 如果需要创建大量不同的对象,可以使用
      • 如果创建对象的过程很复杂,可以使用

      ……

      生活中的应用:产品在工厂生产,用户只管使用而不需要关注产品的生产过程

      Spring中的应用:在创建SqlSession对象时,是使用工厂模式构建的

    • 工厂模式的分类(以下三者抽象程度从上至下抽象程度逐渐提高,并且更具一般性)

      • 简单工厂模式(Simple Factory)
      • 工厂方法模式(Factory Method)
      • 抽象工厂模式(Abstract Factory)

      特别说明:简单工厂其实不是一个标准的的设计模式。GOF 23 种设计模式中只有「工厂方法模式」与「抽象工厂模式」。简单工厂模式可以看为工厂方法模式的一种特例,为了统一整理学习,就都归为工厂模式

    🌱工厂模式的实现

    🍀简单工厂模式

    简单工厂模式(Simple Factory),又叫做静态工厂方法(Static Factory Method)模式,它的实质是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。

    • 简单工厂模式的特点:根据给定的参数,决定究竟应该创建哪个具体类的对象(对象的创建由工厂决定)

    • 简单工厂模式解决的问题实现了对象创建和使用的职责分离

    • 简单工厂模式存在的问题违背了“开闭原则,每次新增产品,都需要去修改原有的工厂类

    • 简单工厂模式适用的场景

      • 一些比较简单的项目
      • 如果能够提前知道所有的产品,同时以后也会由产品的新增,可以尝试使用
    • 简单工厂模式中的角色划分

      • 工厂(Factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象
      • 抽象产品(Abstract Product)角色:它是一个接口,是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口
      • 具体产品(Concrete Product)角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例
    • 简单工厂模式的核心步骤

      • Step1:创建抽象产品
      • Step2:创建具体产品
      • Step3:创建工厂类

      实例

      问题描述:使用简单工厂模式设计一个可以创建不同几何形状(如圆形、方形和三角形等)绘图工具,每个几何形状都要有绘制draw()和擦除erase() 两个方法,要求在绘制不支持的几何图形时,提示一个UnSupportedShapeException

      要求:设计一个简单工厂模式,通过修改配置文件让工厂类创建不同的对象

      image-20221109212526965

      创建抽象产品
      具体产品
      创建工厂类
      编写配置文件
      编写配置文件的读取类
      测试
      • Step1:创建抽象产品

        Shape:

        package com.hhxy.product.shape;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title
         * @description
         */
        public interface Shape {
        
            /**
             * 形状的绘制方法
             */
            void draw();
        
            /**
             * 形状的擦除方法
             */
            void erase();
        
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
      • Step2:创建具体产品

        1)Circular:

        package com.hhxy.product.shape.imp;
        
        import com.hhxy.product.shape.Shape;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title 圆形类
         * @description
         */
        public class Circular implements Shape {
        
            /**
             * 形状的绘制方法
             */
            @Override
            public void draw() {
                System.out.println("绘制了一个圆形");
            }
        
            /**
             * 形状的擦除方法
             */
            @Override
            public void erase() {
                System.out.println("将绘制的圆形擦除了");
            }
        }
        
        • 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

        2)Rectangle

        具体代码请参考Gitee或Github仓库,略……

        3)Triangle

        具体代码请参考Gitee或Github仓库,略……

      • Step3:创建工厂类

        SimpleFactory

        package com.hhxy.factory;
        
        import com.hhxy.shape.Shape;
        import com.hhxy.shape.imp.Circular;
        import com.hhxy.shape.imp.Rectangle;
        import com.hhxy.shape.imp.Triangle;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title 简单工厂类
         * @description 用于创建Shape对象
         */
        public class SimpleFactory {
        
            public static Shape getShape(String shapeName){
                Shape shape;
                if("circular".equalsIgnoreCase(shapeName)){
                    shape = new Circular();
                }else if ("rectangle".equalsIgnoreCase(shapeName)){
                    shape = new Rectangle();
                }else if("triangle".equalsIgnoreCase(shapeName)){
                    shape = new Triangle();
                }else{
                    throw new RuntimeException("UnSupportedShapeException");
                }
                return shape;
            }
        }
        
        • 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
      • Step4:编写配置文件

        shape-config.xml

        
        <config>
            <shapeName>CircularshapeName>
            <shapeName>RectangleshapeName>
            <shapeName>TriangleshapeName>
            <shapeName>123shapeName>
        config>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
      • Step5:编写配置文件读取类

        ReadShapeConfig

        package com.hhxy.read;
        
        import org.w3c.dom.Document;
        import org.w3c.dom.Node;
        import org.w3c.dom.NodeList;
        
        import javax.xml.parsers.DocumentBuilder;
        import javax.xml.parsers.DocumentBuilderFactory;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title
         * @description 读取用于设置形状对象的配置文件
         */
        public class ReadShapeConfig {
            public static String getXML(){
                
                try{
                    //1、将配置文件加载到内存中,获取DOM对象
                    //1.1 获取DOM解析器工厂对象DocumentBuilderFactory,用于创建DOM解析器
                    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                    //1.2 获取DOM解析器DocumentBuilder
                    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                    //1.3 加载配置文件
        //            Document document = documentBuilder.parse(new FileInputStream("Factory/src/shape-config.xml"));
                    //让代码和模块名进行解耦,比上面那种方法要更优
                    Document document = documentBuilder.parse(ReadShapeConfig.class.getResourceAsStream("/shape-config.xml"));
        
                    //2、获取配置文件中的数据
                    //2.1 从DOM中获取指定的结点的结点列表
                    NodeList nodeList = document.getElementsByTagName("shapeName");
                    //2.2 获取指定位置的结点
                    Node classNode = nodeList.item(1).getFirstChild();
                    //2.3 获取指定结点中的数据(排除空格)
                    String name = classNode.getNodeValue().trim();
        
                    //3、返回从配置文件中读取的形状的名字
                    return name;
                } catch (Exception e) {
                    //如果异常就打印异常信息,同时返回一个空
                    e.printStackTrace();
                    return null;
                }
                
            }
        }
        
        • 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
      • Step6:测试

        package com.hhxy.test;
        
        import com.hhxy.factory.SimpleFactory;
        import com.hhxy.read.ReadShapeConfig;
        import com.hhxy.shape.Shape;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title 测试类1
         * @description 用于测试简单工厂
         */
        public class Test1 {
            public static void main(String[] args) {
                //1、读取配置文件,得到要创建对象的名字
                String shapeName = ReadShapeConfig.getXML();
                //2、使用简单工厂创建对象
                Shape shape = SimpleFactory.getShape(shapeName);
                //3、测试
                shape.draw();
                shape.erase();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22
        • 23

        测试结果:

        image-20220926200938234

    🍀工厂方法模式

      前面的简单工厂模式虽然实现了对象创建和对象操作的分离,但是存在一个严重的不足之处,那就是每次要新增产品,都需要去修改工厂类,这是不符合"开闭原则"的。

      针对这一现象,我们可以进行改进,从工厂类中抽象出一个工厂接口,不同的产品对应不同的工厂类,这些工厂类统一实现工厂接口,这样每次新增产品就只需要新增一个工厂类,然后实现一下工厂接口就可以了,而不需要像之前一样还要去修改工厂类的代码,这样就符合开闭原则了😃,使用这种方式实现的工厂模式我们称之为工厂方法模式(Factory Method),简称工厂模式,也称虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式

    • 工厂方法模式的特点:将对象的创建与实例化延迟到子类(对象的创建由子类决定)

    • 工厂方法模式解决的问题不符合开闭原则(由于增加产品需要去修改原有代码,变成现在只需要添加代码)

    • 工厂方法模式存在的问题增加了系统的复杂度。每次新增产品都需要编写一个具体工厂类和具体产品类,系统中类变多了,自然而然就让系统的复杂度增多了

    • 工厂方法模式的适用场景

      • 产品不是特别多,同时产品的添加频率不高的系统
      • 想要将类的创建延迟到子类的产品,可以使用工厂方法模式
      • 想要创建对象,只知道对象的父类名,不知道对象的具体类名,可以使用
    • 工厂方法模式中的角色划分

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

      • Step1:创建抽象产品
      • Step2:创建一个类,实现抽象产品
      • Step3:创建抽象工厂
      • Step4:创建一个类,实现抽象工厂

      示例

      问题描述:宝马(BMW)工厂制造宝马汽车,奔驰(Benz)工厂制造奔驰汽车,使用工厂方法模式模拟改场景,并用Java语言实现。并且扩展一个比亚迪工厂生产比亚迪汽车

      要求:设计一个工厂方法模式,抽象工厂对象能够根据配置文件中的内容创建不同的对象

      image-20221109215203716

      创建抽象产品
      创建具体产品
      创建抽象工厂
      创建具体工厂
      编写配置文件
      编写配置文件读取类
      测试
      • Step1:创建抽象产品

        Car:

        package com.hhxy.product.car;
        
        /**
         * @author ghp
         * @date 2022/9/26
         * @Title
         * @description
         */
        public interface Car {
            /**
             * 汽车启动的方法
             */
            void start();
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
      • Step2:创建具体产品

        1)Benz

        package com.hhxy.product.car.imp;
        
        import com.hhxy.product.car.Car;
        
        /**
         * @author ghp
         * @date 2022/9/26
         * @Title
         * @description
         */
        public class Benz implements Car {
            @Override
            public void start() {
                System.out.println("奔驰汽车启动了!");
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16

        2)Bmw

        和上面类似,具体代码请参考Gitee或Github仓库,略……

      • Step3:创建抽象工厂

        Factory:

        package com.hhxy.factory;
        
        import com.hhxy.product.car.Car;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title 工厂类接口
         * @description 用于宝马类工厂和奔驰类工厂实现,
         */
        public interface Factory {
            /**
             * 获取汽车对象的方法
             */
            Car getCar();
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
      • Step4:创建具体工厂

        1)BenzFactory:

        package com.hhxy.factory.imp;
        
        import com.hhxy.product.car.Car;
        import com.hhxy.product.car.imp.Benz;
        import com.hhxy.factory.Factory;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title 奔驰工厂类
         * @description 用于生产奔驰类的实例化对象
         */
        public class BenzFactory implements Factory {
        
            /**
             * 获取奔驰汽车对象的方法
             */
            @Override
            public Car getCar() {
                return new Benz();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22

        2)BmwFactory

        和上面的类似,具体代码请参考Gitee或Github仓库,略……

      • Step5:编写配置文件

        car-config.xml:

        
        <config>
            <factoryName>com.hhxy.factory.imp.BenzFactoryfactoryName>
            <factoryName>com.hhxy.factory.imp.BmwFactoryfactoryName>
            <factoryName>testfactoryName>
        config>
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
      • Step6:编写配置文件读取类

        ReadCarConfig:

        package com.hhxy.read;
        
        
        import com.hhxy.factory.Factory;
        import org.w3c.dom.Document;
        import org.w3c.dom.Node;
        import org.w3c.dom.NodeList;
        
        import javax.xml.parsers.DocumentBuilder;
        import javax.xml.parsers.DocumentBuilderFactory;
        import java.lang.reflect.Constructor;
        
        /**
         * @author ghp
         * @date 2022/9/23
         * @Title
         * @description 读取用于设置汽车对象的配置文件,同时返回一个Factory对象
         */
        public class ReadCarConfig {
            public static Object getFactory(){
        
                try{
                    //1、将配置文件加载到内存中,获取DOM对象
                    //1.1 获取DOM解析器工厂对象DocumentBuilderFactory,用于创建DOM解析器
                    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
                    //1.2 获取DOM解析器DocumentBuilder
                    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
                    //1.3 加载配置文件
        //            Document document = documentBuilder.parse(new FileInputStream("Factory/src/car-config.xml"));
                    //让代码和模块名进行解耦,比上面那种方法更优
                    Document document = documentBuilder.parse(ReadCarConfig.class.getResourceAsStream("/car-config.xml"));
        
                    //2、获取配置文件中的数据
                    //2.1 从DOM中获取指定的结点的结点列表
                    NodeList nodeList = document.getElementsByTagName("factoryName");
                    //2.2 获取指定位置的结点
                    Node classNode = nodeList.item(1).getFirstChild();
                    //2.3 获取指定结点中的数据(排除空格)
                    String factoryName = classNode.getNodeValue().trim();
        
                    //3、使用反射获取获取Factory对象
                    //3.1 获取类对象
                    Class cls = Class.forName(factoryName);
                    //3.2 获取该类对象的构造器对象
                    Constructor constructor = cls.getDeclaredConstructor();
                    //3.3 暴力反射,防止构造器私有化导致无法创建对象
                    constructor.setAccessible(true);
                    //3.4 获取工厂对象
                    Factory factory = (Factory) constructor.newInstance();
        
                    //4、返回通过配置文件获取的工厂对象
                    return factory;
                } catch (Exception e) {
                    //如果异常就打印异常信息,同时返回一个空
                    e.printStackTrace();
                    throw new RuntimeException("未找到该工厂类,请检查配置文件或者添加一个工厂类!");
                }
        
            }
        }
        
        • 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
        • 59
        • 60
      • Step7:测试

        package com.hhxy.test;
        
        import com.hhxy.car.Car;
        import com.hhxy.factory.Factory;
        import com.hhxy.read.ReadCarConfig;
        
        /**
         * @author ghp
         * @date 2022/9/26
         * @Title 测试类2
         * @description 用于测试工厂方法
         */
        public class Test2 {
            public static void main(String[] args) {
                //1、读取配置文件,获取要创建对象的工厂对象
                Factory factory = (Factory) ReadCarConfig.getFactory();
                //2、使用工厂获取对应的汽车对象
                Car car = factory.getCar();
                //3、测试输出
                car.start();
            }
        }
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
        • 17
        • 18
        • 19
        • 20
        • 21
        • 22

        测试结果:

        image-20220928201527085

    🍀抽象工厂模式

    抽象工厂模式(Abstract Factory Pattern)提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式

    前置知识

    • 产品族:指由同一个工厂生产的,位于不同产品等级结构中的一组产品
    • 产品等级结构:产品等级结构指的是产品的继承结构,例如一个空调抽象类,它有海尔空调、格力空调、美的空调等一系列的子类,那么这个空调抽象类和他的子类就构成了一个产品等级结构

    image-20220928204054951

    • 抽象工厂模式的特点:一个工厂能够生产多种不同的产品(前提是这些产品属于一个产品族)
    • 抽象工厂模式解决的问题系统的复杂度高(以前是一个产品需要配置一个工厂,现在是一个产品族只需要一个工厂)
    • 抽象工厂模式存在的缺点增加新的产品等级结构很麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则
    • 抽象工厂模式的适用场景
      • 存在产品族,强烈推荐使用
      • 产品等级结构固定,或者产品等级结构很稳定,推荐使用
      • 简单工厂模式、工厂方法模式能用的,抽象工厂模式都能用
    • 抽象工厂模式的角色划分:和工厂方法模式是一致的……

    示例

    问题描述:小米,华为,联想四家公司都能够生产电视、手机、冰箱三件产品,,使用抽象工厂模式模拟以上场景,并用Java语言实现

    要求:使用抽象工厂模式进行设计,通过读取配置文件获取工厂对象

    image-20221109220700443

    在这里插入图片描述

    创建抽象产品
    创建具体产品
    创建抽象工厂
    创建具体工厂
    编写配置文件
    编写配置文件读取类
    测试
    • Step1:创建抽象产品

      具体代码请参考Gitee或Github仓库,略……

    • Step2:创建具体产品

      具体代码请参考Gitee或Github仓库,略……

    • Step3:创建抽象工厂

      AbstractFactory:

      package com.hhxy.factory;
      
      import com.hhxy.product.conditioner.Conditioner;
      import com.hhxy.product.phone.Phone;
      import com.hhxy.product.tv.TV;
      
      /**
       * @author ghp
       * @date 2022/9/28
       * @Title
       * @description
       */
      public interface AbstractFactory {
          /**
           * 创建手机对象的方法
           */
          Phone getPhone();
      
          /**
           * 创建空调对象的方法
           */
          Conditioner getConditioner();
      
          /**
           * 创建电视对象的方法
           */
          TV getTV();
      
      }
      
      • 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
    • Step4:创建具体工厂

      1)HuaweiAbstractFactory:

      package com.hhxy.factory.imp;
      
      import com.hhxy.factory.AbstractFactory;
      import com.hhxy.product.conditioner.Conditioner;
      import com.hhxy.product.conditioner.imp.HuaweiConditioner;
      import com.hhxy.product.phone.Phone;
      import com.hhxy.product.phone.imp.HuaweiPhone;
      import com.hhxy.product.tv.TV;
      import com.hhxy.product.tv.imp.HuaweiTV;
      
      /**
       * @author ghp
       * @date 2022/9/28
       * @Title
       * @description
       */
      public class HuaweiAbstractFactory implements AbstractFactory {
          /**
           * 创建华为手机对象的方法
           */
          @Override
          public Phone getPhone() {
              return new HuaweiPhone();
          }
      
          /**
           * 创建华为空调对象的方法
           */
          @Override
          public Conditioner getConditioner() {
              return new HuaweiConditioner();
          }
      
          /**
           * 创建电视对象的方法
           */
          @Override
          public TV getTV() {
              return new HuaweiTV();
          }
      }
      
      • 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

      2)XiaomiAbstractFactory

      和上面类似,具体请参考Gitee或Github,略……

    • Step5:编写配置文件

      factory-config.xml:

      <?xml version="1.0" encoding="UTF-8" ?>
      <config>
          <abstractFactoryName>com.hhxy.factory.imp.HuaweiAbstractFactory</abstractFactoryName>
          <abstractFactoryName>com.hhxy.factory.imp.XiaomiAbstractFactory</abstractFactoryName>
          <abstractFactoryName>com.hhxy.factory.imp.LianXiangAbstractFactory</abstractFactoryName>
          <abstractFactoryName>test</abstractFactoryName>
      </config>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
    • Step6:编写配置文件读取类

      和工厂方法模式的类似,具体请参考Gitee或Github,略……

    • Step7:测试

      package com.hhxy.test;
      
      import com.hhxy.factory.AbstractFactory;
      import com.hhxy.read.ReadFactoryConfig;
      
      /**
       * @author ghp
       * @date 2022/9/28
       * @Title 测试类3
       * @description 用于测试抽象工厂模式
       */
      public class Test3 {
          public static void main(String[] args) {
              //测试使用华为工厂创建华为这一产品族的对象
      
              /*
              方式一:
              AbstractFactory huaweiAbstractFactory = new HuaweiAbstractFactory();
              huaweiAbstractFactory.getTV().watch();
              huaweiAbstractFactory.getPhone().call();
              huaweiAbstractFactory.getConditioner().open();
              */
      
              //方式二:通过读取配置文件获取工厂对象。这种方式能够降低耦合度,提高了代码的复用性,很方便测试
              AbstractFactory abstractFactory = ReadFactoryConfig.getAbstractFactory();
              abstractFactory.getTV().watch();
              abstractFactory.getPhone().call();
              abstractFactory.getConditioner().open();
      
          }
      }
      
      • 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

      测试结果:

      image-20220928223859498

    🌲总结

    • 三个工厂模式的比较:

      • 简单工厂模式实现起来最简单,只适合很小的项目,它不属于23种设计模式。对象的创建由工厂决定,实现了对象创建和对象操作的分离,产品的增加需要修改原有的工厂类代码,不符合开闭原则
      • 工厂方法模式适合用于小、中型项目,但对于大型项目会增加系统的复杂度。对象实例化被延迟到了子类,符合开闭行原则,且不需要明确对象对应的类名,每增加一个产品都需要增加一个具体工厂
      • 抽象工厂模式适合小、中以及大型项目,特别是项目中的产品具有产品族的时候更加能体现该模式的优越性。一个工厂能生产多个产品(前提这些产品都属于同一个产品族),对于产品族的增加只需要添加一个产品和一个具体工厂就可以了(符合开闭原则),但是如果想要添加一个新的产品等级结构,就需要修改原来的代码,不符合开闭原则
      • 当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式

      总的来讲三种模式各有优劣,从上往下抽象等级依次增加,这也表明往下更具一般性,适用范围更广

    自此,文章就结束了,如果觉得本文对你有一丢丢帮助的话😄,欢迎点赞👍+评论✍,您的支持将是我写出更加优秀文章的动力O(∩_∩)O

    眼神暗示


    上一篇:每日一个设计模式之【原型模式】

    下一篇:每日一个设计模式之【建造者模式】

    参考文章

    在此致谢

  • 相关阅读:
    springcloudalibaba架构(19):链路追踪ZipKin数据持久化至mysql
    【Redis系列】缓存击穿、穿透、雪崩解决方案详解
    20220920线程属性
    决策树算法
    全国职业院校技能大赛 - ruijie网络模块 - 样卷三解析
    【Flink实战】新老用户方案优化使用状态与布隆过滤器的方式
    Windows11安装MySQL8.1
    TensorFlow手动加载数据集(以mnist为例)
    Unbuntu系统下,切换python版本
    3.2python使用 matplotlib 实现可视化_python量化实用版教程(初级)
  • 原文地址:https://blog.csdn.net/qq_66345100/article/details/127779449