金三银四面试题(二十二):工厂模式知多少?

工厂模式在软件设计中是非常重要的,它提供了一种灵活的方法来创建对象,有助于降低代码的耦合度,提高代码的可维护性和可扩展性。同样也是面试中的高频考点。

什么是工厂模式

工厂模式是一种常用的软件设计模式,用于创建对象。它属于创建型设计模式,主要用于处理对象的创建而无需指定具体类。工厂模式通过定义一个创建对象的接口,但让子类决定实例化哪个类来创建对象。这样,客户端代码就不需要知道实际要实例化的类,只需要知道使用的是工厂方法即可。

工厂模式的几个重要优点:

  1. 降低耦合度:工厂模式将对象的创建和使用分离开来,客户端代码不需要直接依赖于具体的类,而是依赖于抽象的接口或基类,从而减少了对象之间的耦合度。

  2. 提高可维护性:由于工厂模式使得对象的创建集中在工厂类中,当需要修改对象创建逻辑时,只需要修改工厂类而不影响客户端代码,这样就提高了代码的可维护性。

  3. 增加灵活性:工厂模式可以根据需求灵活地创建不同类型的对象,而且可以通过配置或者运行时动态决定创建哪种类型的对象,从而增加了系统的灵活性。

  4. 提高代码的可扩展性:当需要添加新的产品类时,只需要添加相应的具体产品类和对应的具体工厂类,而不需要修改现有的代码,这样就提高了系统的可扩展性。

  5. 促进代码的重用:工厂模式可以将对象的创建逻辑封装在工厂类中,这样可以在不同的地方重复使用相同的创建逻辑,提高了代码的重用性。

工厂模式有三种主要的实现方式:

  1. 简单工厂模式(Simple Factory Pattern):由一个工厂类根据传入的参数,决定创建哪一种产品类的实例。这种模式只有一个工厂类。
  2. 工厂方法模式(Factory Method Pattern):定义一个用于创建对象的接口,但是将实际创建工作推迟到子类中。每个子类都可以实现这个工厂方法以提供对象的实例化。
  3. 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。通常,这种模式涉及一个工厂接口和多个具体工厂类,每个具体工厂类负责实例化一组相关的对象。

这些工厂模式的选择取决于具体的需求和设计情况。在大型软件系统中,工厂模式可以帮助降低代码的耦合度,提高代码的可维护性和可扩展性。

简单工厂模式

简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。比如,一台咖啡机就可以理解为一个工厂模式,你只需要按下想喝的咖啡品类的按钮(摩卡或拿铁),它就会给你生产一杯相应的咖啡,你不需要管它内部的具体实现,只要
告诉它你的需求即可。

优点:

  • 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象;
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;
  • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

缺点:

不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑;
产品类型较多时,工厂的创建逻辑可能过于复杂,一旦出错可能造成所有产品的创建失败,
不利于系统的维护。

实现

这里实现一个简单的咖啡机

// 咖啡接口
interface Coffee {
    void brew();
}

// 具体的咖啡类:美式咖啡
class Americano implements Coffee {
    @Override
    public void brew() {
        System.out.println("冲一杯美式咖啡");
    }
}

// 具体的咖啡类:拿铁咖啡
class Latte implements Coffee {
    @Override
    public void brew() {
        System.out.println("冲一杯拿铁咖啡");
    }
}

// 咖啡机工厂类
class CoffeeMachine {
    // 根据咖啡类型生产咖啡
    public Coffee makeCoffee(String type) {
        if (type.equalsIgnoreCase("americano")) {
            return new Americano();
        } else if (type.equalsIgnoreCase("latte")) {
            return new Latte();
        } else {
            System.out.println("不支持的咖啡类型");
            return null;
        }
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        CoffeeMachine coffeeMachine = new CoffeeMachine();

        // 制作美式咖啡
        Coffee americano = coffeeMachine.makeCoffee("americano");
        if (americano != null) {
            americano.brew();
        }

        // 制作拿铁咖啡
        Coffee latte = coffeeMachine.makeCoffee("latte");
        if (latte != null) {
            latte.brew();
        }

        // 制作不支持的咖啡类型
        Coffee cappuccino = coffeeMachine.makeCoffee("cappuccino");
        if (cappuccino != null) {
            cappuccino.brew();
        }
    }
}

抽象工厂

抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。

比如,以上面的咖啡工厂为例,某天我的口味突然变了,不想喝咖啡了想喝啤酒,这个时候如果直接修改简单工厂里面的代码,这种做法不但不够优雅,也不符合软件设计的“开闭原则” ,因为每次新增品类都要修改原来的代码。这个时候就可以使用抽象工厂类了,抽象工厂里只声明方法,具体的实现交给子类(子工厂)去实现,这个时候再有新增品类的需求,只需要新创建代码即可。

// 抽象产品接口:饮料
interface Drink {
    void consume();
}

// 具体产品:咖啡
class Coffee implements Drink {
    @Override
    public void consume() {
        System.out.println("喝咖啡");
    }
}

// 具体产品:啤酒
class Beer implements Drink {
    @Override
    public void consume() {
        System.out.println("喝啤酒");
    }
}

// 抽象工厂接口:饮料工厂
interface DrinkFactory {
    Drink createDrink();
}

// 具体工厂:咖啡工厂
class CoffeeFactory implements DrinkFactory {
    @Override
    public Drink createDrink() {
        return new Coffee();
    }
}

// 具体工厂:啤酒工厂
class BeerFactory implements DrinkFactory {
    @Override
    public Drink createDrink() {
        return new Beer();
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 制作咖啡
        DrinkFactory coffeeFactory = new CoffeeFactory();
        Drink coffee = coffeeFactory.createDrink();
        coffee.consume(); // 输出:喝咖啡
        
        // 制作啤酒
        DrinkFactory beerFactory = new BeerFactory();
        Drink beer = beerFactory.createDrink();
        beer.consume(); // 输出:喝啤酒
    }
}

spring和工厂模式

在 Spring 框架中,工厂模式被广泛应用。Spring 提供了多种类型的工厂模式,其中最常见的是上面提到的工厂方法模式和抽象工厂模式的应用。

  1. 工厂方法模式(Factory Method Pattern)

    Spring 中最常见的工厂模式应用就是工厂方法模式。在 Spring 中,Bean 的创建和管理由容器来完成,容器根据配置文件中的信息来创建 Bean,并将它们装配到需要它们的地方。这里的 BeanFactory 就是一个典型的工厂,它负责根据配置信息来创建具体的 Bean 实例。例如,ApplicationContext 接口就是 Spring 的 IoC 容器,它负责管理 Bean 的生命周期,并且提供了多种获取 Bean 实例的方法,比如 getBean() 方法。

  2. 抽象工厂模式(Abstract Factory Pattern)

    Spring 还使用了抽象工厂模式来创建相关的 Bean。在 Spring 中,BeanFactory 可以是一个具体工厂,负责创建一组相关的 Bean,这些 Bean 可能有一定的关联关系。例如,DataSource 接口就是 Spring 中的一个抽象工厂,它定义了获取数据库连接的方法,而具体的实现可以是 BasicDataSource、DriverManagerDataSource 等,这些具体的实现都是相关的,它们都用于创建数据库连接。

工厂模式帮助我们将对象的创建和使用分离开来,从而提高了代码的灵活性和可维护性。

总结

综上所述,工厂模式在软件设计中具有重要的作用,特别是在大型软件系统中,它可以帮助提高代码的质量和可维护性,减少代码的重复和耦合,从而使得系统更加灵活和可扩展。

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

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

相关文章

实验二: ping命令的使用

1.实验环境 同实验案例一环境 2.需求描述 熟悉ping命令的用法并熟悉ping命令的各种参数 3.推荐步骤 分别ping一个存在的和不存在的P 地址,观察返回的信息分别测试ping命令的相关参数 4.实验步骤 4.1、分别ping一个存在的和不存在的IP 地址 C:\>ping 192.1…

C语言如何使⽤指针?

一、问题 指针变量在初始化以后就可以使⽤和参与操作了,那么就要⽤到对指针变量最常⽤的两个操作符——> * 和 & 。 二、解答 这⾥⼜要提到始终贯穿着指针的⼀个符号“ * ”,但是这⾥的“ * ”是作为指针运算符使⽤的,叫做取内…

8个十分受小企业欢迎的电子商务网站制作工具,自助建站,一键生成免安装

如果您的小型企业需要一个网站,通常会考虑使用自助建站系统来构建与自己业务有关的电子商务站或小程序商城。 在这个时代,电子商务不仅迅速成为许多网站上的热门功能,而且几乎成为许多企业生存的必要条件,因为越来越多的人将大部分…

【C++】list的介绍及使用说明

目录 00.引言 01.list的介绍 模版类 独立节点存储 list的使用 1.构造函数 2.迭代器的使用 分类 运用 3.容量管理 empty(): size(): 4.元素访问 5.增删查改 00.引言 我们学习数据结构时,学过两个基本的数据结构:顺序表和链表。顺…

华为机考入门python3--(16)牛客16-购物单最大满意度

分类:动态规划,组合,最大值,装箱问题 知识点: 生成递减数 100, 90, 80, ..., 0 range(100, -1, -10) 访问列表的下标key for key, value in enumerate(my_list): 动态规划-捆绑装箱问题 a. 把有捆绑约束的物…

【技术变现之道】如何打造IT行业的超级个体?

前言 在当今的数字化时代,IT行业蓬勃发展,为具备技术专长的个人提供了无限的可能性。想要成为IT行业的超级个体,实现知识与技能的变现吗?以下是一些高效途径,助你一臂之力! 1. 独立接单外包 1&#xff09…

Flask项目在Pycharm中设置局域网访问

打开PyCharm导入本应用。点击Run标签中的Edit Configurations 其中Target type选择Script path,Target填入本项目中app.py的路径,Additional optional填入--host0.0.0.0(不要有空格)。 再重新运行项目,会观察到除了原本的http://127.0.0.1:50…

上线流程及操作

上节回顾 1 搜索功能-前端:搜索框,搜索结果页面-后端:一种类型课程-APIResponse(actual_courseres.data.get(results),free_course[],light_course[])-搜索,如果数据量很大,直接使用mysql,效率非常低--》E…

分类预测 | Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量机数据分类预测

分类预测 | Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量机数据分类预测 目录 分类预测 | Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量机数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现PSO-LSSVM粒子群算法优化最小二乘支持向量…

FebHost:注册.CA域名的企业有什么限制?

在加拿大,只要满足加拿大互联网注册管理局的“加拿大注册要求”,任何类型的企业都可以注册.CA域名。这些要求的目的是为了确保.CA域名空间作为一个重要的公共资源得到合理的使用和开发,以促进所有加拿大人的社会和经济发展。 以下是一些主要…

0418WeCross搭建 + Caliper测试TPS

1. 基本信息 虚拟机名称:Pure-Ununtu18.04 WeCross位置:/root/wecross-demo 2. 搭建并启动WeCross 参考官方指导文档 https://wecross.readthedocs.io/zh-cn/v1.2.0/docs/tutorial/demo/demo.html 访问WeCross网页管理平台 http://localhost:8250/s/…

嵌入式科普(15)小米su7成本分析和拆解之智驶、座舱分析

目录 一、概述 二、小米su7成本分析 2.1 整车成本构成 2.2 三电系统 2.3 车身与底盘 2.3 智能网联 2.4 内外饰 三、小米su7拆解之智驶、座舱分析 3.1 主要芯片 3.2 智能驾驶&智能座舱 四、NXP S32K324汽车通用微控制器 嵌入式科普(15)小米su7成本分析和拆解之智…

问答营销之官方号问答推广技巧

问答营销作为一种网络推广的重要手段,受到各大品牌企业的关注。实战中,问答营销有新起提问再回答和直接回复老问题两种形式,一般做企业官方号问答营销都是选择后者。这里小马识途营销顾问详细解析下开展老问题回复营销的思路和步骤。 一、分析…

2024最新大厂C++面试真题合集,玩转互联网公司面试!

小米C 1. 进程和线程的区别 进程是操作系统分配资源和调度的独立单位,拥有自己的地址空间和系统资源。线程是进程内部的执行单元,共享属于相同进程的资源,但是执行切换代价更小。进程间相互独立,稳定性较高;线程间共…

C++修炼之路之反向迭代器和非模板参数,模板特化,分离编译

目录 前言 一:反向迭代器 二:非类型模板参数 三:模板的特化 四:模板的分离编译 五:模板的优点与缺点 接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧 前言 在vector&am…

代码随想录第40天|343. 整数拆分

343. 整数拆分 343. 整数拆分 - 力扣(LeetCode) 代码随想录 (programmercarl.com) 动态规划,本题关键在于理解递推公式!| LeetCode:343. 整数拆分_哔哩哔哩_bilibili 给定一个正整数 n ,将其拆分为 k 个 正…

2024-4-18 群讨论:Java Agent,JFR 与 JIT 的一些讨论

以下来自本人拉的一个关于 Java 技术的讨论群。关注公众号:hashcon,私信进群拉你 命令行中带 -XX:StartFlightRecording 启动,同时带 -javaagent,那么谁先启动?jfr能采集到agent启动前后资源消耗情况不? 不…

基于深度学习的手写汉字识别系统(含PyQt+代码+训练数据集)

基于深度学习的手写汉字识别系统(含PyQt代码训练数据集) 前言一、数据集1.1 数据集介绍1.2 数据预处理 二、模型搭建三、训练与测试3.1 模型训练3.2 模型测试 四、PyQt界面实现参考资料 前言 本项目是基于深度学习网络模型的人脸表情识别系统&#xff0…

c++编程(6)——类与对象(4)运算符重载、赋值重载函数

欢迎来到博主的专栏——C编程 博主ID:代码小豪 文章目录 运算符重载赋值重载函数默认赋值重载函数其他运算符重载函数 运算符重载 重载这个概念在c中已经出现两次了,在前面的文章中,函数重载指的是可以用相同名字的函数实现不同的功能。而运…

【WebSocket连接异常】前端使用WebSocket子协议传递token时,Java后端的正确打开方式!!!

文章目录 1. 背景2. 代码实现和异常发现3. 解决异常3.1 从 URL入手3.2 从 WebSocket子协议的使用方式入手(真正原因) 4. 总结(仍然存在的问题) 前言: 本篇文章记录的是使用WebSocket进行双向通信时踩过的坑&#xff0c…