简单工厂模式大解析:让代码创造更高效、更智能!

个人主页: danci_  
🔥系列专栏:《设计模式》《MYSQL应用》
💪🏻 制定明确可量化的目标,坚持默默的做事。
🚀 转载自热榜文章:探索设计模式的魅力:简单工厂模式


简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,其主要目的是用于创建对象的实例。这种模式通过封装创建对象的代码来降低客户代码与具体类之间的耦合度。简单工厂不是GoF(四人帮)设计模式之一,但它是一个常用的编程惯用法。

在简单工厂模式中,创建对象的责任通常由一个单一的工厂类承担,这个工厂类有一个用来根据输入参数创建并返回不同类型对象实例的方法。这种模式通常用于管理和创建那些具有共同接口或父类的一组类的实例。

目录

一、业务案例

二、简单实现

三、简单工厂模式

3.1 面向对象编程

3.1.2 接口

3.1.2 面向接口编程

3.2 不用设计模式解决

3.3 用简单工厂模式解决

3.3.1 工厂模式结构及说明

3.3.2 模式分解

3.3.3 理解简单工厂模式

3.4 简单工厂模式优缺点

3.5 思考简单工厂模式

3.5.1 本质

3.5.2 何时选用简单工厂模式

3.6 相关设计模式结合


一、业务案例

请用程序实现输入两个整数和运算符,然后输出结果。

二、简单实现

    两三下就搞定,代码如下:

import java.util.Scanner;

public class Tester {

    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);

        int a = scanner.nextInt();
        int b = scanner.nextInt();
        String c = scanner.nextLine().trim();
        scanner.close();

        switch (c) {
            case "+": {
                System.out.println(a + b);
                return;
            }
            case "-": {
                System.out.println(a - b);
                return;
            }
            case "*": {
                System.out.println(a * b);
                return;
            }
            case "/": {
                if (b == 0) {
                    return;
                }
                System.out.println(a / b);
                return;
            }
            default: return;
        }

    }
}

正常运行看结果看似没有什么毛病,但阅读一下代码就实在不康入目

  • 看不懂变量abc代码什么意思。
  • 好多判断。
  • 如果第一次和第二次输入符号会出错 等等。

把以上问题全部解决就行了么?当然不行,Java是面向对象编程。

        

三、简单工厂模式

3.1 面向对象编程

    面向对象编程是一种基于对象和类的编程方法,它将数据和操作数据的方法封装在一起,以创建对象。在Java中,你可以通过类、对象、封装、继承和多态来构建复杂的软件系统。这些概念使得代码更具可维护性、可重用性和扩展性,是Java编程语言的重要特征之一。

3.1.2 接口

Java中的接口是一种抽象数据类型,它定义了一组方法的规范,但没有提供方法的具体实现。接口可以被类实现,一个类可以实现一个或多个接口。

在Java中,通过使用interface关键字来声明接口。接口的方法默认是publicabstract的,也就是说,接口中的方法必须是公共的和抽象的,不需要显式地声明这两个修饰符。

        

接口可以包含以下类型的成员:

  • 抽象方法:接口中的方法没有方法体,只有方法签名。
  • 默认方法:在Java 8中引入的,默认方法在接口中有一个具体的实现。实现类可以直接继承默认方法,也可以选择覆盖它们。
  • 静态方法:在Java 8中引入的,接口中的静态方法可以通过接口名称直接调用,无需通过实现类。
  • 常量:接口中可以定义常量,它们默认是publicstaticfinal的。

接口的主要作用是实现多继承或多重实现。通过实现接口,一个类可以同时拥有多个接口定义的行为,并且可以在不同的类之间共享和重用代码。一个类可以实现多个接口,但只能继承一个类。

        

3.1.2 面向接口编程

Java面向接口编程是一种编程思想和重要的原则,它强调程序设计应该以接口为基础进行。这种编程方式的关键思想是将接口作为代码组织和交互的核心,而不是将具体的实现细节暴露给调用者。

在面向接口编程中,接口是一种契约,它定义了一组方法的规范。类可以实现接口,以表明它们能够提供接口中定义的行为。通过使用接口,可以减少代码之间的耦合性,并提高代码的可读性、可维护性和可扩展性。      

面向接口编程的优点包括:

  1. 扩展性:通过定义接口,可以方便地添加新的实现类,从而提供更多的功能扩展点。
  2. 可替换性:由于面向接口编程的关注点是接口而不是具体实现,所以可以方便地替换实现类,以满足不同的需求和场景。
  3. 可测试性:接口的抽象性使得可以更容易地对代码的不同部分进行单元测试和模拟。
  4. 代码复用性:通过多个类实现同一个接口,可以实现代码逻辑的复用。
  5. 降低耦合性:通过依赖于接口而不是具体的实现类,可以降低代码之间的耦合性,提高系统的灵活性和可维护性。

在实践中,面向接口编程可以结合工厂模式来进一步提高代码的可扩展性和灵活性。在Java 程序设计里面,非常讲究层的划分和模块的划分,每层之间只通过接口来通信,而不需要知道具体的实现。

总的来说,接口提供了一种规范和契约的机制,用于定义类应该实现的方法,以及类们之间的协议。

                

3.2 不用设计模式解决

结构图如下

代码实现如下:

(接口)

/**
 * 运算接口 <br/>
 *
 * @author danci_
 * @date 2024/1/13 11:13:00
 */
public interface CalApi {

    /**
     * 根据传入的两个数字和运算符获得运算结果
     *
     * @param number1 数字1
     * @param number2 数字2
     * @param operator 运算符
     * @return
     */
    int cal(int number1, int number2, String operator);
}

(实现类)

/**
 * 运算实现类 <br/>
 *
 * @author danci_
 * @date 2024/1/13 11:14:46
 */
public class CalApiImpl implements CalApi {

    @Override
    public int cal(int number1, int number2, String operator) {
        switch (operator) {
            case "+": {
                return number1 + number2;
            }
            case "-": {
                return number1 - number2;
            }
            case "*": {
                return number1 * number2;
            }
            case "/": {
                if (number2 == 0) {
                    return 0;
                }
                return number1 / number2;
            }
            default: return 0;
        }    }
}

(客户端实现)

public class Client {

    public static void main(String[] args) {
        CalApi calApi = new CalApiImpl();
        calApi.cal(1, 2, "+");
    }
}

问题

    客户的这行代码 CalApi calApi = new CalApiImpl(),客户端不仅知道了接口还知道了接口具体的实现,违背面向接口编程的思想

    使用工厂模式来解决问题。

        

3.3 用简单工厂模式解决

定义⼀个创建对象的接口,让其子类⾃己决定实例化哪⼀个工厂类,⼯厂模式使其创建过程延迟到⼦子类进⾏。

解决思路

    客户端不应该知道具体的实现类,只知道接口又不应该知道具体的实现来满足业务,该怎么办?而创建接口又是需要知道实现类的。

    创建一个工厂类,由工厂类来实例化接口,对外提供能获取接口的实例对象,然后就可以操作接口的方法了。

    客户端通过工厂类来获取接口对象来调接口对应的方法。如此,实现了客户端不需要知道具体的接口实现了。

        

3.3.1 工厂模式结构及说明

  • Api:定义客户所需要的功能接口。
  • Impl:具体实现Api 的实现类,可能会有多个。

  • Fact ory: 工厂,选择合适的实现 类来创建Api 接又对象。

  • Client:客户端,通过Factory 来获取Api接又对象,然后面向Api接又编程。

代码实现如下:

  定义接口,代码如下:

public interface CalApi {

    /**
     * 根据传入的两个数字进行运算
     *
     * @param number1 数字1
     * @param number2 数字2
     * @return
     */
    int cal(int number1, int number2);
}

         

  运算实现类,代码如下:

public class AdditionCalApi implements CalApi {

    /**
     * 获取数字number1 + 数字number2的结果
     * 
     * @param number1 数字1
     * @param number2 数字2
     * @return int 加法运算结果
     */
    @Override
    public int cal(int number1, int number2) {
        return number1 + number2;
    }
}
public class SubtractionCalApi implements CalApi {

    /**
     * 获取数字number1 - 数字number2的结果
     *
     * @param number1 数字1
     * @param number2 数字2
     * @return
     */
    @Override
    public int cal(int number1, int number2) {
        return number1 - number2;
    }
}

        

  创建工厂类,代码如下:

public class Factory {

    public static CalApi getCalApi(String operator) {
        switch (operator) {
            case "+": {
                return new AdditionCalApi();
            }
            case "-": {
                return new SubtractionCalApi();
            }
            default: return null;
        }
    }
}

        

  客户端如何使用工厂?客户端就不用再自己去创建接口的对象了,应该使用工厂来获取 。 经过改造,客户端代码如下:

public class Client {

    public static void main(String[] args) {
        CalApi calApi1 = Factory.getCalApi("+");
        int rs1 = calApi1.cal(12, 55);
        System.out.println(rs1);

        CalApi calApi2 = Factory.getCalApi("-");
        int rs2 = calApi2.cal(12, 55);
        System.out.println(rs2);
    }
}

    客户端通过简单工厂创建 了一个实现接口的对象,然后面向接口编程,从客户端来看,它根本不知道具体的实现是什么,也不知道是如何实现的,它只知道通过工厂获得了一个接口对象 , 然后通过这个接口来获取想要的功能。

        

3.3.2 模式分解

  • 客户端与接口具体的实现类实现了完全的解藕。
  • 工厂类跟接口和接口的实现在一起的,是一个封装体。(如下图)

    图3 中的虚线框,就好比是一个组件的包装边界,表示接口、实现类和工厂类组合成了一 个组件。在这个封装体里面,只有接口和工厂是对外的,也就是让外部知道并使用的 ,所以故意漏了一些在虚线框外,而具体的实现类是不对外的,被完全包含在虚线框内。

    对于客户端而言,只是知道了接口Api和简单工厂Factory,通过Factory 就可以获得Api 了,这样就达到了让Client在不知道具体实现类的情况下获取接口Api。 所以看似简单地将new Impl (这句话从客户端里面移动到了简单工厂里面,其实是有了质的变化的。

        

3.3.3 理解简单工厂模式

简单工厂模式(Simple Factory Pattern)属于创建型设计模式之一,其核心思想是通过一个专门的工厂类来负责创建其他类的实例,将实例的创建与使用解耦,减少客户端直接创建对象的责任。

  简单工厂模式通常涉及以下三个角色

  1. 工厂角色(Factory):这是简单工厂模式的核心,含有一个创建产品的方法,客户端调用这个方法来请求产品。根据传入的参数,工厂决定创建哪一种产品。

  2. 抽象产品角色(Product):这是工厂需要创建的所有对象的父类或接口,通常是一个抽象类或接口,定义了产品的公共接口。

  3. 具体产品角色(Concrete Product):工厂方法创建的具体实例,这些产品是继承自抽象产品或实现了产品接口的类。

  简单工厂模式的核心思想可以概括为:

  • 集中管理:将对象的创建集中到一个位置,便于管理和维护。

  • 解耦:减少系统中的代码耦合,使用者不需要知道具体的产品类名,只需要知道工厂类和产品的抽象接口。

  • 易于扩展:增加新的产品类时,只需在工厂类中新增相应的创建逻辑即可,对其他类的修改较小,遵循开闭原则(在扩展时,不需要修改现有代码,只需要增加新的代码)。

  但是,简单工厂模式也有其局限性

  • 工厂类的职责相对比较重,如果产品种类非常多,工厂方法会变得非常复杂。
  • 当增加新产品时,需要修改工厂类,这违反了开闭原则(对扩展开放,对修改封闭)。

        

3.4 简单工厂模式优缺点

  优点:

  • 帮助封装:简单工厂虽然很简单,但是非常友好帮我们实现了组件的封装,然后让组件外部能真正面向接口编程。
  • 解耦:通过简单工厂,实现了客户端和具体实现类的解耦。如同上面的例子,客户端根本就不知道具体是由谁来实现,也不知道具体是如何实现的,客户端只是通过工厂获取它需要的接口对象。

  缺点:

  • 可能增加客户端的复杂度:如果通过客户端的参数来选择具体的实现类,那么就必须让客户端能理解各个参数所代表的具体功能和含义,这样会增加客户端使用的难度,也部分暴露了内部实现,这种情况可以选用可配置的方式来实现。

  • 不方便扩展子工厂:私有化简单工厂的构造方法,使用静态方法来创建接口,也就不能通过写简单工厂类的子类来改变创建接口的方法的行为了。不过,通常情况下是不需要为简单工厂创 建子类的。

        

3.5 思考简单工厂模式

3.5.1 本质

筒单工厂的本质是:选择实现。

    简单工厂的重点在选择,实现是已经做好了的。就算实现再简单,也要由具体的实现类来实现,而不是在简单工厂里面来实现。简单工厂的目的在于为客户端来选择相应的实现,从而使得客户端和实现之间解耦。这样一来,具体实现发生了变化,就不用变动客户端了,这个变化会被简单工厂吸收和屏蔽掉。

    实现简单工厂的难点就在于 “如何选择” 实现,前面便子中传递参数的方法, 那都是静态的参数,还可以实现成为动态的参数。比如,在运行期间,由工厂去读取某个内存的值,或者是去读取数据库中的值,然后根据这个值来选择具体的实现等。

        

3.5.2 何时选用简单工厂模式

  建议在以 下情况中选用简单工厂:

  • 如果想要完全封装隔离具体实现,让外部只能通过接又来操作封装体,那么可 以选用简单工厂,让客户端通过工厂来获取相应的接又,而无须关心具体的实现。
  • 如果想要把对外创建对象的职责集中管理和控制,可以选用简单工厂,一个简 单工厂可以创建很多的、不相关的对象,可以把对外创建对象的职责集中到一个简单 工厂来,从而实现集中管理和控制。

        

3.6 相关设计模式结合

    简单工厂模式本身是一个非常基础的创建型模式,它是许多更复杂设计模式的起点。虽然它具有一定的局限性,但是在与其他设计模式结合使用时,它可以帮助更好地组织和管理代码。以下是几种与简单工厂模式相结合的设计模式,以及这种结合的好处:

  1. 策略模式(Strategy Pattern):
    简单工厂可以创建策略模式中的各种策略对象。策略模式允许您在运行时根据不同的情境切换算法或策略。当结合简单工厂时,您可以隐藏创造这些策略的逻辑,简化策略的更换过程,进而使得客户代码在使用时,只需要关注策略接口而不是实现。

  2. 工厂方法模式(Factory Method Pattern):
    虽然简单工厂模式不是工厂方法模式,但是它可以被视为是工厂方法模式的一种特例,当只有一个具体工厂类时。如果产品的创建逻辑比较简单,且不需要扩展额外的工厂类,使用简单工厂可能更为简便。

  3. 单例模式(Singleton Pattern):
    简单工厂和单例模式可以结合起来用于确保特定类型只有一个实例被创建。例如,简单工厂可以返回应用程序中唯一的数据库连接实例或配置对象,从而保证资源的统一管理。

  4. 外观模式(Facade Pattern):
    简单工厂可能被用于实现一个外观类的一部分,这个外观类提供了一个简化的接口,用于隐藏更复杂的子系统。外观模式经常与简单工厂一起使用,进一步简化客户端和子系统之间的交互。

  5. 适配器模式(Adapter Pattern):
    当需要提供多个适配器类的实例时,简单工厂可以帮助创建这些类,无论是对象适配器还是类适配器,简单工厂都可以根据不同情况和需求来创建合适的适配器实例。

  6. 建造者模式(Builder Pattern):
    在某些情况下,可以使用简单工厂来选择并创建具体的建造者实例。建造者模式通常用于创建复杂的对象,其中对象的创建过程需要多个步骤和过程。简单工厂可用于封装这一选择过程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541333.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

传输层协议——UDP/TCP协议

目录 端口号 端口号范围 pidof UDP协议 UDP协议格式 UDP特点 UDP缓冲区 UDP的注意事项 基于UDP的应用层协议 TCP协议 TCP协议格式 序号与确认序号 窗口大小 6个标记位 紧急指针 确认应答机制 连接管理机制 三次握手 四次挥手 超时重传机制 流量控制 滑动…

java使用ShutdownHook优雅地停止服务

在Java程序中可以通过添加关闭钩子&#xff0c;实现在程序退出时关闭资源、平滑退出的功能。 使用Runtime.addShutdownHook(Thread hook)方法&#xff0c;可以注册一个JVM关闭的钩子&#xff0c;这个钩子可 这通常用于确保在应用程序退出时能够执行一些清理工作&#xff0c;比…

KVM + GFS 分布式存储

目录 一、案例分析 1.1、案例概述 1.2、案例前置知识点 1&#xff09;Glusterfs 简介 2&#xff09;Glusterfs 特点 1.3、案例环境 1&#xff09;案例环境 2&#xff09;案例需求 3&#xff09;案例实现思路 二、案例实施 2.1、安装部署 KVM 虚拟化平台 1&…

【Web】DASCTF 2023 0X401七月暑期挑战赛题解

目录 EzFlask MyPicDisk ez_cms ez_py 让俺看看401web题 EzFlask 进来直接给了源码 import uuidfrom flask import Flask, request, session from secret import black_list import jsonapp Flask(__name__) app.secret_key str(uuid.uuid4())def check(data):for i i…

亚远景科技-ASPICE 4.0-HWE硬件过程的范围 The Technical Scope of HW process

ASPICE 4.0中的HWE process是电气和电子硬件的技术范畴&#xff0c;涵盖了硬件工程中的需求分析、设计和验证活动&#xff0c;但不包括以下活动&#xff1a; 1. 系统级工程过程。既不包括机电一体MECHATRONIC&#xff0c;也不包括ECU特定电子控制单元的开发。 2. 硬件采购过程…

叉车载货出入库AI检测算法介绍及应用

随着物流行业的快速发展&#xff0c;叉车作为物流运输的重要设备&#xff0c;其安全性和效率性越来越受到人们的关注。然而&#xff0c;在实际操作中&#xff0c;由于人为因素和操作环境的复杂性&#xff0c;叉车事故时有发生&#xff0c;给企业和个人带来了巨大的损失。为了提…

部署Kafka集群图文详细步骤

1 集群规划 共三台虚拟机同处overlay网段&#xff0c;每台虚拟机部署一套kafka和zookeeper&#xff0c;kafka_manager安装其中一台虚拟机上即可。 HostnameIP addrPortListenerzk1docker-swarm分配2183:2181zk2docker-swarm分配2184:2181zk3docker-swarm分配2185:2181k1docke…

word从零基础到高手【办公】

第1课 - word基础操作快速入门第2课 - 让你效率10倍提升的快捷操作第3课 - word排版快速入门第4课 - 排版实战案例讲解第5课 - 搞定论文排版全过程第6课 - 让你的word更强大的神技第7课 - 提高工作效率必备的批量操作 资料截图如下: 发送: "word办公" 获取提取码

基于ssm的土家风景文化管理平台(java源码+文档)

项目简介 土家风景文化管理平台实现了以下功能&#xff1a; 土家风景文化管理平台的主要使用者分为管理员&#xff1a;管理员使用本平台涉到的功能主要有&#xff1a;首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;景点分类管理&#xff0c;热门景点管理&#xf…

海康4G摄像机国标注册失败,接入国标28181视频监控平台失败的问题分析、排查、解决

目录 一、问题现象 &#xff08;一&#xff09;背景 &#xff08;二&#xff09;在平台端&#xff0c;设备显示在线&#xff0c;通道不能传到平台端 &#xff08;二&#xff09;直接把通道接入进来&#xff0c;查看是否&#xff0c;显示请求超时 二、问题分析 &#xff0…

IntelliJ IDE 插件开发 | (九)实现 Unicode 字符折叠预览

系列文章 本系列文章已收录到专栏&#xff0c;交流群号&#xff1a;689220994&#xff0c;也可点击链接加入。 前言 在上一篇文章中我们介绍了如何实现 i18n 的方式&#xff0c;其中提到官方建议我们在编写语言文件时将 ASCII 码范围外的字符都使用 Unicode 编码进行表示&am…

【vue3-pbstar-books】大学生前端期末作业(vue3、element-plus、ts、pinia、vite、json-server)

一、项目要求 二、项目介绍 vue3-pbstar-books是一个图书主题的pc端网站&#xff0c;该项目有首页、全部书籍页、书籍分类页、书籍详情页和关于页五个页面。该方案结合了 Vue3、Element-Plus、TypeScript、Pinia 和 Vite 等先进技术&#xff0c;实现高效的页面布局、状态管理和…

基于ssm的校园短期闲置资源置换平台(java项目+文档+源码)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的校园短期闲置资源置换平台。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 校园短期闲置资源置换…

软考 - 系统架构设计师 - 面向对象架构设计案例

问题1&#xff1a; 解决该题&#xff0c;用例和参与者要一起进行分析&#xff0c;首先看到用例 U1 和 U2 是 U3 的扩展&#xff0c;分析用例列表中的用例&#xff0c;可以分析出 U1 和 U2 是Underpaid transaction 和 Record lllegal use&#xff0c;顺序可以颠倒&#xff0c;…

Unity绘制地图

首先在项目/Assets文件夹下创建一个Tiles文件夹 在层级下点击鼠标右键选择2D对象选择瓦片地图创建Tilemap。 选择地图素材 如果素材需要裁剪&#xff0c;在检查器Sprite模式选择多个&#xff0c;点击Sprite Editor,选择切 &#xff0c;选择类型Grid By Cell Count&#xff0c;…

Windows server SMB服务 文件夹访问缓慢 解决方法

Windows server用了很久&#xff0c;一直有个问题没有解决&#xff0c;就是用手机访问SMB时&#xff0c;文件夹列出速度非常慢&#xff0c;今天去翻阅了一下官方文档&#xff0c;找到了解决办法。 更改注册表SMB服务的工作进程数 HKLM\System\CurrentControlSet\Control\Sessi…

【PHP系统学习】——Laravel框架数据库的连接以及数据库的增删改查的详细教程

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

【C++成长记】C++入门 |函数重载、引用、内联函数

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;C❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、函数重载 1、函数重载概念 二、引用 1、引用概念 2、引用特性 3、常引用 4、使用场景 5、…

2024年MathorCup数学建模A题移动通信网络中PCI规划问题解题文档与程序

2024年第十四届MathorCup高校数学建模挑战赛 A题 移动通信网络中PCI规划问题 原题再现&#xff1a; 物理小区识别码(PCI)规划是移动通信网络中下行链路层上&#xff0c;对各覆盖小区编号进行合理配置&#xff0c;以避免 PCI 冲突、PCI 混淆以及 PCI 模3 千扰等现象。PCI 规划…

pycharm2024关闭项目后一直显示正在关闭项目

网上的很多教程都试了不行&#xff0c;直接用下面的方法有效解决。 点击 帮助--查找操作--输入Registry--点注册表&#xff0c;取消ide.await.scope.completion后的勾选即可。