看板 Soft_Job 關於我們 聯絡資訊
推文有個連結有解答我的疑惑 感謝bron大 文章有點長 先說說我對依賴注入的理解 Spring boot 依賴注入大致有三種方式 透過建構子的 透過setter的 或是 field 這三種都可以透過@Autowired註解來達到依賴注入的效果 我自己想到的建構子的舉例是 假設有兩個類 Address 和 Employee好了 1. public class Address { String Country; String City; String Street; public Address(String country, String city, String street) { Country = country; City = city; Street = street; } } 2. public class Employee { String sex; String name; Address address; // 沒有依賴注入的方式 public Employee(String Country,String City,String Street,String sex, String name ) { this.sex=sex; this.address = new Address( Country, City,Street ); this.name=name; } // 有依賴注入的方式 public Employee(String sex, String name, Address address) { this.sex = sex; this.name = name; this.address = address; } } 在上面的例子當中可以發現,如果哪一天 Address這個類新增了一個屬性叫 phoneNumber好了 沒有依賴注入的方式,必須要更改 Employee 的 this.address =new Address(Country,City,Street,phoneNumber) 而有依賴注入的方式確實降低了耦合 因為他不用更改Employee的建構方式 所以我理解依賴注入可以降低耦合 所以我理解依賴注入可以降低耦合 所以我理解依賴注入可以降低耦合 但我的問題是Spring boot 的 autowird annotation 有幫助我們降低耦合嗎 在常見的開發中 我們經常都會有 Dao 以及 Service 假設我有兩個 Dao 好了 分別是 Dao1 和 Dao2 以及一個Service Dao1 public class Dao { public void sayhi() { System.out.println("hello"); } } Dao1 public class Dao { public void sayhi() { System.out.println("hello"); } } Dao2 public class Dao2 { public void saygoodbye() { System.out.println("say goodbye"); } } 如果我不在service上面使用autowired 我的service會是 public class Service { Dao1 dao=new Dao1(); Dao2 dao2=new Dao2(); public void sayhi() { dao.sayhi(); } public void saygoodbye() { dao2.saygoodbye(); } } 如果我使用了@Autowired註解 那我只是將 Dao1 dao=new Dao1(); Dao2 dao2=new Dao2(); 替換成 @Autowired Dao1 dao @Autowired Dao2 dao2 我想請問所以我使用了Autowired註解 我知道我可以不需要使用new 來建構實體 但 Spring 真的有幫我降低耦合嗎 即使我換成 setter 配合 autowired的方式好了 那個 setter也是要我自己去撰寫 Spring 幫我降低了耦合甚麼? 我的問題簡單來說就是 我知道依賴注入可以降低耦合 但Spring boot透過 @Autowired註解幫我降低耦合在哪 謝謝 p.s 因為面試的時候常常被面試官問說懂不懂甚麼是 控制反轉還有DI,我基本上舉例都舉 Address還有 Employee的例子 但當我反問下面例子的時候,他們好像也說要再回去想一下... 只有其中一個就說更複雜的例子會用到,但也沒說甚麼是更複雜的例子QQ -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.167.157.11 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/Soft_Job/M.1648731970.A.382.html ※ 編輯: ntpuisbest (49.216.186.239 臺灣), 03/31/2022 21:14:38
Keade0325: 當有需要抽換實作的時候03/31 21:27
MoonCode: 在你理解前應該先完全不靠 spring 的功能,只靠 java03/31 21:29
MoonCode: 本身來做依賴注入,然後判斷有沒有真的有效就是你的類03/31 21:29
MoonCode: 可以把依賴的東西改用mock替換。那等你都弄好後開始不03/31 21:29
MoonCode: 斷的堆積業務邏輯時,就會發現初始化的地方會有一堆 n03/31 21:29
MoonCode: ew constructor 然後再傳進另一個 new constructor,那03/31 21:29
MoonCode: 這時候一個像 spring 這樣的框架就可以用各種方式來幫03/31 21:29
MoonCode: 助你避免自己寫這些 new,就可以避免一些麻煩。 但我是03/31 21:29
MoonCode: 喜歡自己手動操作啦,靠框架的話整個生命周期很難看懂03/31 21:29
MoonCode: 。03/31 21:29
wulouise: 我覺得任何DI framework都跟singleton 87%像邪惡03/31 21:33
illya65536: 個人覺得方便測試時去 mock,平常用 Laravel 的經驗03/31 21:35
bheegrl: Polymorphism03/31 21:39
bheegrl: 通常是autowired interface啦,再依參數配置決定要使用03/31 21:42
Keade0325: 簡單的例子就是更換DB driver03/31 21:43
bheegrl: 哪個實作上面那interface的component03/31 21:44
bronx0807: @Autowired只是依類名或型別幫你在Spring容器生物件03/31 22:00
bronx0807: DI與IoC才是低耦合的關鍵,與@Autowired無關03/31 22:01
ntpuisbest: 可是如果DI要我自己寫的話,Spring幫我做了啥,單純03/31 22:03
ntpuisbest: 的控制反轉有降低耦合嗎?03/31 22:03
bronx0807: Spring幫你new物件並注入到使用的對象屬性中 03/31 22:04
bronx0807: 還有上面Dao1 Dao2例子有誤,DI是從外面set進來03/31 22:05
ntpuisbest: 我的第一個例子應該是DI吧,把ADDRESS注入到Employee03/31 22:07
ntpuisbest: 當中03/31 22:07
ntpuisbest: 即使用Spring,不用自己寫new,可是建構子還是要自己寫03/31 22:08
ntpuisbest: 阿,降低了什麼功夫呢03/31 22:08
bronx0807: 幫你搞定層層的依賴關係03/31 22:10
bronx0807: 你可以試試不用Spring自己寫依賴注入,你就知道差異03/31 22:10
ntpuisbest: 我第一個例子就沒有依賴Spring 阿 地址跟員工那個03/31 22:13
foreverk: spring就是做掉你自己舉的例子,不然誰要往兩個class傳03/31 22:16
foreverk: dao進去?03/31 22:16
foreverk: 你後面舉的自己new dao的行為,就等於你前面沒有做DI的03/31 22:18
foreverk: 舉例了03/31 22:18
MoonCode: 我看下來只覺得原po寫太少了 哈哈哈哈03/31 22:19
foreverk: 今天是dao你感覺比較單純無法,如果你要new的是service03/31 22:24
foreverk: 呢?視你的專案複雜度,一個service可能會有10幾20個建03/31 22:24
foreverk: 構子需要你自己new出來,而service互相依賴不會只有有03/31 22:24
foreverk: 兩個這樣簡單的情況03/31 22:24
我有試著在Controller當中去new service @RestController public class Controller { Service service=new Service( ); @GetMapping("test") public void saysomething() { service.saygoodbye(); service.sayhi(); } } 即使Service 裡面需要20個DAO好了 在Controller裡面new Service不也一樣只要 一行 Service service=new Service( ); 另外如果是setter 或是 Constructor方式的 DI 就我的理解 setter和建構子也是要自己寫 Spring 不會幫你產生 那我這樣看起來好像只是幫你從 new 換成了 @Autowired 這樣真的看不太出來 降低了甚麼耦合 因為建構子也是要自己寫啊 我覺得我好像陷入了泥淖中了QQ 翻了很多網頁,舉的例子大都跟我自己舉的 員工還有地址的差不多 ※ 編輯: ntpuisbest (118.167.157.11 臺灣), 03/31/2022 22:36:56
bluelink: 可以看看跟qualifier的搭配03/31 22:33
bronx0807: https://code.labstack.com/Raualw2G03/31 22:40
kirin021: 要以類別與類別間的關係來看是否降低耦合吧?03/31 22:40
kirin021: 降低耦合的定義應該不是叫大家可以少寫code哈哈03/31 22:40
bronx0807: 不用@Autowired就要寫上面連結中那坨new03/31 22:41
foreverk: 20個dao只是一行嗎?那你試試new 20個都有20個dao的ser03/31 22:41
foreverk: vice03/31 22:41
foreverk: 其實有在寫mockito的應該都體會過,當service耦合太嚴03/31 22:43
foreverk: 重時,寫test有多痛苦,最後都會順便解耦XD03/31 22:43
atpx: 你寫工具給別人用比較會需要. 寫商業邏輯不太用的到03/31 22:44
abadfriend: 不確定 @Qualifier 能不能解答到你的疑惑?03/31 22:46
atpx: 運算的過程不想變動, 但又需要把產生的實例替換掉的情況下03/31 22:46
atpx: 就用到你的例子03/31 22:46
ntpuisbest: 謝謝bron大,我好像懂了,qualfied還在看@@03/31 22:48
abccbaandy: 不懂正常,因為例子太爛,簡單的new感受不到這東西的03/31 22:50
abccbaandy: 用處03/31 22:50
abccbaandy: 你試試"new"個jdbc connection就知道了03/31 22:52
foreverk: 會有spring好像沒幹事的錯覺,是因為作者是你自己,你03/31 22:52
foreverk: 可以掌控那些複雜的service建構子,當多人協作時有人需03/31 22:52
foreverk: 要使用你的service,還需要搞懂那些建構子的邏輯跟用法03/31 22:52
foreverk: ,那就是一場災難,更別提那個人的service立刻又跟那些03/31 22:52
foreverk: 建構子用途的物件耦合,每個人都這樣就沒完沒了03/31 22:52
lovdkkkk: 重點在 依賴於介面 而不依賴於實作03/31 23:22
lovdkkkk: 要能自己 new, 就綁死實作的 package/class 了03/31 23:23
lovdkkkk: 給 spring 生, 自己只綁介面定義 實作就可替換03/31 23:24
s06yji3: 降低耦合和少寫code是兩回事04/01 00:16
tttkkk: 整篇看完了 你要補的地方是 code to interface 的概念04/01 00:24
tttkkk: 先了解 interface 再來看 dependency injection 會較易懂04/01 00:25
tttkkk: 例如你有個 Dao interface 他有兩個實作 Dao1 和 Dao204/01 00:26
tttkkk: 用 DI 可以在你的 Service 裡面去指定用哪一個實作04/01 00:26
感謝上面所有大大 尤其是bron大,謝謝 ok 謝謝,我對介面的理解只有降低耦合 但跟di的關聯還沒補上 謝謝 ※ 編輯: ntpuisbest (49.216.186.239 臺灣), 04/01/2022 00:35:55
tttkkk: 其實你舉的 service 例子不是解耦合喔 試想你若真的要在 04/01 00:39
tttkkk: service 中同時用到 Dao1 跟 Dao2 那怎會有解偶合的問題 04/01 00:39
tttkkk: 當你會需要偶爾使用Dao1 偶爾使用 Dao2 甚至未來改成Dao3 04/01 00:41
tttkkk: 才會需要解耦合 因為你把 Service 跟 Dao 解耦合了 04/01 00:42
tttkkk: 更改 Dao 實作時 就不會動到 Service 04/01 00:43
x246libra: 你第一個例子,地址,通常不會視為DI吧,比較像ddd的v 04/01 01:19
x246libra: alue object 04/01 01:19
lazarus1121: 我也有類似的問題,如果建構子會吃參數 04/01 01:38
lazarus1121: 如果要在spring上是不是最好改寫為另外set進去比較好 04/01 01:39
lazarus1121: 不然常常會寫一堆bean,好像沒有比較方便 04/01 02:01
lazarus1121: 但如果要用時再抓來set,物件的命名又會很混亂 04/01 02:07
handsomeLin: 一句話:DI並不解決耦合問題,DI只是幫助你更輕鬆的 04/01 02:36
handsomeLin: 測試並且轉換實作的時候不需要大量改動code 04/01 02:36
godsparticle: 樓上正解 04/01 08:30
foreverk: 不管是依賴介面別依賴實作,還是用DI,都是解決掉你的 04/01 08:43
foreverk: 耦合問題,才有後續帶來的輕鬆測試跟切換實作,避免大 04/01 08:43
foreverk: 量改動code,他們都是解耦過程的一部分 04/01 08:43
sharek: 會感覺不到DI好處,大概只能親身經歷過痛過強耦合的proje 04/01 09:22
sharek: ct才比較能體會 04/01 09:22
devilkool: 當你打算寫單元測試就會懂DI的好處了 04/01 09:29
ssccg: @Autowired找到完全同一個concrete class的bean來注入本來 04/01 10:25
ssccg: 就沒有降低耦合,可以找到相容的實作(實作interface的bean 04/01 10:27
ssccg: 或subclass的bean)才有降低耦合 04/01 10:27
tw11509: Autowired介面,搭配profile註解,可以在不同環境使用不 04/01 10:40
tw11509: 同實作 04/01 10:40
tw11509: 關於di,spring in action有個騎士出任務的範例,還蠻有 04/01 10:52
tw11509: 趣的 04/01 10:52
vi000246: 你可以A一下91哥的文 id是landlord 04/01 13:45
vi000246: 他有個土砲重構的範例滿不錯的 04/01 13:45
MonyemLi: spring 只是稍微降低耦合。主要降低的是多用介面,多寫 04/01 18:42
MonyemLi: 幾層 04/01 18:42
superpandal: 不想講但還是講一下好了 它就只是偵測你包內的 04/01 23:51
superpandal: annotation並且儲存起來(map) 需要的時候取用初始化 04/01 23:51
superpandal: 而已 依賴注入本身不是問題 問題是使用annotation的 04/01 23:52
superpandal: 依賴注入 專案大了以後 一堆初始化流程你都不見得能 04/01 23:53
superpandal: 夠掌握 更別說annotation設值所造成的影響 04/01 23:54
superpandal: 然後這樣的初始化效能肯定比你直接new來的差 04/01 23:55
superpandal: 介面的話更是扯 你直接改個類不就得了... 當然如果 04/01 23:57
superpandal: 習慣非常好 用annotation也都無所謂 但你不一定是一 04/01 23:57
superpandal: 一個人開發 04/01 23:57
superpandal: 用這些框架有時候就不是人在使用工具 是人被工具玩 04/02 00:00
superpandal: 更準確的是人寫工具的惡意 而非工具本身自主 04/02 00:01
superpandal: 無腦開發你才有人生 耗在這沒意義的事情才糟糕 04/02 00:06
ssccg: 樓上肯定沒用到request、session、refresh scope 04/02 10:32
ssccg: 才會覺得spring DI只是個map存起來這麼簡單 04/02 10:32
superpandal: 當然不是講的這麼大致方向 剩下的就只是應用再應用 04/02 22:42
superpandal: 講的這些真的要自己寫框架不難寫 04/02 22:44
superpandal: 只是個人不會遇到一個問題解決了再創造一個名詞 04/02 22:46
superpandal: 光看這些其實很容易眼花撩亂 還是學習真的知識比較好 04/02 22:48
CoNsTaR: Java 哈哈 Java 04/03 10:31
CoNsTaR: Old school try hard language 04/03 10:31
CoNsTaR: 搞笑的語言就是只能搞笑 04/03 10:31
tw11509: 去除掉springBoot,IoC、DI和DIP這些概念又不是Java獨有 04/03 21:17
tw11509: ,說Java搞笑跟這篇文章的關聯真是無法理解!? 04/03 21:17
CoNsTaR: 樓上找給我看除了 Java 以外還有哪個語言什麼事都要 anno 04/04 13:21
CoNsTaR: tations ,設定檔,框架魔法和 reflection 才能做的?真 04/04 13:21
CoNsTaR: 的笑死 04/04 13:21
CoNsTaR: https://i.imgur.com/wAMYYbI.png 04/04 14:04
tw11509: 嗯嗯,您說得對 04/04 21:15