[請益] Spring boot的依賴注入降低耦合的例子

作者: ntpuisbest (阿龍)   2022-03-31 21:06:08
推文有個連結有解答我的疑惑
感謝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
作者: Keade0325 (pinpin)   2022-03-31 21:27:00
當有需要抽換實作的時候
作者: MoonCode (MoonCode)   2022-03-31 21:29:00
在你理解前應該先完全不靠 spring 的功能,只靠 java本身來做依賴注入,然後判斷有沒有真的有效就是你的類可以把依賴的東西改用mock替換。那等你都弄好後開始不斷的堆積業務邏輯時,就會發現初始化的地方會有一堆 new constructor 然後再傳進另一個 new constructor,那這時候一個像 spring 這樣的框架就可以用各種方式來幫助你避免自己寫這些 new,就可以避免一些麻煩。 但我是喜歡自己手動操作啦,靠框架的話整個生命周期很難看懂。
作者: wulouise (在線上!=在電腦前)   2022-03-31 21:33:00
我覺得任何DI framework都跟singleton 87%像邪惡
作者: illya65536 (illya65536)   2022-03-31 21:35:00
個人覺得方便測試時去 mock,平常用 Laravel 的經驗
作者: bheegrl   2022-03-31 21:39:00
Polymorphism通常是autowired interface啦,再依參數配置決定要使用
作者: Keade0325 (pinpin)   2022-03-31 21:43:00
簡單的例子就是更換DB driver
作者: bheegrl   2022-03-31 21:44:00
哪個實作上面那interface的component
作者: bronx0807 (堅持需要練習)   2022-03-31 22:00:00
@Autowired只是依類名或型別幫你在Spring容器生物件DI與IoC才是低耦合的關鍵,與@Autowired無關
作者: ntpuisbest (阿龍)   2022-03-31 22:03:00
可是如果DI要我自己寫的話,Spring幫我做了啥,單純的控制反轉有降低耦合嗎?
作者: bronx0807 (堅持需要練習)   2022-03-31 22:04:00
Spring幫你new物件並注入到使用的對象屬性中還有上面Dao1 Dao2例子有誤,DI是從外面set進來
作者: ntpuisbest (阿龍)   2022-03-31 22:07:00
我的第一個例子應該是DI吧,把ADDRESS注入到Employee當中即使用Spring,不用自己寫new,可是建構子還是要自己寫阿,降低了什麼功夫呢
作者: bronx0807 (堅持需要練習)   2022-03-31 22:10:00
幫你搞定層層的依賴關係你可以試試不用Spring自己寫依賴注入,你就知道差異
作者: ntpuisbest (阿龍)   2022-03-31 22:13:00
我第一個例子就沒有依賴Spring 阿 地址跟員工那個
作者: foreverk (文藝青年)   2022-03-31 22:16:00
spring就是做掉你自己舉的例子,不然誰要往兩個class傳dao進去?你後面舉的自己new dao的行為,就等於你前面沒有做DI的舉例了
作者: MoonCode (MoonCode)   2022-03-31 22:19:00
我看下來只覺得原po寫太少了 哈哈哈哈
作者: foreverk (文藝青年)   2022-03-31 22:24:00
今天是dao你感覺比較單純無法,如果你要new的是service呢?視你的專案複雜度,一個service可能會有10幾20個建構子需要你自己new出來,而service互相依賴不會只有有兩個這樣簡單的情況
作者: bluelink (淡水小麵仔)   2022-03-31 22:33:00
可以看看跟qualifier的搭配
作者: bronx0807 (堅持需要練習)   2022-03-31 22:40:00
作者: kirin021 (kirin)   2022-03-31 22:40:00
要以類別與類別間的關係來看是否降低耦合吧?降低耦合的定義應該不是叫大家可以少寫code哈哈
作者: bronx0807 (堅持需要練習)   2022-03-31 22:41:00
不用@Autowired就要寫上面連結中那坨new
作者: foreverk (文藝青年)   2022-03-31 22:41:00
20個dao只是一行嗎?那你試試new 20個都有20個dao的service其實有在寫mockito的應該都體會過,當service耦合太嚴重時,寫test有多痛苦,最後都會順便解耦XD
作者: atpx (秋雨的心情)   2022-03-31 22:44:00
你寫工具給別人用比較會需要. 寫商業邏輯不太用的到
作者: abadfriend (藍色憂鬱)   2022-03-31 22:46:00
不確定 @Qualifier 能不能解答到你的疑惑?
作者: atpx (秋雨的心情)   2022-03-31 22:46:00
運算的過程不想變動, 但又需要把產生的實例替換掉的情況下就用到你的例子
作者: ntpuisbest (阿龍)   2022-03-31 22:48:00
謝謝bron大,我好像懂了,qualfied還在看@@
作者: abccbaandy (敏)   2022-03-31 22:50:00
不懂正常,因為例子太爛,簡單的new感受不到這東西的用處你試試"new"個jdbc connection就知道了
作者: foreverk (文藝青年)   2022-03-31 22:52:00
會有spring好像沒幹事的錯覺,是因為作者是你自己,你可以掌控那些複雜的service建構子,當多人協作時有人需要使用你的service,還需要搞懂那些建構子的邏輯跟用法,那就是一場災難,更別提那個人的service立刻又跟那些建構子用途的物件耦合,每個人都這樣就沒完沒了
作者: lovdkkkk (dk)   2022-03-31 23:22:00
重點在 依賴於介面 而不依賴於實作要能自己 new, 就綁死實作的 package/class 了給 spring 生, 自己只綁介面定義 實作就可替換
作者: s06yji3 (阿南)   2022-04-01 00:16:00
降低耦合和少寫code是兩回事
作者: tttkkk (學到。)   2022-04-01 00:24:00
整篇看完了 你要補的地方是 code to interface 的概念先了解 interface 再來看 dependency injection 會較易懂例如你有個 Dao interface 他有兩個實作 Dao1 和 Dao2用 DI 可以在你的 Service 裡面去指定用哪一個實作其實你舉的 service 例子不是解耦合喔 試想你若真的要在service 中同時用到 Dao1 跟 Dao2 那怎會有解偶合的問題當你會需要偶爾使用Dao1 偶爾使用 Dao2 甚至未來改成Dao3才會需要解耦合 因為你把 Service 跟 Dao 解耦合了更改 Dao 實作時 就不會動到 Service
作者: x246libra (楓)   2022-04-01 01:19:00
你第一個例子,地址,通常不會視為DI吧,比較像ddd的value object
作者: lazarus1121 (...)   2022-04-01 01:38:00
我也有類似的問題,如果建構子會吃參數如果要在spring上是不是最好改寫為另外set進去比較好不然常常會寫一堆bean,好像沒有比較方便但如果要用時再抓來set,物件的命名又會很混亂
作者: handsomeLin (DoGLin)   2022-04-01 02:36:00
一句話:DI並不解決耦合問題,DI只是幫助你更輕鬆的測試並且轉換實作的時候不需要大量改動code
作者: godsparticle (阿粒)   2022-04-01 08:30:00
樓上正解
作者: foreverk (文藝青年)   2022-04-01 08:43:00
不管是依賴介面別依賴實作,還是用DI,都是解決掉你的耦合問題,才有後續帶來的輕鬆測試跟切換實作,避免大量改動code,他們都是解耦過程的一部分
作者: sharek (...)   2022-04-01 09:22:00
會感覺不到DI好處,大概只能親身經歷過痛過強耦合的project才比較能體會
作者: devilkool (對貓毛過敏的貓控)   2022-04-01 09:29:00
當你打算寫單元測試就會懂DI的好處了
作者: ssccg (23)   2022-04-01 10:25:00
@Autowired找到完全同一個concrete class的bean來注入本來就沒有降低耦合,可以找到相容的實作(實作interface的bean或subclass的bean)才有降低耦合
作者: tw11509 (John-117)   2022-04-01 10:40:00
Autowired介面,搭配profile註解,可以在不同環境使用不同實作關於di,spring in action有個騎士出任務的範例,還蠻有趣的
作者: vi000246 (Vi)   2022-04-01 13:45:00
你可以A一下91哥的文 id是landlord他有個土砲重構的範例滿不錯的
作者: MonyemLi (life)   2022-04-01 18:42:00
spring 只是稍微降低耦合。主要降低的是多用介面,多寫幾層
作者: superpandal   2022-04-01 23:51:00
不想講但還是講一下好了 它就只是偵測你包內的annotation並且儲存起來(map) 需要的時候取用初始化而已 依賴注入本身不是問題 問題是使用annotation的依賴注入 專案大了以後 一堆初始化流程你都不見得能夠掌握 更別說annotation設值所造成的影響然後這樣的初始化效能肯定比你直接new來的差介面的話更是扯 你直接改個類不就得了... 當然如果習慣非常好 用annotation也都無所謂 但你不一定是一一個人開發用這些框架有時候就不是人在使用工具 是人被工具玩更準確的是人寫工具的惡意 而非工具本身自主無腦開發你才有人生 耗在這沒意義的事情才糟糕
作者: ssccg (23)   2022-04-02 10:32:00
樓上肯定沒用到request、session、refresh scope才會覺得spring DI只是個map存起來這麼簡單
作者: superpandal   2022-04-02 22:42:00
當然不是講的這麼大致方向 剩下的就只是應用再應用講的這些真的要自己寫框架不難寫只是個人不會遇到一個問題解決了再創造一個名詞光看這些其實很容易眼花撩亂 還是學習真的知識比較好
作者: CoNsTaR ((const *))   2022-04-03 10:31:00
Java 哈哈 JavaOld school try hard language搞笑的語言就是只能搞笑
作者: tw11509 (John-117)   2022-04-03 21:17:00
去除掉springBoot,IoC、DI和DIP這些概念又不是Java獨有,說Java搞笑跟這篇文章的關聯真是無法理解!?
作者: CoNsTaR ((const *))   2022-04-04 13:21:00
樓上找給我看除了 Java 以外還有哪個語言什麼事都要 annotations ,設定檔,框架魔法和 reflection 才能做的?真的笑死
作者: tw11509 (John-117)   2022-04-04 21:15:00
嗯嗯,您說得對

Links booklink

Contact Us: admin [ a t ] ucptt.com