Java基礎(chǔ)之教你如何正確運(yùn)用依賴注入
一、C++的詬病
C++最遭人詬病的地方就是定義一個(gè)類需要寫兩個(gè)文件,一個(gè).h文件和一個(gè).cpp文件。例如定義一個(gè)CMainFrame類,mainframe.h內(nèi)容如下:
class CMainFrame : public CFrameWndEx { protected: CMainFrame(); public: virtual ~CMainFrame(); };
mainframe.cpp內(nèi)容如下:
CMainFrame::CMainFrame() { } CMainFrame::~CMainFrame() { }
當(dāng)需要給這個(gè)類添加一個(gè)方法時(shí),需要同時(shí)修改.h文件和.cpp文件。例如新增一個(gè)DefWindowProc函數(shù)。需要在.h文件中增加該函數(shù)的聲明。
class CMainFrame : public CFrameWndEx { protected: CMainFrame(); public: virtual ~CMainFrame(); protected: virtual LRESULT DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam); };
mainframe.cpp中增加DefWindowProc的定義:
LRESULT CMainFrame::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if(message==WM_NCPAINT ) { if(bShow){ ShowWindow(SW_SHOW); } else { ShowWindow(SW_HIDE); } } return CFrameWndEx::DefWindowProc(message, wParam, lParam); }
可以看出C++的類定義代碼中,一次變化需要修改兩個(gè)文件,其維護(hù)的繁瑣令人詬病。
二、Java的改進(jìn)
然而Java的出現(xiàn)徹底解決了這個(gè)問題,一個(gè)類就對(duì)應(yīng)一個(gè).java文件(包括后來其他面向?qū)ο笳Z(yǔ)言也秉承了這個(gè)思路,比如C#)。
比如一個(gè)LogService類用于對(duì)日志進(jìn)行維護(hù),起初只包含日志的增刪功能,LogService.java代碼如下。
public class LogService{ public ServiceResult<Boolean> addLog (SysLogInfo logInfo) { ...... } public ServiceResult<Boolean> delLog (String id) { ...... } }
當(dāng)需要增加一個(gè)updateLog方法時(shí),僅需對(duì)LogService.java進(jìn)行修改。
public class LogService{ public ServiceResult<Boolean> addLog (SysLogInfo logInfo) { ...... } public ServiceResult<Boolean> delLog(String id) { ...... } public ServiceResult<Boolean> updateLog (SysLogInfo logInfo) { ...... } }
一切變得方便了很多。
三、誤用導(dǎo)致的退步
但是最近在看一些基于Spring(SpringBoot、SpringMVC)框架寫的代碼時(shí),發(fā)現(xiàn)很多類的代碼又回到了C++的形式。例如在使用一個(gè)LogService時(shí),開發(fā)人員首先定義了一個(gè)interface,在LogService.java中:
public interface LogService { ServiceResult<Boolean> addLog(SysLogInfo logInfo); ServiceResult<Boolean> delLog(String id); }
然后定義了一個(gè)該接口的實(shí)現(xiàn)類,在LogServiceImpl.java中:
public class LogServiceImpl implements LogService{ @Override public ServiceResult<Boolean> addLog(SysLogInfo logInfo) { ...... } @Override public ServiceResult<Boolean> delLog(String id) { ...... } }
在需要實(shí)例化這個(gè)類的地方用了一個(gè)@Autowired注解注入。
public class LogController { @Autowired private LogService logservice; }
在問及開發(fā)人員為什么要象這樣做時(shí),其給了一個(gè)自信的回答:這是面向接口編程!
注意:這個(gè)設(shè)計(jì)中LogService.java類似于C++中的.h文件,LogServiceImpl.java類似于C++中的.cpp文件,這兩個(gè)文件共同定義了一個(gè)LogService類。當(dāng)需要給這個(gè)類添加一個(gè)updateLog方法時(shí),LogService.java和LogServiceImpl.java都需要被修改,又走回了C++的老路。這顯然是對(duì)面向接口編程的曲解。如果這樣都能算面向接口編程的話,那么C++就成了一門天然的面向接口編程的語(yǔ)言,還何必去學(xué)那些復(fù)雜的設(shè)計(jì)模式。
不過這樣寫代碼有什么問題嗎?其實(shí)也沒有太大問題,只是代碼繁瑣一點(diǎn)而已(C++就是這樣的)。只不過既然你選擇了Java語(yǔ)言,卻又寫成了C++的樣子,就好像在開一輛自動(dòng)擋的汽車,卻一直撥到手動(dòng)模式駕駛一樣。
四、正確理解面向接口編程
那么什么才是面向接口編程呢,其要點(diǎn)在于:接口是基于變化的抽象。在有可能變化的地方才需要接口。假設(shè)上面的例子中,寫日志的動(dòng)作同時(shí)存在3種不同的實(shí)現(xiàn):
1.寫到日志文件。
2.寫到數(shù)據(jù)庫(kù)。
3.寫到本地的一個(gè)日志服務(wù)的UDP端口。
那么可以基于這個(gè)接口寫3個(gè)不同的實(shí)現(xiàn)類:
public class LogServiceFile implements LogService{ }
public class LogServiceDB implements LogService{ }
public class LogServiceUdp implements LogService{ }
當(dāng)然此時(shí)如果還是使用下面的代碼會(huì)報(bào)錯(cuò),因?yàn)锳utowired只能裝配對(duì)應(yīng)接口的唯一一個(gè)派生類的Bean,而此時(shí)存在3個(gè)派生類。
public class LogController { @Autowired private LogService logservice; }
需要改進(jìn)成類似下面這個(gè)樣子,根據(jù)實(shí)際情況使用對(duì)應(yīng)的派生類對(duì)象:
public class LogController { private LogService logservice; void writeLog(SysLogInfo logInfo){ logservice = GetLogServiceInst(); logservice.addLog(logInfo); } }
如果你的接口只有一個(gè)實(shí)現(xiàn)類,而且在可以遇見的將來也不會(huì)有其他實(shí)現(xiàn)類,那么還是建議你能簡(jiǎn)化一點(diǎn),采用最基本的類定義方式,減少代碼的復(fù)雜性。
到此這篇關(guān)于教你如何正確運(yùn)用Java依賴注入的文章就介紹到這了,更多相關(guān)Java依賴注入內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java版C語(yǔ)言版簡(jiǎn)單使用靜態(tài)語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的方法
本文給大家分享java版和C語(yǔ)言版簡(jiǎn)單使用靜態(tài)語(yǔ)言實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-10-10SpringBoot 項(xiàng)目使用hutool 工具進(jìn)行 http 接口調(diào)用的處理方
在實(shí)際的開發(fā)過程中一個(gè)互聯(lián)網(wǎng)的項(xiàng)目來說 ,有可能會(huì)涉及到調(diào)用外部接口的實(shí)際業(yè)務(wù)場(chǎng)景,下面通過本文給大家介紹SpringBoot 項(xiàng)目 使用hutool 工具進(jìn)行 http 接口調(diào)用的處理方法,需要的朋友可以參考下2022-06-06一文秒懂IDEA中每天都在用的Project Structure知識(shí)
這篇文章主要介紹了一文秒懂IDEA中每天都在用的Project Structure知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10springboot+swagger2.10.5+mybatis-plus 入門詳解
這篇文章主要介紹了springboot+swagger2.10.5+mybatis-plus 入門,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Spring的Ioc模擬實(shí)現(xiàn)詳細(xì)介紹
這篇文章主要介紹了Spring的Ioc模擬實(shí)現(xiàn)詳細(xì)介紹,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11mybatis?@InsertProvider報(bào)錯(cuò)問題及解決
這篇文章主要介紹了mybatis?@InsertProvider報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07MyBatis動(dòng)態(tài)<if>標(biāo)簽的使用
本文主要介紹了MyBatis動(dòng)態(tài)<if>標(biāo)簽的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05