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

文章目录

  • 引言
  • 工厂方法模式简介
    • 定义与用途:
    • 实现方式:
  • 使用场景
  • 优势与劣势
  • 工厂模式在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 {@OverridePlan getPlan() {return new DomesticPlan();}
}class CommercialPlanFactory extends GetPlanFactoryPro {@OverridePlan getPlan() {return new CommercialPlan();}
}class InstitutionalPlanFactory extends GetPlanFactoryPro {@OverridePlan 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.hqwc.cn/news/213862.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

星河创新,开拓新纪!2023“星河产业应用创新奖”报名全面开启!

科技的浪潮汹涌而至,人工智能正悄无声息地渗透进我们生活的每一个角落,成为推动社会奔腾向前的强大引擎。 随着大模型时代到来,更多的创新者涌现出来,他们正积极探索AI与实体的深度融合,解决行业难题,开拓…

js检测dom变化的方法:MutationObserver

前言 检测一个原生dom的变化,如一个div的颜色,大小,所在位置,内部元素的属性是否变化,更深层dom树上的变化等等。 都可以使用一个window上暴露出来的一个api:MutationObserver 语法 官方地址:MutationObserver.MutationObserver() - Web API 接口参考 | MDN 使用new Mutat…

查询Greenplum的视图和存储过程,指定schema

查询视图 SELECT schemaname,viewname AS view_name, definition AS view_definition FROM pg_views WHERE schemaname dcf_user; 查询存储过程 SELECT a.proname ,a.prosrc ,b.rolname FROM pg_proc a left join pg_roles b on a.proowner b.oid where b.rolname dcf…

打印菱形-第11届蓝桥杯选拔赛Python真题精选

[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第9讲。 打印菱形&#xff…

Django框架之中间件

目录 一、引入 二、Django中间件介绍 【1】什么是Django中间件 【2】Django中间件的作用 【3】示例 三、Django请求生命周期流程图 四、Django中间件是Django的门户 五、Django中间件详解 六、中间件必须要掌握的两个方法 (1) process_request (2) process_respon…

创意设计与个性化定制:酒精壁炉的独特之处

在当今家居装饰的潮流中,人们越来越注重个性化和创意,而酒精壁炉正是在这一趋势中崭露头角。它不仅成为家居的温馨之选,更因其设计的灵活性而成为创意焦点,吸引了越来越多注重家居设计的人群。 酒精壁炉的设计灵活性为家居注入了新…

加载minio中存储的静态文件html,不显示样式与js

问题描述:点击链接获取的就是纯静态文件,但是通过浏览器可以看到明明加载了css文件与js文件 原因:仔细看你会发现加载css文件显示的contentType:text/html文件,原来是minio上传文件时将所有文件的contentType设置成了text/html 要在上传时指定文件,根据文章的类型指定的Conten…

uniapp分包优化,包括分包路由跳转规则

分包指的是把一个完整的小程序项目,按照需求划分为不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载。以达到优化小程序响应速度的目的。 可以看微信官方给的解释:小程序性能优化指南 | 微信开放社区 小程序官方文…

Docker Swarm总结+service创建和部署、overlay网络以及Raft算法(2/3)

博主介绍:Java领域优质创作者,博客之星城市赛道TOP20、专注于前端流行技术框架、Java后端技术领域、项目实战运维以及GIS地理信息领域。 🍅文末获取源码下载地址🍅 👇🏻 精彩专栏推荐订阅👇🏻…

【开源】基于JAVA的在线课程教学系统

项目编号: S 014 ,文末获取源码。 \color{red}{项目编号:S014,文末获取源码。} 项目编号:S014,文末获取源码。 目录 一、摘要1.1 系统介绍1.2 项目录屏 二、研究内容2.1 课程类型管理模块2.2 课程管理模块2…

Android 提示框代码 java语言

在Android中,你可以使用 AlertDialog 类来创建提示框。以下是一个简单的Java代码示例,演示如何创建和显示一个基本的提示框: import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; im…

实时语音克隆:5 秒内生成任意文本的语音 | 开源日报 No.84

CorentinJ/Real-Time-Voice-Cloning Stars: 43.3k License: NOASSERTION 这个开源项目是一个实时语音克隆工具,可以在5秒内复制一种声音,并生成任意文本的语音。 该项目的主要功能包括: 从几秒钟的录音中创建声纹模型根据给定文本使用参考…