java设计模式学习之【工厂模式】

news2024/11/17 19:30:17

文章目录

  • 引言
  • 工厂方法模式简介
    • 定义与用途:
    • 实现方式:
  • 使用场景
  • 优势与劣势
  • 工厂模式在spring中的应用
  • 电费计算示例(简单工厂模式)
  • 改善为方法工厂模式
  • 代码地址

引言

在软件开发的世界中,对象的创建可能是一个复杂且重复的过程。为了简化这个过程,设计模式中的“工厂方法”就像一个小工厂,专门负责生产特定类型的对象。今天,我们来深入探索这个设计模式,看看它是如何让对象的创建变得简单又有趣。

工厂方法模式简介

工厂方法模式是一种创建型设计模式。 它通过使用一个工厂类来创建对象,而不是直接使用 new 运算符。这使得程序可以在不知道对象确切类型的情况下,生成对象的实例。

定义与用途:

  1. 工厂设计模式是一种创建型设计模式,广泛应用于JDK和像Spring、Struts这样的框架中。
  2. 当有一个超类和多个子类,并且基于输入返回其中一个子类时,使用工厂设计模式是非常合适的。

实现方式:

通过将类的实例化过程从客户端代码转移到工厂类,从而减少客户端的复杂性。

使用场景

  • 当类的实例化过程复杂,需要依据不同的条件来创建不同的对象时。
  • 当需要解耦对象的创建和使用时。
  • 在提供一个类库,并希望只暴露接口而非实现细节时。

优势与劣势

  • 优势
    提高灵活性:可以在运行时选择创建哪个类的实例。
    降低耦合度:客户端代码与具体类的创建过程解耦。
    易于扩展:添加新的类不影响现有代码。
  • 劣势
    增加代码复杂性:可能会引入许多新类,增加系统的复杂性。
    维护难度:当添加新类型时,可能需要修改工厂类。

工厂模式在spring中的应用

Spring框架广泛地应用了工厂模式,这是Spring框架中对象管理和依赖注入核心功能的基础。以下是Spring框架中使用工厂模式的几个关键地方:

BeanFactory:
Spring框架中最基本的容器,它提供了依赖注入(DI)的支持。
BeanFactory 使用工厂模式来实例化应用程序中的所有bean。
它使用 getBean 方法来创建bean实例。

ApplicationContext:
它是 BeanFactory 的子接口,提供了更高级的特性,如事件传播、资源加载等。
ApplicationContext 本身也是一个大型工厂,用于创建并管理应用程序中的beans,以及提供对不同类型的bean的访问。

FactoryBean:
Spring中特殊的bean类型,用于产生其他bean实例。
这种模式允许用户实现复杂的初始化逻辑,并通过Spring容器进行管理。

BeanDefinition:
在Spring中,BeanDefinition 代表了bean的配置元数据,它将如何在Spring容器中创建bean的细节描述了出来。
通过这种方式,Spring使用工厂模式来创建具体的bean实例。

单例模式与工厂模式的结合:
默认情况下,Spring容器中的所有bean都是单例的,这意味着每个bean都是全局唯一的并且在整个应用程序中共享。
Spring容器作为工厂,管理着这些单例bean的生命周期和实例化过程。

依赖注入(DI):
虽然DI不是工厂模式,但它利用了工厂模式的概念来实现对象的创建和依赖的注入。
DI容器(如 Ap	plicationContext)负责创建对象和管理它们的依赖关系,这在本质上是一种工厂模式的应用。

电费计算示例(简单工厂模式)

我们将创建一个名为 Plan 的抽象类以及继承该抽象类的具体类。下一步是定义一个名为 GetPlanFactory 的工厂类。
GenerateBill 类将使用 GetPlanFactory 来获取一个 Plan 对象。它将传递信息(DOMESTICPLAN / COMMERCIALPLAN / INSTITUTIONALPLAN)给 GetPlanFactory,以获取它所需的对象类型。
在这里插入图片描述

步骤 1: 创建抽象计划类
首先,我们定义一个抽象类 Plan,它包含了计算电费所必需的方法和属性。

abstract class Plan {
    protected double rate;
    abstract void getRate();

    public void calculateBill(int units) {
        System.out.println(units * rate);
    }
} //end of Plan class.

步骤 2: 定义具体计划类
接着,我们创建具体类 DomesticPlan、CommercialPlan 和 InstitutionalPlan,这些类继承自 Plan 并提供了 getRate 方法的具体实现。

class DomesticPlan extends Plan {
    public void getRate() {
        rate = 3.50;
    }
} //end of DomesticPlan class.

class CommercialPlan extends Plan {
    public void getRate() {
        rate = 7.50;
    }
} //end of CommercialPlan class.

class InstitutionalPlan extends Plan {
    public void getRate() {
        rate = 5.50;
    }
} //end of InstitutionalPlan class.

步骤 3: 创建工厂类
GetPlanFactory 是一个工厂类,根据传入的计划类型生成相应的计划对象。

class GetPlanFactory {
    public Plan getPlan(String planType) {
        if (planType == null) {
            return null;
        }
        if (planType.equalsIgnoreCase("DOMESTICPLAN")) {
            return new DomesticPlan();
        } else if (planType.equalsIgnoreCase("COMMERCIALPLAN")) {
            return new CommercialPlan();
        } else if (planType.equalsIgnoreCase("INSTITUTIONALPLAN")) {
            return new InstitutionalPlan();
        }
        return null;
    }
} //end of GetPlanFactory class.

步骤 4: 生成账单
GenerateBill 类使用 GetPlanFactory 来获取具体的计划对象,并根据使用的单位数计算电费。

class GenerateBill {
    public static void main(String args[]) throws IOException {
        GetPlanFactory planFactory = new GetPlanFactory();

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Enter the name of plan for which the bill will be generated: ");
        String planName = br.readLine();
        System.out.print("Enter the number of units for bill will be calculated: ");
        int units = Integer.parseInt(br.readLine());

        Plan p = planFactory.getPlan(planName);
        System.out.print("Bill amount for " + planName + " of " + units + " units is: ");
        p.getRate();
        p.calculateBill(units);
    }
} //end of GenerateBill class.

以上就是一个简单的工厂模式示例代码,运行代码我们可以看到:
输入相应的计划就可以算出该类型下具体的电费。
在这里插入图片描述

改善为方法工厂模式

当新的计划类型增加时,GetPlanFactory 就需要修改。这违反了开闭原则(对扩展开放,对修改封闭)。
以上举例属于简单工厂模式接下来改为方法工厂模式。

改造步骤

  • 创建一个抽象的工厂类或接口。
  • 为每种计划类型创建具体的工厂类,继承自抽象工厂类或实现工厂接口。
  • 每个具体工厂类实现创建相应产品对象的方法。
public abstract class GetPlanFactoryPro {
    abstract Plan getPlan();
}

class DomesticPlanFactory extends GetPlanFactoryPro {
    @Override
    Plan getPlan() {
        return new DomesticPlan();
    }
}

class CommercialPlanFactory extends GetPlanFactoryPro {
    @Override
    Plan getPlan() {
        return new CommercialPlan();
    }
}

class InstitutionalPlanFactory extends GetPlanFactoryPro {
    @Override
    Plan getPlan() {
        return new InstitutionalPlan();
    }
}

调用方法:

public class GenerateBillPro {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("Enter the name of plan for which the bill will be generated: ");
        String planName = br.readLine();
        System.out.print("Enter the number of units for bill will be calculated: ");
        int units = Integer.parseInt(br.readLine());

        GetPlanFactoryPro factory = getFactory(planName);
        if (factory == null) {
            System.out.println("Invalid Plan Type");
            return;
        }

        Plan p = factory.getPlan();
        System.out.print("Bill amount for " + planName + " of " + units + " units is: ");
        p.getRate();
        p.calculateBill(units);
    }

    private static GetPlanFactoryPro getFactory(String planType) {
        if (planType.equalsIgnoreCase("DOMESTICPLAN")) {
            return new DomesticPlanFactory();
        } else if (planType.equalsIgnoreCase("COMMERCIALPLAN")) {
            return new CommercialPlanFactory();
        } else if (planType.equalsIgnoreCase("INSTITUTIONALPLAN")) {
            return new InstitutionalPlanFactory();
        }
        return null;
    }

}

**灵活性和扩展性:**通过使用工厂方法模式,我们增加了代码的灵活性和扩展性。如果要添加新的计划类型,只需增加一个新的工厂类,而无需修改现有的工厂逻辑或客户端代码。
**符合开闭原则:**工厂方法模式使得我们的代码更好地符合开闭原则,因为现在系统可以在不修改现有代码的情况下引入新类型的Plan。

缺点:
随着产品类的增加,相关的工厂类也会增加,可能导致系统类的数量增长。

代码地址

23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NX二次开发UF_CSYS_edit_matrix_of_object 函数介绍

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan UF_CSYS_edit_matrix_of_object Defined in: uf_csys.h int UF_CSYS_edit_matrix_of_object(tag_t object_id, tag_t matrix_id ) overview 概述 Updates the specified coordinat…

杰发科技AC7801——ADC简单理解

前言 7801资料读起来不是很好理解,大概率是之前MTK的大佬写的。在此以简单的方式进行描述。我们做一个简单的规则组软件触发Demo。因为规则组通道只有一个数据寄存器,因此还需要用上DMA方式搬运数据到内存。 AC7801的ADC简介 7801的ADC是一种 12 位 逐…

7-22 龟兔赛跑

import java.util.Scanner; class Main {public static void main(String[] args) {Scanner scnew Scanner(System.in);int timesc.nextInt();sc.close();int wugui 0;//乌龟里程int tuzi 0;//兔子里程int tuzi_run0;int tuzi_rest0;int is_rest0;//是否需要休息:…

Python大语言模型实战-记录一次用ChatDev框架实现爬虫任务的完整过程

1、模型选择:GPT4 2、需求:在win10操作系统环境下,基于python3.10解释器,爬取豆瓣电影Top250的相关信息,包括电影详情链接,图片链接,影片中文名,影片外国名,评分&#x…

游戏是第一生产力!Python实现生命游戏的示例代码(tkinter版)

文章目录 生命游戏(Game of Life)游戏概述生存定律图形结构 代码实现运行界面使用简介后续改进关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③Python小游戏源码五…

【Linux】匿名管道+进程池

文章目录 前置知识一、管道的原理二、管道的特性三、管道的接口四、使用管道实现简单的进程池解决进程池的一个小问题 前置知识 一个进程在创建时,会默认打开三个文件,分别是:stdin,stdout,stderr 进程中有一个维护进…

社区物联网云服务架构设计

文章目录 1 摘要2 架构图2.1 社区物联网云服务网络拓扑图2.2 社区物联网云服务通讯流程图2.3 社区远程开锁功能流程图 3 应用场景 1 摘要 随着社区管理越来越智能化,社区物联网升级与改造的市场空间也越来越大。社区物联网包含楼宇对讲、门禁门锁、通道闸等等设备系…

浅谈国内智能制造现状和未来发展趋势

进人二十一世纪,互联网、新能源、大数据等技术的迅猛发展,从而使得社会发生巨大的改变,人类生产工业发生变革。为应对全球挑战,我国根据发展的实际情况,提出《中国制造2025》的国家战略规划。毋庸置疑的是,…

大数据题目的解题技巧

目录 大数据题目的技巧总括 实例精析 实例一 实例二 实例三 大数据题目的技巧总括 (1)哈希函数可以把数据按照种类均匀分流; (2)布隆过滤器用于集合的建立与查询,并可以节省大量空间; &…

Git永久或者限时保存用户名及密码,解决每次拉取或者提交代码时都需要手动输入验证信息

介绍 这里以我自身项目情况为例: 依据项目要求,这边使用了 TortoiseGit进行项目的统一管理,下载了 TortoiseGit克隆项目之后,每次拉取或者提交代码,都会弹出一个提示框,要求输入用户名及密码。 解决方式 单个仓库内设置,只作用于对当前仓库 在当前项目目录文件夹下,…

vue3之echarts渐变柱状图

vue3之echarts渐变柱状图 效果&#xff1a; 核心代码&#xff1a; <template><div class"abnormal"><div class"chart" ref"chartsRef"></div></div> </template><script setup> import * as echa…

【EI会议征稿】第三届电子信息技术国际学术会议(EIT 2024)

The 3rd International Conference on Electronic Information Technology 第三届电子信息技术国际学术会议&#xff08;EIT 2024&#xff09; 电子信息工程在我国信息化产业的发展过程中举足轻重&#xff0c;且随着现代社会的发展&#xff0c;航空航天领域、制造业领域和智能…

2024年度投资策略:AI大模型和半导体国产化加速

今天分享的是AI系列深度研究报告&#xff1a;《2024年度投资策略&#xff1a;AI大模型和半导体国产化加速》。 &#xff08;报告出品方&#xff1a;东方证券&#xff09; 报告共计&#xff1a;48页 前言: 行情回顾与未来展望 电子板块涨幅转正&#xff0c;信心逐渐回归。截至…

7000家门店的盈利增长,从导购的人效提升开始

管理是艺术&#xff0c;还是科学&#xff1f; 说管理是艺术&#xff0c;是因为管理面向的是人&#xff0c;而人是动态复杂的&#xff1b;说管理是科学&#xff0c;是因为我们可以研究动态的人背后的共性需求&#xff0c;并使管理的模型、策略、工具与之契合。 在绫致时装看来…

搭建Angular并引入NG-ZORRO组件库

作者&#xff1a;baekpcyyy&#x1f41f; 1.安装node.js 注&#xff1a;安装 16.0 或更高版本的 Node.js node官网&#xff1a;https://nodejs.org/en 2.进入angular官网 https://angular.cn/guide/setup-local 新建一个文件夹 vsc打开 打开终端 1.首先安装angular手脚架…

静电放电模型中的阻容参数

依据静电放电产生原因及其对集成电路放电方式的不同&#xff0c;静电放电模型可分成以下四类模型&#xff1a;1、人体放电模型(HBM, Human-Body Model)、2、机器放电模型(MM, Machine Model)、3、器件充电模型(CDM, Charged-Device Model)、4、电场感应模型(FIM, Field-Induced…

从设计上理解JDK动态代理

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 照理说&#xff0c;动态…

【Django-DRF】md笔记第6篇:Django-DRF的视图、认证、分页和其他功能详解

本文从分析现在流行的前后端分离Web应用模式说起&#xff0c;然后介绍如何设计REST API&#xff0c;通过使用Django来实现一个REST API为例&#xff0c;明确后端开发REST API要做的最核心工作&#xff0c;然后介绍Django REST framework能帮助我们简化开发REST API的工作。 DR…

win10 tensorrt源码编译onnx

直接利用官方源码&#xff0c;如下图&#xff0c;trtexec源码在TensorRT安装目录下&#xff0c;双击trtexec.sln文件&#xff0c;使用vs2019打开源码工程。 如下图&#xff0c;以yolov8为例子&#xff0c;编译成功项目之后&#xff0c;设置命令行参数&#xff1a; --onnxd:/yo…

表单邮箱密码登录 原生+Jquery实现

文章目录 效果代码邮箱验证正则表达式HTMLCSS JS 效果 正确密码为&#xff1a;123456 点击登录按钮校验。 代码 表单校验 - CodeSandbox 邮箱验证正则表达式 /(?:[a-z0-9!#$%&*/?^_{|}~-](?:\.[a-z0-9!#$%&*/?^_{|}~-])*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1…