sealed 類別

June 6, 2022

若你想設計另一個 RPG 程式庫,可以讓其他人拿來進一步設計遊戲,然而你想限定角色只有騎兵、戰士、魔導士、弓兵四種形態,在你定義了 Role 類別,讓 KnightWarriorMageArcher 繼承 Role 之後,就面對了一個問題,該怎麼阻止其他人繼承 Role 呢?

sealed 與 permits

有時候要解決的問題領域中,某些模型的型態架構是已知的,你想控制型態的邊界,像是控制 Role 只能有方才四個子類別,在 Java 17 之前,沒有適當的方式可以達成這類需求,然而 Java 17 以後的 sealed 關鍵字,可以達到需求。例如:

public abstract sealed class Role
                    permits Knight, Warrior, Mage, Archer {}
final class Knight extends Role {}
final class Warrior extends Role {}
final class Mage extends Role {}
final class Archer extends Role {}

可以使用 sealed 關鍵字修飾的類別必須是抽象類別,permits 列出了允許的子類別,子類別必須在同一套件中定義,並且必須使用finalnon-sealed、或 sealed 修飾,以上的程式片段使用了 final,這表示其他人除了不能繼承 Role 以外,也不能建立KnightWarriorMageArcher 的子類別。

non-sealed 或 final

如果使用 non-sealed 修飾,例如:

public abstract sealed class Role
                    permits Knight, Warrior, Mage, Archer {}
non-sealed class Knight extends Role {}
non-sealed class Warrior extends Role {}
non-sealed class Mage extends Role {}
non-sealed class Archer extends Role {}

這就表示其他人不能繼承 Role,然而可以任意地建立 KnightWarriorMageArcher 的子類別,也許目的是可以讓其他人,可以隨意定義騎兵、戰士、魔導士、弓兵進化後的延伸職業,例如騎兵可以進化為飛龍騎兵之類。

如果你也想進一步掌握騎兵、戰士、魔導士、弓兵進化後的延伸職業,像是騎兵進化後,只有飛龍騎兵、陸戰騎兵兩種,可以使用 sealed 修飾,並使用 permits 列出了允許的子類別。

sealed class Knight extends Role permits DragonKnight, MarineKnight {}
final class DragonKnight extends Knight {}
final class MarineKnight extends Knight {}

後續會談到介面,sealed 也可以用來修飾介面,這表示你很清楚介面會有幾種實作品或子介面,不允許其他人實作該介面或增加直接的子介面,實作類別必須在同一套件中定義,並且必須使用 finalnon-sealed、或 sealed 修飾,子介面必須在同一套件中定義,並且必須使用 non-sealed、或 sealed 修飾,這些等之後聊完介面再來說明。

分享到 LinkedIn 分享到 Facebook 分享到 Twitter