【開發智能合約 — Solidity系列】實作篇Ep.13 - 抽象化的合約(Abstract Contracts)
我們在前幾篇有介紹到介面的用途,都知道介面可以制定規格,建議可以先複習一下這一篇「【開發智能合約 — Solidity系列】實作篇Ep.10 — 標準化的介面(Interfaces)」,而這次來介紹一個非常抽象的概念,名為「抽象化合約」,果然如其名! 不太容易理解,這種合約跟介面非常相似,都可以用來制定規格,而不同之處在於「抽象合約」可以被繼承,且「抽象合約」可以實作一些共同方法,但介面是不能實作的,也就是說介面有點設計的意味在,以「車」為例,介面僅設計出草圖,後續交由各種汽車、卡車…,進行不同的實作,只要遵照著規格走就好,怎麼實作就由各家決定,但「抽象合約」還可以先設計出「驅動」的方法,並藉由繼承的方式讓不同的車種皆擁有一樣的「驅動」方式,具有減少共同實作邏輯的特性。
以介面來實現,功能雖廣泛,但…
舉例來說,我們可能會設計一個「車」的介面,這個介面規格規定必須有「驅動」的功能,以燃油車來說會去實作「車」的介面,除了具備「驅動」以外,我們在燃油車的類別還可以實作「添加燃油」的功能,以符合燃油車的特性,那麼假設要製造其他燃油車型時,我們只要繼承「燃油車」這個類別就能基於燃油車進行擴充,以solidity語法設計如下:
// 車的介面 interface ICar { // 驅動 function drive() external; } // 燃油車 contract FuelCar is ICar { // 實作燃油車的驅動方式 function drive() public override { ... } // 添加燃油 function fill() public { ... } } // 一般燃油轎車 contract GeneralCar is FuelCar { ...更多燃油車的方法 }
但…,有沒有發現,這樣的方式雖然非常直觀,但也帶來了層層實作繼承的複雜度與設計規劃的高水準。
我們用抽象合約來實現看看?
我們可以發現到,捨去介面後會由三層降為兩層,主要是因為抽象合約除了可以制定規格以外,也能實現共同方法,讓繼承的類別除了自行實作之外,亦可承襲共同方法。
abstract contract FuelCar { // 定義驅動的方法,讓繼承類別各自實作 function drive() public virtual; function fill(uint amount) public { // 添加燃油... } } // 一般燃油轎車 contract Car is FuelCar { function drive() public override { // 實作一般燃油轎車的驅動方法 } }
除了能夠操作實作的「驅動」之外,亦可操作到繼承的添加函數。
圖片來源
結語
一開始在看介面與抽象類別時真的是傻傻分不清楚,兩者實在太相似了,因此有些程式語言就乾脆移除抽象類別的使用方式,但又會有別的派系支持抽象類別的使用,才會發現到市面上各種程式語言皆提倡不同的理念,有的程式語言甚至乾脆移除抽象類別的使用情境,例如: Golang…等,對我們來說多學一個念也無彷拉,只要知道其中的核心理念即可得心應手。
參考資源
- https://www.youtube.com/watch?v=jdWM91sDd6s&ab_channel=Hung-YingTai
- https://medium.com/upstate-interactive/solidity-how-to-know-when-to-use-abstract-contracts-vs-interfaces-874cab860c56
- https://ad57475747.medium.com/c-雜記-介面-interface-抽象-abstract-虛擬-virtual-之我見-dc3c5878bb80