Java工厂模式的最佳实践?
"Simplicity is prerequisite for reliability." - Edsger Dijkstra
“简单是可靠的前提条件。” —— 艾兹格·迪杰斯特拉
0x00 大纲
0x01 前言
最近在重温设计模式(in Java)的相关知识,然后在工厂模式的实现上面进行了一些较深入的探究,有了一些以前不曾注意到的发现,遂将其整理成文,以作后用。
工厂模式是典型的创建型模式,相比于创建简单对象的小作坊(new一个对象),它可以将复杂的构造逻辑进行封装,并对外暴露相对简单的接口方法,从而简化对象的创建流程。并在一定程度上提供平替模块而不用改变代码结构的灵活特性。
在许多书籍和文献里喜欢将工厂模式划分为简单工厂模式和抽象工厂模式,但是我个人认为它们或许并没有如此明确的界限——至少在OOP里面。继承的存在使得我们的“工厂”和”产品“都可以是多态的,我认为理解这一点尤为重要。工厂模式只是一种对复杂构造流程的封装,至于抽象程度高还是低并不影响它的本质。
通过代码来展示工厂模式的文章已经很多了,但我认为它很无聊且脱离实际,有点通过答案来倒推过程的味道。我将用一个夸张的故事来说明工厂模式的局限,以及需要注意的地方,提醒自己在今后的工作中不要犯这样的错误——当我得意忘形,以为自己很聪明的时候。
0x02 理想的工厂模型
通常来说,只有明确了我们的“产品”是什么,才能知道我们需要怎么样的“工厂”。我们假定最初的产品是一个MP3播放器,它的构造很复杂,因此我们引入了一个工厂类用来创建它的实例。为了应对未来可能的修改,我们对解码器和解码器工厂做了接口的抽象,看起来像这样:

到目前为止,它都符合我们的设计预期,运作良好。我们甚至有足够的信心应对未来可能的(想像中的)需求变更:“随着业务的发展,只支持MP3格式的播放器看起来已经太寒酸了,于是乎引入了其它的播放格式。得益于我们之前的设计,不用改动原来的代码,只需要增加一组实现就能实现新增的需求,so easy.”

然而,现实总是打脸的,经过产品的深入调研,决定将播放器业务扩展到视频领域,对没错,就先支持个H.264编码的视频流吧,好像同行竞品都在用呢。于是,开发人员不得不重新考量原来的设计。于是经过若干个996,开发组调整了原来的设计,并完成了下面的系统:

开发人员顶着黑眼圈,面带满意微笑地在最后期限的前一天晚上提交了代码——这下无论它增加音频格式和视频格式,我们都可以灵活应对了,嘿嘿嘿!负责架构的小锅拍着胸脯向各位开发成员如是说道。并在PPT上附上了下一阶段的(想像中的)技术方向:

新入职的初级开发小蔡似乎觉得有什么地方不太对劲,欲言又止。但下一秒又安慰自己:肯定是我自己经验不足,理解还不到位,这个设计应该没有问题!
0x03 道高一尺魔高一丈
随着一阵聊天工具此起彼伏的响声,产品又紧急召集众人开会了。”来活了各位,我们的播放器面对同行毫无优势,经过我们的研究,决定在原有的播放基础上,增加转换输出的功能!速度要快,质量要稳!对了,最好能多支持几种格式,最好市面上找得到的格式都支持一下。“各位开发脸色铁青,尤其是架构师小锅的脸色黑得最为纯粹。
由于研发周期短,项目组来不及细细思考和重新设计,只能在原有项目基础上增加相关的模块来应对新的需求。半小时讨论,半小时敲定。大家一致决定,不如就沿用原来工厂模式的设计,反正我们已经有前面的经验,应该不会有什么大问题,于是新的设计诞生了:

为了维持项目原有的结构设计,开发人员在编码阶段似乎显得有点不堪重负,经过两周紧锣密鼓的开发,项目不出所料地延期了。
年轻的被寄予厚望的架构师小锅在复盘会议上失去了往昔眼中的高光。
0x03 何谓最佳实践
以至于多年以后,在公司新来的架构师小程向大家讲述工厂模式的巧妙应用的那一刻。
不再年轻的小锅又回想起三月里那个温暖的下午。注:就是去背锅的那个下午。
小锅起身,先是肯定了小程扎实的基本功和流畅的表达,随后又把当年的往事向大家娓娓道来,边板书边讲,尽最大可能向大家讲述了当年事情的来龙去脉,并作出总结:
- 切勿盲目自信,陷入教条的陷阱
- 你可以预见变更,但永远不能预测需求
- 过早的优化是万恶之源
众人陷入沉默,随后年轻的小程率先打破僵局,向小锅问道:”那么,最后,问题是怎么解决的呢?“
小锅微微一笑,先是没有说话,随后转过身去疯狂画起图来,毕了潇洒转身将手背到身后,说:”从哪里跌倒就从哪里站起来。“

0x04 小结
为了更好的说明工厂模式能解决什么问题,不能解决什么问题,以上故事纯属虚构,饱含夸张的成分,如有雷同,请勿对号入座。
回到最初的起点,只有明确了我们的“产品”是什么,才能知道我们需要怎么样的“工厂”。 不必着急引入模式,先让产品飞一会儿。在不稳定的维度上引入工厂模式是没有意义的,因为异变需求无法被初始抽象完全界定,错误的抽象还不如不抽象。
Java工厂模式的最佳实践?的更多相关文章
- java工厂模式
(1)概念大白话:java工厂模式就是客户端(main函数)要创建对象觉得麻烦就让另外一个叫工厂的类帮它创建,然后自己每次要创建对象就叫工厂帮它弄,举个例子,在没有工厂这个"手下" ...
- paip.java gui swt/jface 最佳实践
paip.java gui swt/jface 最佳实践 1. 工具:Eclipse +jigloo4 1 2. 安装插件: 1 1. IMPORT swt lib 2 2. 新建立窗体 2 3. 运 ...
- paip.提升性能--多核编程中的java .net php c++最佳实践 v2.0 cah
paip.提升性能--多核编程中的java .net php c++最佳实践 v2.0 cah 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax ...
- atitit.Atitit. Gui控件and面板-----服务端控件 java struts的实现最佳实践
atitit.Atitit. Gui控件and面板-----服务端控件 java struts的实现最佳实践 1. 服务器控件的类别 1 1.1. 数据控件:该类控件可细分为两种类型:数据源控件和数 ...
- Java工厂模式解耦 —— 理解Spring IOC
Java工厂模式解耦 -- 理解Spring IOC 最近看到一个很好的思想来理解Spring IOC,故记录下来. 资源获取方式 主动式:(要什么资源都自己创建) 被动式:(资源的获取不是我们创建, ...
- Java学习笔记——Java工厂模式之简单工厂
package com.app; import java.util.Date; /* * 工厂模式:简单工厂.工厂方法.抽象工厂 * * */ public class Test0718_Factor ...
- [Java Performance] 数据库性能最佳实践 - JPA和读写优化
数据库性能最佳实践 当应用须要连接数据库时.那么应用的性能就可能收到数据库性能的影响. 比方当数据库的I/O能力存在限制,或者因缺失了索引而导致运行的SQL语句须要对整张表进行遍历.对于这些问题.只相 ...
- JAVA - 工厂模式
1. 简单工厂违背OCP(Open Close Principle)原则 , 即对增加开放,对修改关闭.如果要符合OCP原则,要针对接口编程. //简单工厂模式,违反了OCP原则 public cla ...
- Java 工厂模式(一)— 抽象工厂(Abstract Factory)模式
一.抽象工厂模式介绍: 1.什么是抽象工厂模式: 抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的一种形态,抽象工厂模式向客户端提供一个接口,使得客户端在不知道具体产品的情类型的情况下,创建 ...
- Java 工厂模式(一)— 简单工厂模式
一.什么是工厂模式: Java中的工厂模式主要是用来将有大量共同接口的类实例化.工厂模式可以动态的决定将哪一个类实例化,不必事先知道要实例化哪个类,将类的实例化的主动权交给工厂而不是类本身.我们常见的 ...
随机推荐
- 数据卷Volume
数据卷概述 Kubernetes Volume(数据卷)主要解决了如下两方面问题: 数据持久性:通常情况下,容器运行起来之后,写入到其文件系统的文件暂时性的.当容器崩溃后,kubelet 将会重启该容 ...
- 使用 Loki 搭建个人日志平台
文章转载自:https://blog.kelu.org/tech/2020/01/31/grafana-loki-for-logging-aggregation.html 背景 Loki的第一个稳定版 ...
- 通过 Docker 部署 Redis 6.x 集群
要点步骤总结: # 这里演示使用同一台主机上 # 创建各节点存储路径 mkdir -p /opt/redis/{7000,7001,7002,7003,7004,7005} # 创建各节点配置文件 c ...
- NAT模式下的虚拟机连接主机网络
基于NAT模式的VMware虚拟机(Linux CentOS 7)连接主机(Windows 11)网络 一.什么是NAT模式 虚拟机连接主机网络的三种方式: Bridged(桥接) NAT(网络地址转 ...
- python锦鲤
今日内容目录 垃圾回收机制 流程控制理论& 流程控制之分支结构& 流程控制之循环结果& 详情 Python垃圾回收机制 """ 有一些语言,内存空 ...
- 使用FreeMarker配置动态模板
FreeMarker动态模板 目录 FreeMarker动态模板 前言 准备工作 FreeMarker 代码构建 项目结构 创建 Configuration 实例 调用 模板文件 调用结果 Tips ...
- JavaScript函数式编程之函子
函子(Functor) 函子是一个特殊的容器,通过一个普通对象来实现,该对象具有map方法,map方法可以运行一个函数对值进行处理(变形关系),容器包含值和值变形关系(这个变形关系就是函数).函数式编 ...
- 8.DRF请求响应和api_view
一.请求对象(Request objects) DRF引入了一个扩展Django常规HttpRequest对象的Request对象,并提供了更灵活的请求解析能力 Request对象的核心功能是re ...
- java学习之socket编程
0x00前言和思维导图 Socks实际上是什么:实际上是提供了精彩通信的端口,在通信之前双方都必须要创造一个端点才能通信,其实感觉socket跟计算机的三次握手有些相似,分为三个步骤: (1)服务器监 ...
- AIR32F103(五) FreeRTOSv202112核心库的集成和示例代码
目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...