: 感謝bron大
: 文章有點長
: 先說說我對依賴注入的理解
: Spring boot
: 依賴注入大致有三種方式
: 透過建構子的 透過setter的 或是 field
: 這三種都可以透過@Autowired註解來達到依賴注入的效果
在這個時代依賴注入最重要的用途,特別是在後端開發是讓Application 在多個不同的
環境下(Development, Production, local, etc)
能夠根據profile 組出能正確執行的Application
多型在這裡當然有他的地位,但是一般來說,大部分不接觸system boundary的service
objects 是不太需要多型的,如果是java,那種一個interface 只有一個implementation
class 的情況其實就代表著那個interface 沒有用
倒是如何搭配Annotation 與aspect programming在後端開發是更重要的
: 假設有兩個類 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的建構方式
: 所以我理解依賴注入可以降低耦合
這是資料物件,資料物件頂多實現封裝而已,這也不是什麼依賴注入,這只是單純
的物件組裝
當你說降低『耦合』的時候,你覺得是什麼東西的『耦合』需要降低?
: 在常見的開發中 我們經常都會有 Dao 以及 Service
: 假設我有兩個 Dao 好了 分別是 Dao1 和 Dao2
: 以及一個Service
: Dao1
: public class Dao {
: public void sayhi() {
: System.out.println("hello");
: }
: }
: Dao2
: public class Dao2 {
: public void saygoodbye() {
: System.out.println("say goodbye");
: }
: }
Data Access Object 是要去存取Data source的,你取這個名字,就表示後面存在
某種DB、file 等總之是需要透過IO去存取獲得資料的東西
如果你的service 就是需要存取特定的Data source 才能工作,那你當然沒辦法
讓這兩個Dao 消失啊,你頂多再插入一層service ,把他們封裝進其他的service object
裡
: 我的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 在這裡幫你:
1. 把物件組裝起來
2. DAO 是要存取Data source 的,所以會開Connection,有Connection 就有
lifecycle 要管,而Spring 可以幫你把lifecycle 管好
3. 某些Datasource 的互動是需要transaction 來保證資料一致性的,Spring
也幫你做了
4. localhost、Dev、Production 要連不同的datasource,要開大小不同的connection
pool 這Spring 幫你做了
5. 哪裡連不上出差錯了,Spring 報給你知
他幫你做了這麼多、唯一沒辦法幫你做的就是你期待的降低耦合(事實上你期待的是
零耦合),但因為你的service 業務邏輯實作就是需要跟這兩個Dao 互動啊,那是要
怎麼降?
問題不是出在Spring,而是出在你對Framework 有錯誤的認識與期待
更深入探討,如果你不用Spring 這類的DI 容器,那你肯定就要自己Construct 這兩個
DAO,如果你直接在你的Service constructor 創建這兩個Dao,那我列的那五件事,
就得完全歸service 自己管了,在採用Spring 以至於你不用擔心dao 到底該怎麼baby
sitting就可以像自來水電一樣轉開就用的情況下,你的service 就已經在一個夠低的
耦合水平下與這兩個dao 互動了
吃米要知道米價啊
: 我知道依賴注入可以降低耦合
: 但Spring boot透過 @Autowired註解幫我降低耦合在哪
: 謝謝
: p.s 因為面試的時候常常被面試官問說懂不懂甚麼是
: 控制反轉還有DI,我基本上舉例都舉 Address還有 Employee的例子
你舉這個例子,我是面試官大概就會直接當作你不懂
因為Address 還有Employee 都是資料物件,而控制反轉與DI要解決的問題是:
『如何組織程序?如何把系統中許許多多需要執行的procedure適當的切分,然後
在適當的地方、時機,可以有適當的Context去執行?』
這與資料物件如何透過實現多型而可以任意組裝沒有關係
我們要注入給Framework或是Container 的不是資料物件,而是行為物件,是那種suffix
會叫做:Filter、Listener、Consumer、Interceptor 的『行為』物件
你要我舉例,我大概會用HttpClient 當例子
當我的系統中到處都用得上httpClient,而且他需要可以Configure Circuit Breaker
、有Rate Limiter、遇到response error 知道要retry、而且有預設的Http status
handling 但仍舊可以客製化、response deserialization 要可以從json 與form間
自由切換,然後系統中每個地方用HttpClient 的情境都不太一樣,請問要怎麼設計這
個HttpClient?
: 只有其中一個就說更複雜的例子會用到,但也沒說甚麼是更複雜的例子QQ
控制反轉在實作上,最直白的做法,就是業務邏輯不是由programmer 直接撰寫
imperative procedure 執行,而是把這些業務邏輯(一般實現成各種services)包裹
成各式各樣代表行為的物件,比如說:Listener、Consumer、Filter 、Interceptor、
visitor 等等,然後實際在什麼時間點、在什麼地方這些物件會被呼叫是由Application
內某種processor、Container 根據當初的Configuration來決定
這些東西應該書上都有寫的,我建議你還是要找本書好好的看過一遍才比較會有全面
的認識
--
『你知道人有腦子,所以不要只是單純的滿足它,偶爾也要使用它啊。』
--