閱讀本文大概需要 6 分鐘。
很多人都想知道架構師是做什麼?我們看看下面的一段對話。
菜鳥 —— 剛入門的程序員
老鳥 —— 資深架構師
老鳥:菜鳥,你的目標是什麼?
菜鳥:我要成為一個軟體架構師。
老鳥:對一個年輕的工程師來說,這是一個很好的目標。那你為什麼要成為架構師呢?
菜鳥:我要領導一個團隊,還要做所有關於資料庫、框架和Web伺服器的重要決定。
老鳥:好吧,如果是這樣,你就沒必要成為一個軟體架構師了。
菜鳥:當然有必要了!我要成為一個能夠做所有重要決定的人。
老鳥:這樣很好,只是你沒有列出哪些纔是重要的決定。你剛才說的那些跟重要的決定沒有什麼關係。
菜鳥:你說什麼?難道資料庫不重要?你知道我們在資料庫上面花了多少錢嗎?
老鳥:可能很多。不過資料庫仍然不是最重要的。
菜鳥:你怎麼能這麼說呢?資料庫可是整個系統的心臟啊!所有的數據都保存在這裡,它們在這裡被排序,被索引,被訪問。如果沒有資料庫,整個系統就無法運作!
老鳥:資料庫只不過是一個IO設備,它提供了一些有用的工具對數據進行排序、查詢,並生成報表,但這些工具都只是整個系統的附屬品。
菜鳥:附屬品?真是不可思議。
老鳥:是的,附屬品。你的系統業務邏輯或許會用到這些工具,但這些工具並非業務邏輯固有的組成部分。如果有必要,你可以隨時替換掉這些工具,但業務邏輯還是那些業務邏輯。
菜鳥:好吧,不過如果把這些工具替換掉,我們就要重新實現業務邏輯了。
老鳥:那是你的問題。
菜鳥:為什麼這麼說?
老鳥:你認為業務邏輯依賴資料庫,但實際上不是這樣的。如果你的架構足夠好,最起碼業務邏輯不應該依賴資料庫。
菜鳥:這太瘋狂了。我怎麼可能創建出不使用這些工具的業務邏輯?
老鳥:我並沒有說業務邏輯不要使用資料庫工具,我的意思是它們不應該依賴這些工具。業務邏輯不應該知道使用的是哪一種資料庫。
菜鳥:如果業務邏輯對資料庫一無所知,它怎麼使用這些工具呢?
老鳥:依賴反轉。你要讓資料庫依賴業務邏輯,而不是讓業務邏輯依賴資料庫。
菜鳥:你的話讓人費解。
老鳥:費解嗎?我講的可是軟體架構。這個就是依賴反轉原則,讓下層策略來依賴上層策略。
菜鳥:那就更加費解了!既然上層策略(假設你指的是業務邏輯)要調用下層策略(假設你指的是資料庫),那麼就應該是上層策略依賴依賴下層策略,就像調用者依賴被調用者一樣。這是眾所周知的!
老鳥:在運行時確實是這樣的,但在編譯時我們要把依賴反轉過來。上層策略的代碼裏不要引用任何下層策略的代碼。
菜鳥:拜託!不引用代碼就無法調用它們。
老鳥:當然可以調用了。面向對象就可以做到。
菜鳥:面向對象對真實世界進行建模,把數據和函數組合到對象裏,把代碼組織成直觀的結構。
老鳥:這是他們告訴你的嗎?
菜鳥:所有人都知道的,這不是很明顯的事情嗎?
老鳥:確實如此。不過,面向對象是可以做到不引用也能調用的。
菜鳥:好吧,那它是怎麼做到的?
老鳥:你應該知道,在面向對象系統裏對象會給其它對象發送消息的,對吧?
菜鳥:是的,當然。
老鳥:那麼你就該知道,消息發送者是不知道消息接收者是什麼類型的。
菜鳥:這要看使用的是哪一種語言了。在Java裏,發送者最起碼要知道接收者的基本類型。在Ruby裏,發送者知道接收者一定會處理它所發送的消息。
老鳥:是的。不過不管是哪一種情況,發送者都不知道接收者具體的類型。
菜鳥:嗯,是的。
老鳥:所以發送者可以給接收者傳遞一個函數,讓接收者執行這個函數,這樣發送者就不需要知道接收者是什麼類型了。
菜鳥:沒錯。我瞭解你的意思。不過發送者仍然依賴接收者。
老鳥:在運行時確實是的,但在編譯時不是這樣的。發送者的代碼裏並沒有引用接收者的代碼。實際上,是接收者的代碼依賴了發送者的代碼。
菜鳥:啊!但發送者仍然會依賴接收者的類。
老鳥:看來需要用代碼來說明瞭,我用Java來寫些代碼。首先是發送者代碼: