今天就跟大家聊聊有关如何在Java中运用依赖注入,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。
一、C++的诟病
C++最遭人诟病的地方就是定义一个类需要写两个文件,一个.h文件和一个.cpp文件。例如定义一个CMainFrame类,mainframe.h内容如下:
class CMainFrame : public CFrameWndEx{protected:CMainFrame();public:virtual ~CMainFrame();};
mainframe.cpp内容如下:
CMainFrame::CMainFrame(){} CMainFrame::~CMainFrame(){}
当需要给这个类添加一个方法时,需要同时修改.h文件和.cpp文件。例如新增一个DefWindowProc函数。需要在.h文件中增加该函数的声明。
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++的类定义代码中,一次变化需要修改两个文件,其维护的繁琐令人诟病。
二、Java的改进
然而Java的出现彻底解决了这个问题,一个类就对应一个.java文件(包括后来其他面向对象语言也秉承了这个思路,比如C#)。
比如一个LogService类用于对日志进行维护,起初只包含日志的增删功能,LogService.java代码如下。
public class LogService{public ServiceResult<Boolean> addLog (SysLogInfo logInfo) {......} public ServiceResult<Boolean> delLog (String id) {......}}
当需要增加一个updateLog方法时,仅需对LogService.java进行修改。
public class LogService{public ServiceResult<Boolean> addLog (SysLogInfo logInfo) {......} public ServiceResult<Boolean> delLog(String id) {......} public ServiceResult<Boolean> updateLog (SysLogInfo logInfo) {......} }
一切变得方便了很多。
三、误用导致的退步
但是最近在看一些基于Spring(SpringBoot、SpringMVC)框架写的代码时,发现很多类的代码又回到了C++的形式。例如在使用一个LogService时,开发人员首先定义了一个interface,在LogService.java中:
public interface LogService {ServiceResult<Boolean> addLog(SysLogInfo logInfo);ServiceResult<Boolean> delLog(String id);}
然后定义了一个该接口的实现类,在LogServiceImpl.java中:
public class LogServiceImpl implements LogService{@Overridepublic ServiceResult<Boolean> addLog(SysLogInfo logInfo) {......} @Overridepublic ServiceResult<Boolean> delLog(String id) {......}}
在需要实例化这个类的地方用了一个@Autowired注解注入。
public class LogController {@Autowiredprivate LogService logservice;}
在问及开发人员为什么要象这样做时,其给了一个自信的回答:这是面向接口编程!
注意:这个设计中LogService.java类似于C++中的.h文件,LogServiceImpl.java类似于C++中的.cpp文件,这两个文件共同定义了一个LogService类。当需要给这个类添加一个updateLog方法时,LogService.java和LogServiceImpl.java都需要被修改,又走回了C++的老路。这显然是对面向接口编程的曲解。如果这样都能算面向接口编程的话,那么C++就成了一门天然的面向接口编程的语言,还何必去学那些复杂的设计模式。
不过这样写代码有什么问题吗?其实也没有太大问题,只是代码繁琐一点而已(C++就是这样的)。只不过既然你选择了Java语言,却又写成了C++的样子,就好像在开一辆自动挡的汽车,却一直拨到手动模式驾驶一样。
四、正确理解面向接口编程
那么什么才是面向接口编程呢,其要点在于:接口是基于变化的抽象。在有可能变化的地方才需要接口。假设上面的例子中,写日志的动作同时存在3种不同的实现:
写到日志文件。
写到数据库。
写到本地的一个日志服务的UDP端口。
那么可以基于这个接口写3个不同的实现类:
public class LogServiceFile implements LogService{}
public class LogServiceDB implements LogService{}
public class LogServiceUdp implements LogService{}
当然此时如果还是使用下面的代码会报错,因为Autowired只能装配对应接口的唯一一个派生类的Bean,而此时存在3个派生类。
public class LogController {@Autowiredprivate LogService logservice;}
需要改进成类似下面这个样子,根据实际情况使用对应的派生类对象:
public class LogController {private LogService logservice;void writeLog(SysLogInfo logInfo){logservice = GetLogServiceInst();logservice.addLog(logInfo);}}
Java的优点是什么
1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程序;2. 面向对象;3. 分布性,Java是面向网络的语言;4. 鲁棒性,java提供自动垃圾收集来进行内存管理,防止程序员在管理内存时容易产生的错误。;5. 安全性,用于网络、分布环境下的Java必须防止病毒的入侵。6. 体系结构中立,只要安装了Java运行时系统,就可在任意处理器上运行。7. 可移植性,Java可以方便地移植到网络上的不同机器。8.解释执行,Java解释器直接对Java字节码进行解释执行。
看完上述内容,你们对如何在Java中运用依赖注入有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网行业资讯频道,感谢大家的支持。