依賴注入的邏輯基于Java語言

對于一個廚師,要做一道菜。傳統的做法是:你需要什么食材,就自己去菜市場買什么。這意味著你必須知道去哪個菜市場、怎么挑選食材、怎么討價還價等等。你不僅要會做菜,還要會買菜,職責變得復雜了。

而依賴注入就像是有一個貼心的助手,他會提前把你需要的所有食材準備好,直接送到你手上。你只需要專心做菜就行了,不用操心食材從哪里來、怎么來的。

技術層面的深入理解

在軟件開發中,**依賴注入(Dependency Injection,簡稱DI)**是一種設計模式,它的核心思想是:不要讓對象自己創建它所依賴的其他對象,而是由外部容器來創建并注入這些依賴對象

傳統方式下,如果類A需要使用類B的功能,類A會在內部直接創建類B的實例。這就像廚師自己去買菜一樣,造成了緊耦合。依賴注入則是讓外部的"容器"來創建類B的實例,然后"注入"給類A使用。

為什么需要依賴注入?

  1. 降低耦合度:類不再負責創建它的依賴對象,只需要聲明需要什么依賴
  2. 提高可測試性:可以輕松地注入模擬對象進行單元測試
  3. 增強靈活性:可以在運行時動態地改變依賴關系
  4. 符合開閉原則:對擴展開放,對修改關閉

依賴注入的三種主要方式

  1. 構造器注入:通過構造函數參數注入依賴
  2. Setter注入:通過setter方法注入依賴
  3. 接口注入:通過實現特定接口來注入依賴

Java代碼示例演示

第一步:沒有依賴注入的傳統方式

// 數據庫服務類
class DatabaseService {public void save(String data) {System.out.println("保存數據到數據庫: " + data);}
}// 郵件服務類
class EmailService {public void sendEmail(String message) {System.out.println("發送郵件: " + message);}
}// 用戶服務類 - 傳統方式(緊耦合)
class UserService {private DatabaseService databaseService;private EmailService emailService;public UserService() {// 直接在內部創建依賴對象 - 這就是緊耦合的問題所在this.databaseService = new DatabaseService();this.emailService = new EmailService();}public void registerUser(String username) {// 保存用戶信息databaseService.save("用戶: " + username);// 發送歡迎郵件emailService.sendEmail("歡迎 " + username + " 注冊我們的系統!");}
}

問題分析:

  • UserService直接創建了DatabaseService和EmailService的實例
  • 如果要換成其他類型的數據庫或郵件服務,必須修改UserService的代碼
  • 難以進行單元測試,因為無法模擬這些依賴對象

第二步:使用依賴注入重構

首先定義接口,實現依賴倒置:

// 定義數據庫服務接口
interface DatabaseServiceInterface {void save(String data);
}// 定義郵件服務接口
interface EmailServiceInterface {void sendEmail(String message);
}// MySQL數據庫實現
class MySQLDatabaseService implements DatabaseServiceInterface {@Overridepublic void save(String data) {System.out.println("保存數據到MySQL數據庫: " + data);}
}// MongoDB數據庫實現
class MongoDatabaseService implements DatabaseServiceInterface {@Overridepublic void save(String data) {System.out.println("保存數據到MongoDB: " + data);}
}// SMTP郵件服務實現
class SMTPEmailService implements EmailServiceInterface {@Overridepublic void sendEmail(String message) {System.out.println("通過SMTP發送郵件: " + message);}
}// 短信服務實現(也可以發送通知)
class SMSService implements EmailServiceInterface {@Overridepublic void sendEmail(String message) {System.out.println("發送短信通知: " + message);}
}

第三步:構造器注入方式

class UserService {private final DatabaseServiceInterface databaseService;private final EmailServiceInterface emailService;// 通過構造器注入依賴public UserService(DatabaseServiceInterface databaseService, EmailServiceInterface emailService) {this.databaseService = databaseService;this.emailService = emailService;}public void registerUser(String username) {databaseService.save("用戶: " + username);emailService.sendEmail("歡迎 " + username + " 注冊我們的系統!");}
}

第四步:Setter注入方式

class UserServiceWithSetter {private DatabaseServiceInterface databaseService;private EmailServiceInterface emailService;// 通過setter方法注入依賴public void setDatabaseService(DatabaseServiceInterface databaseService) {this.databaseService = databaseService;}public void setEmailService(EmailServiceInterface emailService) {this.emailService = emailService;}public void registerUser(String username) {if (databaseService == null || emailService == null) {throw new IllegalStateException("依賴服務未正確注入!");}databaseService.save("用戶: " + username);emailService.sendEmail("歡迎 " + username + " 注冊我們的系統!");}
}

第五步:簡單的依賴注入容器

import java.util.HashMap;
import java.util.Map;// 簡單的依賴注入容器
class DIContainer {private Map<Class<?>, Object> services = new HashMap<>();// 注冊服務public <T> void register(Class<T> serviceType, T implementation) {services.put(serviceType, implementation);}// 獲取服務@SuppressWarnings("unchecked")public <T> T getService(Class<T> serviceType) {return (T) services.get(serviceType);}// 創建UserService實例,自動注入依賴public UserService createUserService() {DatabaseServiceInterface dbService = getService(DatabaseServiceInterface.class);EmailServiceInterface emailService = getService(EmailServiceInterface.class);if (dbService == null || emailService == null) {throw new IllegalStateException("必要的服務未注冊到容器中!");}return new UserService(dbService, emailService);}
}

第六步:完整的使用示例

public class DependencyInjectionDemo {public static void main(String[] args) {// 創建依賴注入容器DIContainer container = new DIContainer();// 注冊具體的實現到容器中container.register(DatabaseServiceInterface.class, new MySQLDatabaseService());container.register(EmailServiceInterface.class, new SMTPEmailService());// 通過容器創建UserService,依賴會自動注入UserService userService = container.createUserService();// 使用服務userService.registerUser("張三");System.out.println("\n--- 切換到不同的實現 ---");// 可以輕松切換到不同的實現container.register(DatabaseServiceInterface.class, new MongoDatabaseService());container.register(EmailServiceInterface.class, new SMSService());UserService userService2 = container.createUserService();userService2.registerUser("李四");System.out.println("\n--- 演示Setter注入 ---");// 演示Setter注入UserServiceWithSetter userServiceSetter = new UserServiceWithSetter();userServiceSetter.setDatabaseService(new MySQLDatabaseService());userServiceSetter.setEmailService(new SMTPEmailService());userServiceSetter.registerUser("王五");}
}

第七步:單元測試的便利性

// 模擬對象用于測試
class MockDatabaseService implements DatabaseServiceInterface {public boolean saveCalled = false;public String savedData = null;@Overridepublic void save(String data) {saveCalled = true;savedData = data;System.out.println("模擬保存: " + data);}
}class MockEmailService implements EmailServiceInterface {public boolean emailSent = false;public String sentMessage = null;@Overridepublic void sendEmail(String message) {emailSent = true;sentMessage = message;System.out.println("模擬發送郵件: " + message);}
}// 簡單的測試示例
class UserServiceTest {public static void testUserRegistration() {// 創建模擬對象MockDatabaseService mockDB = new MockDatabaseService();MockEmailService mockEmail = new MockEmailService();// 注入模擬對象UserService userService = new UserService(mockDB, mockEmail);// 執行測試userService.registerUser("測試用戶");// 驗證結果System.out.println("數據庫保存被調用: " + mockDB.saveCalled);System.out.println("保存的數據: " + mockDB.savedData);System.out.println("郵件發送被調用: " + mockEmail.emailSent);System.out.println("發送的郵件: " + mockEmail.sentMessage);}public static void main(String[] args) {System.out.println("=== 單元測試演示 ===");testUserRegistration();}
}

總結

依賴注入就像是一個智能的"服務管家",它負責管理和協調各個對象之間的依賴關系。通過這種方式:

  1. 代碼更加靈活:可以輕松地切換不同的實現
  2. 測試更加容易:可以注入模擬對象進行隔離測試
  3. 維護更加簡單:修改依賴關系不需要改動核心業務邏輯
  4. 擴展更加方便:添加新功能只需要實現接口并注冊到容器

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/90819.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/90819.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/90819.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

skywalking鏡像應用springboot的例子

目錄 1、skywalking-ui連接skywalking-oap服務失敗問題 2、k8s環境 檢查skywalking-oap服務狀態 3、本地iidea啟動服務連接skywalking oap服務 4、基于apache-skywalking-java-agent-9.4.0.tgz構建skywalking-agent鏡像 4.1、Dockerfile內容如下 4.2、AbstractBuilder.M…

3. java 堆和 JVM 內存結構

1. JVM介紹和運行流程-CSDN博客 2. 什么是程序計數器-CSDN博客 3. java 堆和 JVM 內存結構-CSDN博客 4. 虛擬機棧-CSDN博客 5. JVM 的方法區-CSDN博客 6. JVM直接內存-CSDN博客 7. JVM類加載器與雙親委派模型-CSDN博客 8. JVM類裝載的執行過程-CSDN博客 9. JVM垃圾回收…

UnityShader——SSAO

目錄 1.是什么 2.原理 3.各部分解釋 2.1.從屏幕空間到視圖空間 2.2.以法線半球為基&#xff0c;獲取隨機向量 2.3.應用偏移&#xff0c;并將其轉換為uv坐標 2.4.獲取深度 2.5.比較并計算貢獻 2.6.最后計算 4.改進 4.1.平滑過渡 4.2.模糊 5.變量和語句解釋 5.1._D…

【設計模式】外觀模式(門面模式)

外觀模式&#xff08;Facade Pattern&#xff09;詳解一、外觀模式簡介 外觀模式&#xff08;Facade Pattern&#xff09; 是一種 結構型設計模式&#xff0c;它為一個復雜的子系統提供一個統一的高層接口&#xff0c;使得子系統更容易使用。 外觀模式又稱為門面模式&#xff0…

【6.1.1 漫畫分庫分表】

漫畫分庫分表 “數據量大了不可怕&#xff0c;可怕的是不知道如何優雅地拆分。” &#x1f3ad; 人物介紹 架構師老王&#xff1a;資深數據庫架構專家&#xff0c;精通各種分庫分表方案Java小明&#xff1a;對分庫分表充滿疑問的開發者ShardingSphere師傅&#xff1a;Apache S…

Tomcat問題:啟動腳本startup.bat中文亂碼問題解決

一、問題描述 我們第一次下載或者打開Tomcat時可能在控制臺會出現中文亂碼問題二、解決辦法 我的是8.x版本的tomcat用notepad打開&#xff1a;logging.properties 找到&#xff1a;java.util.logging.ConsoleHandler.encoding設置成GBK&#xff0c;重啟tomcat即可

Linux中Gitee的使用

一、Gitee簡介&#xff1a;Gitee&#xff08;碼云&#xff09;是中國的一個代碼托管和協作開發平臺&#xff0c;類似于GitHub或GitLab&#xff0c;主要面向開發者提供代碼管理、項目協作及開源生態服務。適用場景個人開發者&#xff1a;托管私有代碼或參與開源項目。中小企業&a…

Oracle大表數據清理優化與注意事項詳解

一、性能優化策略 1. 批量處理優化批量大小選擇&#xff1a; 小批量(1,000-10,000行)&#xff1a;減少UNDO生成&#xff0c;但需要更多提交次數中批量(10,000-100,000行)&#xff1a;平衡性能與資源消耗大批量(100,000行)&#xff1a;適合高配置環境&#xff0c;但需監控資源使…

Anaconda及Conda介紹及使用

文章目錄Anaconda簡介為什么選擇 Anaconda&#xff1f;Anaconda 安裝Win 平臺macOS 平臺Linux 平臺Anaconda 界面使用Conda簡介Conda下載安裝conda 命令環境管理包管理其他常用命令Jupyter Notebook&#xff08;可選&#xff09;Anaconda簡介 Anaconda 是一個數據科學和機器學…

外包干了一周,技術明顯退步

我是一名本科生&#xff0c;自2019年起&#xff0c;我便在南京某軟件公司擔任功能測試的工作。這份工作雖然穩定&#xff0c;但日復一日的重復性工作讓我逐漸陷入了舒適區&#xff0c;失去了前進的動力。兩年的時光匆匆流逝&#xff0c;我卻在原地踏步&#xff0c;技術沒有絲毫…

【QT】多線程相關教程

一、核心概念與 Qt 線程模型 1.線程與進程的區別: 線程是程序執行的最小單元&#xff0c;進程是資源分配的最小單元&#xff0c;線程共享進程的內存空間(堆&#xff0c;全局變量等)&#xff0c;而進程擁有獨立的內存空間。Qt線程只要關注同一進程內的并發。 2.為什么使用多線程…

VS 版本更新git安全保護問題的解決

問題&#xff1a;我可能移動了一個VS C# 項目&#xff0c;然后&#xff0c;發現里面的git版本檢測不能用了 正在打開存儲庫: X:\Prj_C#\3D fatal: detected dubious ownership in repository at X:/Prj_C#/3DSnapCatch X:/Prj_C#/3D is owned by:S-1-5-32-544 but the current …

Git常用命令一覽

Git 是基于 Linux內核開發的版本控制工具。與常用的版本控制工具 CVS, Subversion 等不同&#xff0c;它采用了分布式版本庫的方式&#xff0c;不必服務器端軟件支持&#xff08;ps&#xff1a;這得分是用什么樣的服務端&#xff0c;使用http協議或者git協議等不太一樣。并且在…

基于 JSON 文件定位圖片缺陷點并保存

基于JSON的圖片缺陷處理流程 ├── 1. 輸入檢查 │ ├── 驗證圖片文件是否存在 │ └── 驗證JSON文件是否存在 │ ├── 2. 數據加載 │ ├── 打開并加載圖片 │ └── 讀取并解析JSON文件 │ ├── 3. 缺陷信息提取 │ ├── 檢查JSON中是否存在shapes字…

Redis基礎學習(五大值數據類型的常用操作命令)

目錄 一、Redis基本知識與Redis鍵&#xff08;key&#xff09;常用操作命令。 二、Redis的五大值的數據類型。&#xff08;value&#xff09; 三、Redis關于鍵&#xff08;key&#xff09;的值常用操作指令表格統計。 &#xff08;1&#xff09;字符串&#xff08;String&#…

Ubuntu——辦公軟件 LibreOffice 安裝與使用指南

十四、LibreOffice 安裝與使用1、核心組件組件????圖標????對應MS Office????核心功能定位????Writer??&#x1f4dd;Word專業文檔處理與排版??Calc??&#x1f4ca;Excel數據計算與分析??Impress??&#x1f3ac;PowerPoint演示文稿制作??Draw??&…

Securecrt丟失tab以及終端重新配色

今天在使用 Securecrt 的時候&#xff0c;發現 Securecrt 的 tab 標簽消失不見了&#xff0c;仔細回想起來&#xff0c;應該是上一次誤按了 alt enter 最大化&#xff0c;然后導致配置丟失的問題 還有表現就是菜單中的 Session Tabs 無論勾選還是不勾選都沒有任何變化&#xf…

frp搭建內網穿透教程

frp搭建內網穿透教程 步驟1&#xff1a;準備工作 公網服務器&#xff1a;需要一臺具有公網IP的服務器作為中轉服務器&#xff0c;安裝frp服務器端&#xff08;frps&#xff09;。內網設備&#xff1a;需要暴露服務的內網設備&#xff0c;安裝frp客戶端&#xff08;frpc&#xf…

【JavaEE進階】圖書管理系統(未完待續)

目錄 用戶登錄 添加圖書 圖書列表 修改圖書 刪除圖書 批量刪除 攔截器 &#x1f343;前言 什么是攔截器? 攔截器的基本使用 自定義攔截器 注冊配置攔截器 攔截路徑 攔截器執行流程 項目實現統一攔截 定義攔截器 注冊配置攔截器 前?圖書管理系統, 咱們只完成了??登錄和圖書列…

基于同花順API的熊市與牛市識別模型開發及因子分析

基于同花順API的熊市與牛市識別模型開發及因子分析 1. 引言 1.1 研究背景與意義 金融市場中的牛市與熊市識別一直是投資者和研究人員關注的重點問題。牛市(Bull Market)通常指價格持續上漲的市場環境,投資者信心充足,交易活躍;而熊市(Bear Market)則指價格持續下跌的市場…