密封类的作用
在面向对象语言中,我们可以通过继承(extend)来实现类的能力复用、扩展与增强。但有的时候,有些能力我们不希望被继承了去做一些不可预知的扩展。所以,我们需要对继承关系有一些限制的控制手段。而密封类的作用就是限制类的继承。
已有的限制手段
对于继承能力的控制,Java很早就已经有一些了,主要是这两种方式:
- final修饰类,这样类就无法被继承了
- package-private类,可以控制只能被同一个包下的类继承
但很显然,这两种限制方式的力度都非常粗,如果有更精细化的限制需求的话,是很难实现的。
新手段:密封类
为了进一步增强限制能力,Java 17中的密封类增加了几个重要关键词:
假设我们要设计一个游戏,这个游戏给用户选择的英雄种类分为三大类:
每个种类下又有各种不同的具体英雄。所以,从我们传统的面向设计思路,会这样来创建:
// 英雄基类
public class Hero {}// 坦克英雄的抽象
public class TankHero extends Hero {}// 输出英雄的抽象
public class AttackHero extends Hero {}// 辅助英雄的抽象
public class SupportHero extends Hero {}// 坦克英雄:阿利斯塔
public class Alistar extends TankHero {}// 输出英雄:伊泽瑞尔
public class Ezreal extends AttackHero {}// 辅助英雄:索拉卡
public class Soraka extends SupportHero {}
整体结构有三层,具体如下图所示:
这个时候,为了避免开发人员在创建新英雄的时候,搞乱这样的三层结构。就可以通过引入密封类的特性来做限制。
假设我们希望第一、第二层是稳定的,对于第二层英雄种类的抽象不允许再增加,此时我们就可以这样写:
public sealed class Hero permits TankHero, AttackHero, SupportHero {}
通过sealed关键词和permitspermits关键来定义Hero是一个需要密封的类,并且它的子类只允许为TankHero, AttackHero, SupportHero这三个。
完成这个改造之后,我们会发现TankHero, AttackHero, SupportHero这三个类开始 错了,具体错误如下:
sealed, non-sealed or final modifiers expected
这是因为父类Hero被sealed修饰之后,sealed的密封要求被传递过来,此时子类就必须在sealed、non-sealed、final之间选择一个定义,它们分别代表:
根据上面的假设需求,第一、第二层稳定,允许第三层具体英雄角色可以后期不断增加新英雄,所以三类抽象英雄的定义可以这样编写:
public non-sealed class TankHero extends Hero {}
而对于第三层的英雄角色,已经是最后的具体实现,则可以使用final定义来阻断后续的继承关系,比如这样:
public final class Ezreal extends AttackHero {}
通过这样的设置,这三层英雄的结构中第一第二层就得到了比较好的保护。
声明:本站部分文章内容及图片转载于互联 、内容不代表本站观点,如有内容涉及侵权,请您立即联系本站处理,非常感谢!