PTT推薦

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

看板Soft_Job標題[請益] Spring boot的依賴注入降低耦合的例子作者
ntpuisbest
(阿龍)
時間推噓25 推:25 噓:0 →:102

推文有個連結有解答我的疑惑

感謝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留言評論
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.167.157.11 (臺灣)
PTT 網址
※ 編輯: ntpuisbest (49.216.186.239 臺灣), 03/31/2022 21:14:38

Keade032503/31 21:27當有需要抽換實作的時候

MoonCode03/31 21:29在你理解前應該先完全不靠 spring 的功能,只靠 java

MoonCode03/31 21:29本身來做依賴注入,然後判斷有沒有真的有效就是你的類

MoonCode03/31 21:29可以把依賴的東西改用mock替換。那等你都弄好後開始不

MoonCode03/31 21:29斷的堆積業務邏輯時,就會發現初始化的地方會有一堆 n

MoonCode03/31 21:29ew constructor 然後再傳進另一個 new constructor,那

MoonCode03/31 21:29這時候一個像 spring 這樣的框架就可以用各種方式來幫

MoonCode03/31 21:29助你避免自己寫這些 new,就可以避免一些麻煩。 但我是

MoonCode03/31 21:29喜歡自己手動操作啦,靠框架的話整個生命周期很難看懂

MoonCode03/31 21:29

wulouise03/31 21:33我覺得任何DI framework都跟singleton 87%像邪惡

illya6553603/31 21:35個人覺得方便測試時去 mock,平常用 Laravel 的經驗

bheegrl03/31 21:39Polymorphism

bheegrl03/31 21:42通常是autowired interface啦,再依參數配置決定要使用

Keade032503/31 21:43簡單的例子就是更換DB driver

bheegrl03/31 21:44哪個實作上面那interface的component

bronx080703/31 22:00@Autowired只是依類名或型別幫你在Spring容器生物件

bronx080703/31 22:01DI與IoC才是低耦合的關鍵,與@Autowired無關

ntpuisbest03/31 22:03可是如果DI要我自己寫的話,Spring幫我做了啥,單純

ntpuisbest03/31 22:03的控制反轉有降低耦合嗎?

bronx080703/31 22:04Spring幫你new物件並注入到使用的對象屬性中

bronx080703/31 22:05還有上面Dao1 Dao2例子有誤,DI是從外面set進來

ntpuisbest03/31 22:07我的第一個例子應該是DI吧,把ADDRESS注入到Employee

ntpuisbest03/31 22:07當中

ntpuisbest03/31 22:08即使用Spring,不用自己寫new,可是建構子還是要自己寫

ntpuisbest03/31 22:08阿,降低了什麼功夫呢

bronx080703/31 22:10幫你搞定層層的依賴關係

bronx080703/31 22:10你可以試試不用Spring自己寫依賴注入,你就知道差異

ntpuisbest03/31 22:13我第一個例子就沒有依賴Spring 阿 地址跟員工那個

foreverk03/31 22:16spring就是做掉你自己舉的例子,不然誰要往兩個class傳

foreverk03/31 22:16dao進去?

foreverk03/31 22:18你後面舉的自己new dao的行為,就等於你前面沒有做DI的

foreverk03/31 22:18舉例了

MoonCode03/31 22:19我看下來只覺得原po寫太少了 哈哈哈哈

foreverk03/31 22:24今天是dao你感覺比較單純無法,如果你要new的是service

foreverk03/31 22:24呢?視你的專案複雜度,一個service可能會有10幾20個建

foreverk03/31 22:24構子需要你自己new出來,而service互相依賴不會只有有

foreverk03/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

bluelink03/31 22:33可以看看跟qualifier的搭配

bronx080703/31 22:40https://code.labstack.com/Raualw2G

kirin02103/31 22:40要以類別與類別間的關係來看是否降低耦合吧?

kirin02103/31 22:40降低耦合的定義應該不是叫大家可以少寫code哈哈

bronx080703/31 22:41不用@Autowired就要寫上面連結中那坨new

foreverk03/31 22:4120個dao只是一行嗎?那你試試new 20個都有20個dao的ser

foreverk03/31 22:41vice

foreverk03/31 22:43其實有在寫mockito的應該都體會過,當service耦合太嚴

foreverk03/31 22:43重時,寫test有多痛苦,最後都會順便解耦XD

atpx03/31 22:44你寫工具給別人用比較會需要. 寫商業邏輯不太用的到

abadfriend03/31 22:46不確定 @Qualifier 能不能解答到你的疑惑?

atpx03/31 22:46運算的過程不想變動, 但又需要把產生的實例替換掉的情況下

atpx03/31 22:46就用到你的例子

ntpuisbest03/31 22:48謝謝bron大,我好像懂了,qualfied還在看@@

abccbaandy03/31 22:50不懂正常,因為例子太爛,簡單的new感受不到這東西的

abccbaandy03/31 22:50用處

abccbaandy03/31 22:52你試試"new"個jdbc connection就知道了

foreverk03/31 22:52會有spring好像沒幹事的錯覺,是因為作者是你自己,你

foreverk03/31 22:52可以掌控那些複雜的service建構子,當多人協作時有人需

foreverk03/31 22:52要使用你的service,還需要搞懂那些建構子的邏輯跟用法

foreverk03/31 22:52,那就是一場災難,更別提那個人的service立刻又跟那些

foreverk03/31 22:52建構子用途的物件耦合,每個人都這樣就沒完沒了

lovdkkkk03/31 23:22重點在 依賴於介面 而不依賴於實作

lovdkkkk03/31 23:23要能自己 new, 就綁死實作的 package/class 了

lovdkkkk03/31 23:24給 spring 生, 自己只綁介面定義 實作就可替換

s06yji304/01 00:16降低耦合和少寫code是兩回事

tttkkk04/01 00:24整篇看完了 你要補的地方是 code to interface 的概念

tttkkk04/01 00:25先了解 interface 再來看 dependency injection 會較易懂

tttkkk04/01 00:26例如你有個 Dao interface 他有兩個實作 Dao1 和 Dao2

tttkkk04/01 00:26用 DI 可以在你的 Service 裡面去指定用哪一個實作

感謝上面所有大大 尤其是bron大,謝謝 ok 謝謝,我對介面的理解只有降低耦合 但跟di的關聯還沒補上 謝謝

※ 編輯: ntpuisbest (49.216.186.239 臺灣), 04/01/2022 00:35:55

tttkkk04/01 00:39其實你舉的 service 例子不是解耦合喔 試想你若真的要在

tttkkk04/01 00:39service 中同時用到 Dao1 跟 Dao2 那怎會有解偶合的問題

tttkkk04/01 00:41當你會需要偶爾使用Dao1 偶爾使用 Dao2 甚至未來改成Dao3

tttkkk04/01 00:42才會需要解耦合 因為你把 Service 跟 Dao 解耦合了

tttkkk04/01 00:43更改 Dao 實作時 就不會動到 Service

x246libra04/01 01:19你第一個例子,地址,通常不會視為DI吧,比較像ddd的v

x246libra04/01 01:19alue object

lazarus112104/01 01:38我也有類似的問題,如果建構子會吃參數

lazarus112104/01 01:39如果要在spring上是不是最好改寫為另外set進去比較好

lazarus112104/01 02:01不然常常會寫一堆bean,好像沒有比較方便

lazarus112104/01 02:07但如果要用時再抓來set,物件的命名又會很混亂

handsomeLin04/01 02:36一句話:DI並不解決耦合問題,DI只是幫助你更輕鬆的

handsomeLin04/01 02:36測試並且轉換實作的時候不需要大量改動code

godsparticle04/01 08:30樓上正解

foreverk04/01 08:43不管是依賴介面別依賴實作,還是用DI,都是解決掉你的

foreverk04/01 08:43耦合問題,才有後續帶來的輕鬆測試跟切換實作,避免大

foreverk04/01 08:43量改動code,他們都是解耦過程的一部分

sharek04/01 09:22會感覺不到DI好處,大概只能親身經歷過痛過強耦合的proje

sharek04/01 09:22ct才比較能體會

devilkool04/01 09:29當你打算寫單元測試就會懂DI的好處了

ssccg04/01 10:25@Autowired找到完全同一個concrete class的bean來注入本來

ssccg04/01 10:27就沒有降低耦合,可以找到相容的實作(實作interface的bean

ssccg04/01 10:27或subclass的bean)才有降低耦合

tw1150904/01 10:40Autowired介面,搭配profile註解,可以在不同環境使用不

tw1150904/01 10:40同實作

tw1150904/01 10:52關於di,spring in action有個騎士出任務的範例,還蠻有

tw1150904/01 10:52趣的

vi00024604/01 13:45你可以A一下91哥的文 id是landlord

vi00024604/01 13:45他有個土砲重構的範例滿不錯的

MonyemLi04/01 18:42spring 只是稍微降低耦合。主要降低的是多用介面,多寫

MonyemLi04/01 18:42幾層

superpandal04/01 23:51不想講但還是講一下好了 它就只是偵測你包內的

superpandal04/01 23:51annotation並且儲存起來(map) 需要的時候取用初始化

superpandal04/01 23:52而已 依賴注入本身不是問題 問題是使用annotation的

superpandal04/01 23:53依賴注入 專案大了以後 一堆初始化流程你都不見得能

superpandal04/01 23:54夠掌握 更別說annotation設值所造成的影響

superpandal04/01 23:55然後這樣的初始化效能肯定比你直接new來的差

superpandal04/01 23:57介面的話更是扯 你直接改個類不就得了... 當然如果

superpandal04/01 23:57習慣非常好 用annotation也都無所謂 但你不一定是一

superpandal04/01 23:57一個人開發

superpandal04/02 00:00用這些框架有時候就不是人在使用工具 是人被工具玩

superpandal04/02 00:01更準確的是人寫工具的惡意 而非工具本身自主

superpandal04/02 00:06無腦開發你才有人生 耗在這沒意義的事情才糟糕

ssccg04/02 10:32樓上肯定沒用到request、session、refresh scope

ssccg04/02 10:32才會覺得spring DI只是個map存起來這麼簡單

superpandal04/02 22:42當然不是講的這麼大致方向 剩下的就只是應用再應用

superpandal04/02 22:44講的這些真的要自己寫框架不難寫

superpandal04/02 22:46只是個人不會遇到一個問題解決了再創造一個名詞

superpandal04/02 22:48光看這些其實很容易眼花撩亂 還是學習真的知識比較好

CoNsTaR04/03 10:31Java 哈哈 Java

CoNsTaR04/03 10:31Old school try hard language

CoNsTaR04/03 10:31搞笑的語言就是只能搞笑

tw1150904/03 21:17去除掉springBoot,IoC、DI和DIP這些概念又不是Java獨有

tw1150904/03 21:17,說Java搞笑跟這篇文章的關聯真是無法理解!?

CoNsTaR04/04 13:21樓上找給我看除了 Java 以外還有哪個語言什麼事都要 anno

CoNsTaR04/04 13:21tations ,設定檔,框架魔法和 reflection 才能做的?真

CoNsTaR04/04 13:21的笑死

CoNsTaR04/04 14:04https://i.imgur.com/wAMYYbI.png

圖 Spring boot的依賴注入降低耦合的例子

tw1150904/04 21:15嗯嗯,您說得對