鮑勃大叔實錘:類與資料結構的比較!每個優秀的軟體設計師和架構師都需要牢記的問題

banq發表於2019-06-18

什麼是類?

  • 類是一組類似物件的規範。

什麼是物件?

  • 物件是一組對封裝資料元素進行操作的函式。
  • 或者更確切地說,物件是一組對隱含資料元素進行操作的函式。

暗示資料元素是什麼意思?“

  • 物件的功能意味著存在一些資料元素; 但是該資料不能直接在物件外部訪問或可見。

是不是物件裡面的資料?

  • 它可能是; 但是沒有規則說必須這樣。從使用者的角度來看,物件只不過是一組功能函式。這些函式操作的目標資料必須存在,但使用者不知道該資料的位置。

好。什麼是資料結構?

  • 資料結構是一組有凝聚力的資料元素。
  • 或者,換句話說,資料結構是由隱含函式操作的一組資料元素。

好的好的。我知道了。對資料結構進行操作的函式不是由資料結構指定的,但資料結構的存在意味著某些操作必須存在。

  • 對。那麼你對這兩個定義有什麼看法?

類和資料結構彼此相反

  • 確實。它們是彼此的補充。它們像手套一樣裝在一起。
  • 物件是一組對隱含資料元素進行操作的函式。
  • 資料結構是由隱含函式操作的一組資料元素

哇,所以物件不是資料結構。

  • 正確。物件與資料結構相反。

那麼DTO - 資料傳輸物件 - 不是一個物件?

  • 正確!DTO是資料結構。

所以資料庫表也不是物件嗎?

  • 再次糾正。資料庫包含資料結構,而不是物件。

可是等等。ORM 物件關係對映器是不是將資料庫表對映到物件?

  • 當然不是。資料庫表和物件之間沒有對映。資料庫表是資料結構,而不是物件。

那麼ORM做什麼呢?

  • 它們在資料結構之間傳輸資料。

所以他們與物件沒有任何關係?

  • 沒什麼。沒有物件關係對映器這樣的東西; 因為資料庫表和物件之間本身就無法對映。

但我認為ORM為我們構建了業務物件。

  • 不,ORM提取業務物件操作的資料。該資料包含在ORM載入的資料結構中。

但那麼業務物件不包含該資料結構嗎?

  • 它可能。它可能不會。這不是ORM的業務。

這似乎是一個小的語義點。

  • 一點也不。這種區別具有重要意義。

比如?

  • 例如資料庫模式的設計與業務物件的設計。業務物件是定義業務行為的結構。 資料庫模式是定義業務資料的結構。這兩種結構受到非常不同的力量的約束。業務資料的結構不一定是業務行為的最佳結構。

嗯。這令人困惑。

  • 這樣想吧。資料庫架構不針對一個應用程式進行調整; 它必須服務於整個企業。因此,該資料的結構是許多不同應用程式之間的折衷。

好的,我明白了。

  • 好。但現在看看每個單獨的應用。每個應用程式的物件模型描述了這些應用的行為結構的方式。每個應用程式都有一個不同的物件模型,微調該應用程式的一些行為。

原來如此。由於資料庫模式是所有各種應用程式的折衷,因此該模式將不符合任何特定應用程式的物件模型。

  • 對!物件和資料結構受到非常不同的力量的約束。他們很少很好地協調在一起工作。人們習慣稱之為物件/關係阻抗不匹配。

我聽說過這個。但我認為阻抗不匹配是由ORM解決的。

  • 現在你的想法現在不同了。沒有阻抗不匹配,因為物件和資料結構是互補的,而不是同構的。

什麼?

  • 它們是對立的,而不是類似的實體。

對立?

  • 是的,以一種非常有趣的方式。你看,物件和資料結構意味著截然相反的控制結構。

等等,什麼?

  • 想想一組所有符合公共介面的物件類。例如,想象一下表示二維形狀的類,它們都具有計算形狀area和perimeter形狀的功能。

為什麼每個軟體示例總是涉及形狀?

  • 我們只考慮兩種不同的型別:Squares和Circles。應該清楚的是,這兩個類的area和permimeter函式在不同的隱含資料結構上執行。還應該清楚,呼叫這些操作的方式是通過動態多型。

等待。慢一點。什麼?

  • 有兩種不同的area函式; 一個用於Square,另一個用於Circle。當呼叫者呼叫area特定物件上的函式時,該物件知道要呼叫的函式。我們稱之為動態多型。

好。當然。該物件知道其方法的實現。當然。

  • 現在讓我們將這些物件轉換為資料結構。我們將使用Discriminated Unions。

Discoominated什麼?

  • 可區分聯合discriminated unions。在我們的例子中,這只是兩種不同的資料結構。一個為Square,另一個為Circle。該Circle資料結構具有一箇中心點,和用於資料元素的半徑。它還有一個型別程式碼,可以將其標識為Circle。

你的意思是像一個列舉?

  • 當然。該Square資料結構具有左上點,並且側的長度。它還有型別鑑別器 - 列舉。

好。兩個帶有型別程式碼的資料結構。

  • 對。現在考慮這個area功能。它會有一個switch語句,不是嗎?

嗯。當然,對於兩種不同的情況。一個為Square另一個為Circle。並且該perimeter函式將需要類似的switch語句

  • 再一次。現在考慮這兩種情景的結構。在物件場景中,area函式的兩個實現彼此獨立並且屬於(在某種意義上的單詞)各自型別。 Square的area函式屬於Square,Circle的area函式屬於Circle。

好的,我知道你要去哪裡。在資料結構場景中,area函式的兩個實現在同一個函式中,它們不屬於“型別”(但是你的意思是那個詞)。

  • 它變得更好了。如果要將Triangle型別新增到物件方案中,必須更改哪些程式碼?

沒有程式碼更改。您只需建立新Triangle類。哦,我想這個例項的建立者必須改變。

  • 對。因此,當您新增新型別時,幾乎沒有變化。現在假設您要新增一個新函式 - 比如center函式。

那麼,你就必須將它新增到所有三種型別,Circle,Square,和Triangle。

  • 好!因此類新增新函式很難,您必須更改每個類。

但是對於資料結構,它是不同的。為了新增新Triangle新型別,您必須更改每個函式以將Triangle匹配情況新增到switch語句中。

  • 對!資料結構新增新型別很難,您必須更改每個函式。

但是當你新增新center函式時,資料結構不需要任何改變。

  • 對!資料結構新增新函式很容易。

哇。兩者恰恰相反。

  • 絕對是相反:
  • 向一組類新增新函式很難,您必須更改每個類;將新函式新增到一組資料結構很容易,只需新增函式,不做任何其他更改。
  • 將新型別新增到一組類很簡單,只需新增新類即可;向一組資料結構新增新型別很難,您必須更改每個函式。

是啊。對立統一。以有趣的方式對立。我的意思是,如果您知道要將新函式新增到一組型別中,那麼您需要使用資料結構。但是如果你知道你將要新增新型別,那麼你想要使用類。

  • 好!但今天我們還有最後一件事要考慮。還有另一種方式,資料結構和類是對立的。它與依賴關係有關。

依賴?

  • 是的,原始碼依賴的方向。

好的,我會咬人的。有什麼不同?

  • 考慮資料結構案例。每個函式都有一個switch語句,它根據區分聯合中的型別程式碼選擇適當的實現。

好的,那是真的。但那又怎麼樣?

  • 考慮呼叫area函式。呼叫者依賴於area函式,area函式取決於每個特定的實現。

“依賴”是什麼意思?

  • 想象一下,如果每個類實現area函式,都有寫入了它自己的函式。因此,有circleArea和squareArea和triangleArea單獨自己的實現area函式。

好的,所以switch語句只呼叫那些函式。

  • 想象一下,這些函式放在不同的原始檔中。

然後,帶有switch語句的原始檔必須匯入、使用或包含所有這些原始檔。

  • 對。這是原始碼依賴。一個原始檔依賴於另一個原始檔。這種依賴的方向是什麼?

帶有switch語句的原始檔取決於包含所有實現的原始檔。

  • 那個area函式的呼叫者怎麼樣?

area函式的呼叫者依賴於具有switch語句的原始檔,該語句取決於所有實現

  • 正確。所有原始檔依賴關係都指向呼叫方向,從呼叫者到實現。因此,如果您對其中一個實現進行微小更改......

好的,我知道你要去哪裡。對任何一個實現的更改都將導致重新編譯帶有switch語句的原始檔,這將導致呼叫該switch語句的每個人area(我們的情況下的函式)被重新編譯。

  • 對。至少對於依賴於原始檔的日期來確定應該編譯哪些模組的語言系統來說是這樣的。

幾乎所有這些都使用靜態型別,對吧?

  • 是的,有些則沒有。

很多重新編譯。

  • 還有很多重新部署。

好的,但是在類的情況下這是相反的嗎?

  • 是的,因為area函式的呼叫者依賴於介面,並且實現函式也依賴於該介面。

我明白你的意思了。類的原始檔Square匯入或使用或包含Shape介面的原始檔。

  • 對。實現的原始檔指向呼叫的相反方向。他們從實現指向呼叫者。對於靜態型別語言至少也是如此。對於動態型別語言,area函式的呼叫者完全不依賴於任何東西。連結在執行時得到解決。

對。好。因此,如果您對其中一個實施進行了更改......

  • 只需重新編譯或重新部署已更改的檔案。

這是因為原始檔之間的依賴關係指向呼叫的方向。

  • 對。我們稱之為依賴倒置。

總結

好的,那麼讓我看看我是否可以把它合起來。類和資料結構至少以三種不同的方式存在。

  1. 類在保持資料隱含的同時使函式可見。資料結構使資料可見,同時保持隱含的函式。
  2. 類使新增型別變得容易,但很難新增函式。資料結構使新增函式變得容易,但很難新增型別。
  3. 資料結構將呼叫者公開給重新編譯和重新部署。類將呼叫者與重新編譯和重新部署隔離開來。

你說對了。這些是每個優秀的軟體設計師和架構師都需要牢記的問題。

相關文章