![设计模式就该这样学:基于经典框架源码和真实业务场景](https://wfqqreader-1252317822.image.myqcloud.com/cover/758/33114758/b_33114758.jpg)
4.2 为什么一定要学习设计模式
先来看一个生活案例,当我们开心时,也许会寻求享乐。在学习设计模式之前,你可能会这样感叹:
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_2.jpg?sign=1738885961-IMh134NaZ6XipPXfPZAYuvBjeBaQlzR8-0-566322cc12cd351796a257ce8d738ef7)
学完设计模式之后,你可能会这样感叹:
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_3.jpg?sign=1738885961-cyPLB5GgDrZolFroKGeY82pg6X1wsA3h-0-eb129bf43a0a10969380c58b5d9da7a7)
大家对比一下前后的区别,有何感受?
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_4.jpg?sign=1738885961-so9DOERDuallaXjz4DJJguIzoTmkzLJD-0-ae19b483a769dbade443cb96fa894fe9)
回到代码中,我们来思考一下,设计模式能解决哪些问题?
4.2.1 写出优雅的代码
先来看一段笔者很多年前写的代码。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_5.jpg?sign=1738885961-JuSAwIZ1bwFkI5sbCOBYnQcvuSHFJddW-0-1f581d2f25e6704cbb3660fe5b15dace)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_6.jpg?sign=1738885961-9EeEyUyki92yGowrBoyWzyieRzytoPYK-0-f8475e46709eed0ff2405eda8717773c)
优化之后的代码如下。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_7.jpg?sign=1738885961-IhgT1XN81nIGyhw4wTPntYPYPBdPqLvG-0-158e634386b630e43b1128079ae1829d)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_8.jpg?sign=1738885961-H7x4Xkgc7mdznYA198xFnVGjGWS4dpYE-0-fee489cb16c10ca2b4b54addfdd727dd)
4.2.2 更好地重构项目
平时我们写的代码虽然满足了需求,但往往不利于项目的开发与维护,以下面的JDBC代码为例。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_9.jpg?sign=1738885961-Ex3o2kM4t2m6Z4hq4wPcAs0BR0OR9Bxq-0-60b0a655aab8423ea8ce66f84a4f8612)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_10.jpg?sign=1738885961-IRaAw0yP2HFvJ0aRj0jHXV6P5OGP6syi-0-569af9e9d05ba03e577353fd17f22ef7)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_11.jpg?sign=1738885961-QYRZOelv7NPFO5XGS5xWq2GY5SRYJTMj-0-fc06c6c226520cdac18ec1fb5b03c013)
上述代码的功能没问题,但是代码重复得太多,因此可以进行抽取,把重复代码放到一个工具类JdbcUtil里。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_12.jpg?sign=1738885961-WMyXnNa73YIjxb3P2QgbaG7B7J2ZQcKX-0-491a220a5516c2e1cb35e871a3b949d4)
只需要在实现类中直接调用工具类JdbcUtil中的方法即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_13.jpg?sign=1738885961-M2WYDnnZCGD1bsRoxwbSuimS9hmzg9rI-0-69eafaeff6213ed2b39a354d8f183b43)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_14.jpg?sign=1738885961-ArVpfdnzKAip2GEVQFdOlpPLxgtGmtAF-0-a13c640212fa5d81748e54684c079e87)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_15.jpg?sign=1738885961-qfRsVktgJZ3SI6qvOVtSo4OUgIkjBxt3-0-584ea69a52a31c8b366bd20cfc1c21ed)
虽然完成了重复代码的抽取,但数据库中的账号、密码等直接显示在代码中,不利于后期账户密码改动的维护。可以建立一个db.propertise文件,用来存储这些信息。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_16.jpg?sign=1738885961-9SBOHDRqtibigMxS6bbLtXoGBy0JobzE-0-303886c1e60c48dda5d5d00973d473a4)
只需要在工具类JdbcUtil中获取里面的信息即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_17.jpg?sign=1738885961-SDcvck0ZeHB57EPTm3ZBSiB1WCmIfIAt-0-233e1f4a0f2ecbc967090da2e551a8d9)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_18.jpg?sign=1738885961-ahJHCyb92ixEr9tVVMPithVWo72EDX5A-0-744df7511cd40c7eedd0cbd9ea564c5c)
代码抽取到这里,貌似已经完成,但在实现类中,依然存在部分重复代码,在DML操作中,除了SQL和设置值的不同,其他都相同,把相同的部分抽取出来,把不同的部分通过参数传递进来,无法直接放在工具类中。此时,可以创建一个模板类JdbcTemplate,创建一个DML和DQL的模板来对代码进行重构。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_19.jpg?sign=1738885961-pUZ3HQPwmbJJ3CgQ2rep0Xza5vCcFNZ4-0-4647ad40861a0a767788beece12b3696)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_20.jpg?sign=1738885961-g2uhTxWZSys4Fxp2f8tpiTKagFihAgQN-0-1efb01c0e3127feb735f8ad25757bfba)
实现类直接调用方法即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_21.jpg?sign=1738885961-skmaM6YAI0b7MOI9P3yBZZe0GpfsOwi3-0-4724346fc4fe9423dcfce12df5c951e1)
这样重复的代码基本就解决了,但有一个很严重的问题,就是这个程序DQL操作中只能处理Student类和t_student表的相关数据,无法处理其他类,比如Teacher类和t_teacher表。不同的表(不同的对象)应该有不同的列,不同列处理结果集的代码就应该不一样,处理结果集的操作只有DAO自己最清楚。也就是说,处理结果的方法根本就不应该放在模板方法中,应该由每个DAO自己来处理。因此,可以创建一个IRowMapper接口来处理结果集。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_22.jpg?sign=1738885961-cM93C2kcPqGbC6sY8MiO7DtfFf1yL29j-0-776fe559fb084dc4d1fe3bf5a497b86c)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_23.jpg?sign=1738885961-PahWKBSaNRdXUg18GcKsJOPGyg3WNPVA-0-cea59f2d774681fd2bea5d4332d408b4)
DQL模板类中调用IRowMapper接口中的handle方法,提醒实现类自己去实现mapping方法。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_24.jpg?sign=1738885961-nVy5i6sXiauVFj7PFaneLtywNJfRmCRN-0-0de9f16717a8b8c0ab627814cfe6331c)
实现类自己去实现IRowMapper接口的mapping方法,想要处理什么类型的数据在里面定义即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_25.jpg?sign=1738885961-ggJgKaGYYMLRb32noppmVEaRyPC2QFeM-0-c817d5c56d162ca4b0f921a4975b55bf)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_26.jpg?sign=1738885961-YTW6RvWWa0faaNaZSHdSPxvEqO4ZQkpF-0-24ddaa93cda6705847cbe8635fa96d50)
到这里为止,实现ORM的关键代码已经大功告成,但是DQL查询不单单要查询学生信息(List类型),还要查询学生数量,这时就要通过泛型来完成。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_27.jpg?sign=1738885961-LLg0nOSpL0v9y3i4DPUhOEzqHlXGSIuO-0-6848a6babc31caf319b93c33d0ce9962)
StudentRowMapper类的代码如下。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_28.jpg?sign=1738885961-y2Kq8RjYw04rBx8nSbBNyKqZAiX756FN-0-f5f2ac53d4de80e9915614550c30e3ee)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_29.jpg?sign=1738885961-798xw0xm1VOJ5xJcnY1SjaLpb84JTQjd-0-bbd8fe755752ac9bf7ba9bac6ca6857e)
这样,不仅可以查询List,还可以查询学生数量。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_30.jpg?sign=1738885961-bdDhFgO5xaKvYLou5zviilK9HXxY7kjv-0-798536fb162df6eb449a7bf2b7b8578c)
这样,重构设计就已经完成,好的代码能让我们以后维护更方便,因此学会对代码重构是非常重要的。
4.2.3 经典框架都在用设计模式解决问题
比如,Spring就是一个把设计模式用得淋漓尽致的经典框架。本书会结合JDK、Spring、MyBatis、Netty、Tomcat、Dubbo等经典框架的源码对设计模式展开分析,帮助大家更好、更深入地理解设计模式在框架源码中的落地。