设计模式之简单工厂模式详解

简单工厂模式

工厂模式:工厂方法模式;

低阶:简单工厂模式;

高阶:抽象工厂模式;

1)概述

定义一个工厂类,根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。

在简单工厂模式中创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式。

2)流程

1.将需要创建的对象(Chart对象)的代码封装到不同的类中,称为具体产品类;

2.将公共的代码进行抽象和提取后封装在一个抽象产品类中,每一个具体产品类都是抽象产品类的子类;

3.提供一个工厂类用于创建各种产品,在工厂类中提供一个创建产品的工厂方法,该方法可以根据所传入的参数不同创建不同的具体产品对象;

4.客户端只需调用工厂类的工厂方法并传入相应的参数即可得到一个产品对象。

在这里插入图片描述

3)角色

● Factory(工厂角色):即工厂类,负责创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法 factoryMethod(),返回类型为抽象产品类型 Product。

● Product(抽象产品角色):是工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。

● ConcreteProduct(具体产品角色):是简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

4)案例-初始方案

开发一套图表库,为应用系统提供不同外观的图表,例如柱状图、饼状图、折线图等,要求可以方便增加新类型的图表。

class Chart {private String type; //图表类型public Chart(Object[][] data, String type) {this.type = type;if (type.equalsIgnoreCase("histogram")) {//初始化柱状图}else if (type.equalsIgnoreCase("pie")) {//初始化饼状图}else if (type.equalsIgnoreCase("line")) {//初始化折线图}}public void display() {if (this.type.equalsIgnoreCase("histogram")) {//显示柱状图}else if (this.type.equalsIgnoreCase("pie")) {//显示饼状图}else if (this.type.equalsIgnoreCase("line")) {//显示折线图}	}
}

问题

(1) 在Chart类中包含很多“if…else…”代码块,整个类的代码冗长,阅读难度、维护难度和测试难度大,影响系统性能,程序在执行过程中需要做大量的条件判断。(2) Chart类的职责过重,它负责初始化和显示所有的图表对象,将各种图表对象的初始化代码和显示代码集中在一个类中实现,违反了“单一职责原则”,不利于类的重用和维护;而且将大量的对象初始化代码都写在构造函数中将导致构造函数非常庞大,对象在创建时需要进行条件判断,降低了对象创建的效率。(3) 当需要增加新类型的图表时,必须修改Chart类的源代码,违反了“开闭原则”。(4) 客户端只能通过new关键字来直接创建Chart对象,Chart类与客户端类耦合度较高,对象的创建和使用无法分离。(5) 客户端在创建Chart对象之前可能还需要进行大量初始化设置,例如设置柱状图的颜色、高度等,如果在Chart类的构造函数中没有提供一个默认设置,那就只能由客户端来完成初始设置,这些代码在每次创建Chart对象时都会出现,导致代码的重复。
5)案例-重构后

在这里插入图片描述

//抽象图表接口:抽象产品类
interface Chart {public void display();
}//柱状图类:具体产品类
class HistogramChart implements Chart {public HistogramChart() {System.out.println("创建柱状图!");}public void display() {System.out.println("显示柱状图!");}
}//饼状图类:具体产品类
class PieChart implements Chart {public PieChart() {System.out.println("创建饼状图!");}public void display() {System.out.println("显示饼状图!");}
}//折线图类:具体产品类
class LineChart implements Chart {public LineChart() {System.out.println("创建折线图!");}public void display() {System.out.println("显示折线图!");}
}//图表工厂类:工厂类
class ChartFactory {//静态工厂方法public static Chart getChart(String type) {Chart chart = null;if (type.equalsIgnoreCase("histogram")) {chart = new HistogramChart();System.out.println("初始化设置柱状图!");}else if (type.equalsIgnoreCase("pie")) {chart = new PieChart();System.out.println("初始化设置饼状图!");}else if (type.equalsIgnoreCase("line")) {chart = new LineChart();System.out.println("初始化设置折线图!");			}return chart;}
}// 客户端
class Client {public static void main(String args[]) {Chart chart;chart = ChartFactory.getChart("histogram"); //通过静态工厂方法创建产品chart.display();}
}
6)案例-使用配置文件优化

将静态工厂方法的参数存储在XML或properties格式的配置文件中。

<?xml version="1.0"?>
<config><chartType>histogram</chartType>
</config>

通过工具类 XMLUtil 读取配置文件中的字符串参数。

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;public class XMLUtil {//从 XML 配置文件中提取图表类型,并返回类型名public static String getChartType() {try {//创建文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;							doc = builder.parse(new File("config.xml")); //获取包含图表类型的文本节点NodeList nl = doc.getElementsByTagName("chartType");Node classNode = nl.item(0).getFirstChild();String chartType = classNode.getNodeValue().trim();return chartType;}   catch(Exception e) {e.printStackTrace();return null;}}
}

引入配置文件和工具类XMLUtil后,客户端修改如下:

class Client {public static void main(String args[]) {Chart chart;String type = XMLUtil.getChartType(); //读取配置文件中的参数chart = ChartFactory.getChart(type); //创建产品对象chart.display();}
}
7)总结

简单工厂模式提供了工厂类用于创建对象,将对象的创建和对象的使用分开。

1.优点

实现了对象创建和使用的分离。

引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类。

2.缺点

工厂类集中了所有产品的创建逻辑,职责过重。

系统扩展困难,添加新产品需要修改工厂逻辑。

产品类型较多时,可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。

简单工厂模式使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

3.适用场景

工厂类负责创建的对象较少。

客户端只了解传入工厂类的参数,对于如何创建对象并不关心。

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

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

相关文章

Linux快速入门,上手开发 01.学习路线

少时曾许凌云志&#xff0c;当取世间第一流 再见少年拉满弓&#xff0c;不惧岁月不飓风 —— 24.3.20 1.Linux的发展历史 2.VM虚拟机的Linux初体验 3.图形化页面设置系统——快速上手 4.命令行操作——向专业前进 5.核心操作命令——必知必会&#xff08;管理企业级权限/定位b…

C++学习之旅(二)运行四个小项目 (Ubuntu使用Vscode)

如果是c语言学的比较好的同学 可以直接跟着代码敲一遍&#xff0c;代码附有详细语法介绍&#xff0c;不可错过 一&#xff0c;猜数字游戏 #include <iostream> #include <cstdlib> #include <ctime>int main() {srand(static_cast<unsigned int>(tim…

(一)基于IDEA的JAVA基础3

通过之前的内容&#xff0c;我们在建好的文件夹下建一个java文件&#xff0c;我们来在IDEA中写一下之前用记事本写的helloworld&#xff0c;我们先看一下java代码的规范: 1.java程序文件名一定要有意义&#xff0c;首字母一定要大写。 2.class后面的名字:由大小写字母&#x…

计算机网络相关

OSI七层模型 各层功能&#xff1a; TCP/IP四层模型 应用层 传输层 网络层 网络接口层 访问一个URL的全过程 在浏览器中输入指定网页的 URL。 浏览器通过 DNS 协议&#xff0c;获取域名对应的 IP 地址。 浏览器根据 IP 地址和端口号&#xff0c;向目标服务器发起一个 TCP…

「滚雪球学Java」:国际化(章节汇总)

&#x1f3c6;本文收录于「滚雪球学Java」专栏&#xff0c;专业攻坚指数级提升&#xff0c;助你一臂之力&#xff0c;带你早日登顶&#x1f680;&#xff0c;欢迎大家关注&&收藏&#xff01;持续更新中&#xff0c;up&#xff01;up&#xff01;up&#xff01;&#xf…

深度学习绘制热力图heatmap、使模型具有可解释性

思路 获取想要解释的那一层的特征图&#xff0c;然后根据特征图梯度计算出权重值&#xff0c;加在原图上面。 Demo 加上类激活(cam) 可以看到&#xff0c;cam将模型认为有利于分类的特征标注了出来。 下面以ResNet50为例: Trick: 使用 for i in model._modules.items():可以…

深度学习500问——Chapter03:深度学习基础(4)

文章目录 3.7 预训练与微调&#xff08;fine tuning&#xff09; 3.7.1 为什么无监督预训练可以帮助深度学习 3.7.2 什么是模型微调 fine tuning 3.7.3 微调时候网络参数是否更新 3.7.4 fine-tuning模型的三种状态 3.8 权重偏差和初始化 3.8.1 全都初始化为0 3.8.2 全都初始化为…

Android Launcher开发注意事项

在开发Android Launcher时&#xff0c;需要关注性能、用户体验、权限管理、兼容性等方面&#xff0c;同时遵循相关的开发者政策和最佳实践。有几个重要的注意事项&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎…

选择word中的表格VBA

打开开发工具 选择Visual Basic插入代码 Sub 选择word中的表格() Dim t As Table an MsgBox("即将选择选区内所有表格&#xff0c;若无选区&#xff0c;则选择全文表格。", vbYesNo, "提示") If an - 6 Then Exit Sub Set rg IIf(Selection.Type wdSel…

[HFCTF 2021 Final]easyflask

[HFCTF 2021 Final]easyflask [[python反序列化]] 首先题目给了提示&#xff0c;有文件读取漏洞&#xff0c;读取源码 #!/usr/bin/python3.6 import os import picklefrom base64 import b64decode from flask import Flask, request, render_template, sessionapp Flask(_…

HarmonyOS NEXT应用开发之侧滑返回事件拦截案例

介绍 在编辑场景中&#xff0c;存在用户误触返回&#xff0c;导致内容未保存就退出编辑页的现象; 本示例介绍使用NavDestination组件的onBackPressed回调对返回事件进行拦截&#xff0c;提示用户保存编辑内容&#xff0c;并使用preferences实例持久化保存内容。 效果预览图 使…

C数据类型(C语言)---变量的类型决定了什么?

目录 数据类型&#xff08;Data Type&#xff09; 变量的类型决定了什么&#xff1f; &#xff08;1&#xff09;不同类型数据占用的内存大小不同 如何计算变量或类型占内存的大小 &#xff08;2&#xff09;不同数据类型的表数范围不同 &#xff08;3&#xff09;不同类型…

元素定位之xpath和css

元素定位 xpath绝对路径相对路径案例xpath策略&#xff08;路径&#xff09;案例xpath策略&#xff08;层级、扩展&#xff09;属性层级与属性层级与属性拓展层级与属性综合 csscss选择器&#xff08;id、类、标签、属性&#xff09;id选择器类选择器标签选择器属性选择器案例-…

Spark源码(一)-SparkRPC示例

一、何为SparkRPC RPC全称为远程过程调用&#xff08;Remote Procedure Call&#xff09;&#xff0c;它是一种计算机通信协议&#xff0c;允许一个计算机程序调用另一个计算机上的子程序&#xff0c;而无需了解底层网络细节。通过RPC&#xff0c;一个计算机程序可以像调用本地…

谷歌Gemma大模型部署记录

谷歌Gemma大模型部署记录 配置信息 1.系统&#xff1a;Ubuntu20 2.显卡&#xff1a;RTX3060 6G 一、安装Ollama 官网地址&#xff1a;https://ollama.com/download/linux 按照指令安装 curl -fsSL https://ollama.com/install.sh | sh二、运行模型 输入指令&#xff1a;…

【Java】:类和对象

1.面向对象的初步认知 1.1 什么是面向对象 Java是一门面向对象的语言&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交互完成一件事情。用面向对象的思想来涉及程序&#xff0c;更符合人们对事物的认知…

【LeetCode-114.二叉树展开为链表】

题目详情&#xff1a; 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。展开后的单链表应该与二叉树 先序遍历 顺序…

seleniumUI自动化实例(CSDN发布文章)

1.CSDN登陆成功后&#xff0c;点击发布 源码&#xff1a; #点击首页中的发布按钮 CSDNconf.driver.find_element(By.LINK_TEXT,"发布").click() time.sleep(15) 2.输入标题 #输入文章标题&#xff0c;标题格式“selenium UI自动化测试实例今天的日期” CSDNconf.d…

POI和EasyExcel区别和操作Excel

POI和EasyExcel操作Excel 常用场景 1、将用户信息导出为excel表格&#xff08;导出数据… &#xff09; 2、将Excel表中的信息录入到网站数据库&#xff08;文件数据上传… &#xff09; 开发中经常会设计到excel的处理&#xff0c;如导出Excel&#xff0c;导入Excel到数据库…

springboot+itextpdf+thymeleaf+ognl根据静态模版文件实现动态生成pdf文件并导出demo

第一步&#xff1a;导入maven依赖 <!-- 导出为PDF依赖包 --><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId></dependency><dependency><groupId>com.itextpdf</groupId><art…