圖片來源 |
我們在前幾篇有介紹到介面的用途,都知道介面可以制定規格,建議可以先複習一下這一篇「【開發智能合約 - 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-%E9%9B%9C%E8%A8%98-%E4%BB%8B%E9%9D%A2-interface-%E6%8A%BD%E8%B1%A1-abstract-%E8%99%9B%E6%93%AC-virtual-%E4%B9%8B%E6%88%91%E8%A6%8B-dc3c5878bb80
留言
張貼留言