![设计模式就该这样学:基于经典框架源码和真实业务场景](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=1738974346-Pdg45Ejt6TvaGiz1Ga18a3plVvSoigqA-0-ad8a9887a4f4476bdc970f886f271eab)
学完设计模式之后,你可能会这样感叹:
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_3.jpg?sign=1738974346-xNEUfaBJyO5dCGxVlv6x9GJAcypy3Roy-0-4bf481073f3110978a383f6a732c933c)
大家对比一下前后的区别,有何感受?
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_4.jpg?sign=1738974346-1OAxeB4Pw70Yw0aGNdnL3iRw6hTgV5Rz-0-7c4117a573e2934436f560634295b09c)
回到代码中,我们来思考一下,设计模式能解决哪些问题?
4.2.1 写出优雅的代码
先来看一段笔者很多年前写的代码。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_5.jpg?sign=1738974346-RXadb89HraLwtrWLhJI4TOppbzb0yTJv-0-8ddee3bfc1e40e4b5a7d009190372185)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_6.jpg?sign=1738974346-xCWb8OAgjsPDfPLTn3nIBCjoCyJjdijF-0-563047e16a7937ad8f011ddb77178dfc)
优化之后的代码如下。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_7.jpg?sign=1738974346-cbA5MzYhxiW7DWL007AsK2GmzsKoK9Wx-0-7e4c02c70a1acd7ab84d80882e06814f)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_8.jpg?sign=1738974346-RK9EecIyoCUK34socGrR8IzH1C00E6ax-0-aa8496ff8ec9726488f959b588de0b34)
4.2.2 更好地重构项目
平时我们写的代码虽然满足了需求,但往往不利于项目的开发与维护,以下面的JDBC代码为例。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_9.jpg?sign=1738974346-Sj6V9LiwHn75HPbO9MDL6Q0CXmjyBIAJ-0-4c234455ffaff8270779b7dcf4928d83)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_10.jpg?sign=1738974346-u8KJmX5kiEwfFZLxRe1ethmNc9pJJkqz-0-ff0eadef9396692d805094276e171021)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_11.jpg?sign=1738974346-VzfwWsk5R7YXb8tY9JYDgYfPOIfa8qP4-0-9cbcb50f72f9feace60cc63dbe677013)
上述代码的功能没问题,但是代码重复得太多,因此可以进行抽取,把重复代码放到一个工具类JdbcUtil里。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_12.jpg?sign=1738974346-aflLCLquu2QfIOm4XYR6Xbpxgsq0fbcB-0-575536136de32c3bf808b02d607041e8)
只需要在实现类中直接调用工具类JdbcUtil中的方法即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_13.jpg?sign=1738974346-hwtcWVZhv9VlnbeKtmrFxGtnH3AZQM0C-0-34577503a38f6a863f0db635c39c42fc)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_14.jpg?sign=1738974346-v6N5kaQftattkrZz1PrHP3GJccSBk2uC-0-490366a0dec0da9c3bf55dccce3e1c05)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_15.jpg?sign=1738974346-AbyySF6SBONkqqkvBLsPxRW0yksus29Q-0-843337e9e996d40d52bfc0bac777fa60)
虽然完成了重复代码的抽取,但数据库中的账号、密码等直接显示在代码中,不利于后期账户密码改动的维护。可以建立一个db.propertise文件,用来存储这些信息。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_16.jpg?sign=1738974346-MN07wd2WOyPdJMdoZ5nXQHTanzoUmirr-0-d78d68931977fc09a707ddd1ef1ebe0a)
只需要在工具类JdbcUtil中获取里面的信息即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_17.jpg?sign=1738974346-OoAgolN5Misz8IXiJlxBcEI5NuuhP8D0-0-4929d8913f0389e345731c9aa97d1bcc)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_18.jpg?sign=1738974346-I8uPN6ftNZuR3xg1whBbnTTETOfzENWf-0-96aed11093e5c73daa17c3ad36c6a829)
代码抽取到这里,貌似已经完成,但在实现类中,依然存在部分重复代码,在DML操作中,除了SQL和设置值的不同,其他都相同,把相同的部分抽取出来,把不同的部分通过参数传递进来,无法直接放在工具类中。此时,可以创建一个模板类JdbcTemplate,创建一个DML和DQL的模板来对代码进行重构。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_19.jpg?sign=1738974346-QVIGi7aMkBzKDwYoht35QQ0DqW0VLUby-0-d7097b6e0809b7f010e8036e6f76b7d7)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_20.jpg?sign=1738974346-HLfqqt0xlzOVsLOC3BHf0lmZIZ1dMef5-0-40ee2e2f73196cdbb57c82416e3b8c48)
实现类直接调用方法即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_21.jpg?sign=1738974346-flMNt5Pfc1NbELqzRsHxUuL1qO849Oiu-0-992f4742df3e00fbc8f22983100f37c7)
这样重复的代码基本就解决了,但有一个很严重的问题,就是这个程序DQL操作中只能处理Student类和t_student表的相关数据,无法处理其他类,比如Teacher类和t_teacher表。不同的表(不同的对象)应该有不同的列,不同列处理结果集的代码就应该不一样,处理结果集的操作只有DAO自己最清楚。也就是说,处理结果的方法根本就不应该放在模板方法中,应该由每个DAO自己来处理。因此,可以创建一个IRowMapper接口来处理结果集。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_22.jpg?sign=1738974346-7SJf7amsmzk41zv8vBT9oGKcwCqkq5vM-0-ae106b1277a0f049c7fab00950ad7d85)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_23.jpg?sign=1738974346-pQiL0OVEp9nzGJDdFllbdcvyBd9CgisF-0-d7313afbd6116bf96adf48ba705486db)
DQL模板类中调用IRowMapper接口中的handle方法,提醒实现类自己去实现mapping方法。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_24.jpg?sign=1738974346-qZmpsd9kLKAGIgfMiXaoEM9dVH61pR1h-0-f7b8a30f357cf87ce3809905766655f9)
实现类自己去实现IRowMapper接口的mapping方法,想要处理什么类型的数据在里面定义即可。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_25.jpg?sign=1738974346-6AMABRcGeKHx2crAISdL39Wga5AjDHRU-0-e43909ccedead6bbd8dad3a1aa603d5d)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_26.jpg?sign=1738974346-W0clWoT8CRoSqGFkfZaRsXRCtUL8gnq2-0-5a138064c47d0a9f26ab7d542921304a)
到这里为止,实现ORM的关键代码已经大功告成,但是DQL查询不单单要查询学生信息(List类型),还要查询学生数量,这时就要通过泛型来完成。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_27.jpg?sign=1738974346-Pm9Kmn2T3faMHnLbtueMWmbiHcmyV7mS-0-05df746bd14b6f616a166369407f5959)
StudentRowMapper类的代码如下。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_28.jpg?sign=1738974346-9ctAtfsybyC1m5gP6OoLRjdasUmE7G7K-0-ac362b129b0ba49f1775fb707f483a69)
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_29.jpg?sign=1738974346-7F3Jd5zjO5EOThJuQgMQJNxt9uxhFaFe-0-1b656d146b3c557e1c989d5d29be5e81)
这样,不仅可以查询List,还可以查询学生数量。
![img](https://epubservercos.yuewen.com/A1F36C/17725769807799506/epubprivate/OEBPS/Images/txt005_30.jpg?sign=1738974346-YQtk3omAJijHNXzN38aLNYeVzXXmAEAX-0-7d3aa09099d39434ded720967da34b90)
这样,重构设计就已经完成,好的代码能让我们以后维护更方便,因此学会对代码重构是非常重要的。
4.2.3 经典框架都在用设计模式解决问题
比如,Spring就是一个把设计模式用得淋漓尽致的经典框架。本书会结合JDK、Spring、MyBatis、Netty、Tomcat、Dubbo等经典框架的源码对设计模式展开分析,帮助大家更好、更深入地理解设计模式在框架源码中的落地。