自定義網(wǎng)站主頁設(shè)計今日頭條新聞最新疫情
目錄
前言
一、示例程序
二、OCP開閉原則
三、依賴倒置原則DIP
四、控制反轉(zhuǎn)IOC
總結(jié)
前言
? 在軟件開發(fā)的世界里,隨著項目的增長和需求的變化,如何保持代碼的靈活性、可維護(hù)性和擴(kuò)展性成為了每個開發(fā)者必須面對的問題。傳統(tǒng)的面向過程或基于類的設(shè)計往往導(dǎo)致代碼高度耦合,使得任何小的改動都需要對整個系統(tǒng)進(jìn)行大規(guī)模的測試和調(diào)整。這不僅耗費時間,也增加了出錯的風(fēng)險。因此,理解并應(yīng)用一些基本的設(shè)計原則,如開閉原則(OCP)和依賴倒置原則(DIP),對于構(gòu)建高效、靈活的應(yīng)用程序至關(guān)重要。本文將通過一個簡單的用戶登錄示例,探討如何從傳統(tǒng)設(shè)計模式過渡到使用Spring框架實現(xiàn)控制反轉(zhuǎn)(IoC)來解決這些問題,幫助開發(fā)者更好地理解和實踐這些重要的編程理念。
一、示例程序
? 當(dāng)沒有Spring時,我們是怎么開發(fā)的呢?我們先閱讀下面的程序:
// 控制層
public class UserController {private UserService userService = new UserServiceImpl();public void login(){String username = "admin";String password = "123456";boolean success = userService.login(username, password);if (success) {// 登錄成功} else {// 登錄失敗}}
}// 業(yè)務(wù)層
public class UserServiceImpl implements UserService {private UserDao userDao = new UserDaoImplForMySQL();public boolean login(String username, String password) {User user = userDao.selectByUsernameAndPassword(username, password);if (user != null) {return true;}return false;}
}// 數(shù)據(jù)庫層
public class UserDaoImplForMySQL implements UserDao {public User selectByUsernameAndPassword(String username, String password) {// 連接MySQL數(shù)據(jù)庫,根據(jù)用戶名和密碼查詢用戶信息return null;}
}
? 可以看出,UserDaoImplForMySQL中主要是連接MySQL數(shù)據(jù)庫進(jìn)行操作。如果更換到Oracle數(shù)據(jù)庫上,則需要再提供一個UserDaoImplForOracle。很明顯,以上的操作正在進(jìn)行功能的擴(kuò)展,添加了一個新的類UserDaoImplForOracle來應(yīng)付數(shù)據(jù)庫的變化,這里的變化會引起連鎖反應(yīng)嗎?當(dāng)然會,如果想要切換到Oracle數(shù)據(jù)庫上,UserServiceImpl類代碼就需要修改。
二、OCP開閉原則
? 上面的代碼以及修改違背了OCP開閉原則,開閉原則是這樣說的:在軟件開發(fā)過程中應(yīng)當(dāng)對擴(kuò)展開放,對修改關(guān)閉。也就是說,如果在進(jìn)行功能擴(kuò)展的時候,添加額外的類是沒問題的,但因為功能擴(kuò)展而修改之前運行正常的程序,這是忌諱的,不被允許的。因為一旦修改之前運行正常的程序,就會導(dǎo)致項目整體要進(jìn)行全方位的重新測試。這是相當(dāng)麻煩的過程。導(dǎo)致以上問題的主要原因是:代碼和代碼之間的耦合度太高。如下圖所示:
?更多軟件設(shè)計原則:【設(shè)計模式】軟件設(shè)計原則-CSDN博客
? 可以很明顯的看出,上層是依賴下層的。UserController依賴UserServiceImpl,而UserServiceImpl依賴UserDaoImplForMySQL,這樣就會導(dǎo)致下面只要改動,上面必然會受牽連(跟著也會改),所謂牽一發(fā)而動全身。這樣也就同時違背了另一個開發(fā)原則:依賴倒置原則。?
三、依賴倒置原則DIP
? 依賴倒置原則(Dependence Inversion Principle),簡稱DIP,主要倡導(dǎo)面向抽象編程,面向接口編程,不要面向具體編程,讓上層不再依賴下層,下面改動了,上面的代碼不會受到牽連。這樣可以大大降低程序的耦合度,耦合度低了,擴(kuò)展力就強(qiáng)了,同時代碼復(fù)用性也會增強(qiáng)(軟件七大開發(fā)原則都是在為解耦合服務(wù))。你可能會說,上面的代碼已經(jīng)面向接口編程了呀:
? 確實已經(jīng)面向接口編程了,但對象的創(chuàng)建是:new UserDaoImplForOracle()顯然并沒有完全面向接口編程,還是使用到了具體的接口實現(xiàn)類。什么叫做完全面向接口編程?請看以下代碼:
? 如果代碼是這樣編寫的,才算是完全面向接口編程。那你可能會問,這樣userDao是null,在執(zhí)行的時候就會出現(xiàn)空指針異常呀。你說的有道理,確實是這樣的,所以我們要解決這個問題。解決空指針異常的問題,其實就是解決兩個核心的問題:?
- 誰來負(fù)責(zé)對象的創(chuàng)建?!疽簿褪钦f誰來:new UserDaoImplForOracle()/new UserDaoImplForMySQL()】
- 誰來負(fù)責(zé)把創(chuàng)建的對象賦到這個屬性上?!疽簿褪钦f誰來把上面創(chuàng)建的對象賦給userDao屬性】
? 如果我們把以上兩個核心問題解決了,就可以做到既符合OCP開閉原則,又符合依賴倒置原則。很榮幸的通知你:Spring框架可以做到。在Spring框架中,它可以幫助我們new對象,并且它還可以將new出來的對象賦到屬性上。換句話說,Spring框架可以幫助我們創(chuàng)建對象,并且可以幫助我們維護(hù)對象和對象之間的關(guān)系。比如:
? Spring可以new出來UserDaoImplForMySQL對象,也可以new出來UserDaoImplForOracle對象,并且還可以讓new出來的dao對象和service對象產(chǎn)生關(guān)系(產(chǎn)生關(guān)系其實本質(zhì)上就是給屬性賦值)。很顯然,這種方式是將對象的創(chuàng)建權(quán)/管理權(quán)交出去了,不再使用硬編碼的方式了。同時也把對象關(guān)系的管理權(quán)交出去了,也不再使用硬編碼的方式了。像這種把對象的創(chuàng)建權(quán)交出去,把對象關(guān)系的管理權(quán)交出去,被稱為控制反轉(zhuǎn)。
四、控制反轉(zhuǎn)IOC
? 控制反轉(zhuǎn)(Inversion of Control,縮寫為IoC),是面向?qū)ο缶幊讨械囊环N設(shè)計思想,可以用來降低代碼之間的耦合度,符合依賴倒置原則??刂品崔D(zhuǎn)的核心是:將對象的創(chuàng)建權(quán)交出去,將對象和對象之間關(guān)系的管理權(quán)交出去,由第三方容器來負(fù)責(zé)創(chuàng)建與維護(hù)??刂品崔D(zhuǎn)常見的實現(xiàn)方式:依賴注入(Dependency Injection,簡稱DI)。通常,依賴注入的實現(xiàn)又包括兩種方式:
- set方法注入
- 構(gòu)造方法注入
? Spring框架就是一個實現(xiàn)了IoC思想的框架。IoC可以認(rèn)為是一種全新的設(shè)計模式,但是理論和時間成熟相對較晚,并沒有包含在GoF中(GoF指的是23種設(shè)計模式)。
總結(jié)
? 通過對一個簡單用戶登錄系統(tǒng)的分析,我們了解到了在沒有采用現(xiàn)代框架時開發(fā)可能面臨的挑戰(zhàn):高耦合度的代碼難以維護(hù)和擴(kuò)展。遵循開閉原則(OCP)和依賴倒置原則(DIP),可以有效地降低這種耦合,提高代碼的復(fù)用性和可擴(kuò)展性。然而,手動管理對象創(chuàng)建和依賴關(guān)系仍然復(fù)雜且容易出錯。Spring框架通過引入控制反轉(zhuǎn)(IoC)概念,提供了一種優(yōu)雅的解決方案。它不僅簡化了對象的創(chuàng)建和依賴注入過程,還促進(jìn)了更清晰、模塊化的代碼結(jié)構(gòu),極大地提升了開發(fā)效率和軟件質(zhì)量。掌握這些設(shè)計原則與技術(shù)框架的應(yīng)用,可以幫助開發(fā)者構(gòu)建更加健壯、靈活和易于維護(hù)的軟件系統(tǒng)。