协议:不允许实例化的类以及必须被重写的方法

说了方法的重写,我们再回过头来看看那个继承树:

类的继承树
类的继承树

这个看起来应该还行,我们可以创建大刀的实例,创建手枪的实例……

但是如果我要这样写呢?

那么问题来了:挖掘机……

不,我们的问题是“武器”到底是个什么东西?

我们说“动物”,人是动物,鸟是动物,狗、猫都是动物,那有没有个动物是动物呢?

答案是没有——动物是个抽象的词汇。同样的,作为继承树顶端的类,它也必定是个极为抽象的家伙,从这里实例化出来的——不,绝不应该让它实例化!

所以,我们一定能找到一种办法来让类只能被继承,不能被初始化。

抽象类

针对我们的这个继承树来说,“武器”、“冷兵器”、“热兵器”、“枪械”、“远程”等这些类都不应该被实例化,它们都是抽象的东西,所以我们要把这些类作为抽象类来对待,让它必须被继承了才能使用,而且里边的方法必须被重写了才能调用!

也就是说只规定合同框架,要由子类自己去实现合同细则。

第一种方法

通过将初始化器搞成私有,这样我们在调用一个类来实例它的时候,编译器却找不到初始化器——目前我们还没有讲到初始化器,而且也没有写出来,现在你只需要知道,我们不写的话编译器会自己帮你实现一个基本的,如果写了,编译器就会用你的。

总之,我们用这样的方法实现了这个类无法被初始化。

 

要测试这种方法,不能在 playground 里,必须新建个项目使用不同的文件来操作才行!

第二种方法

换一种思路,把类替换为协议来声明——因为协议天生就是不能被实例化的……

协议

声明协议和声明类差不多的,都是大写开头的命名方法,不过 class 要换成 protocol 。

在协议里不能设定属性的值也不能实现方法,只能像占位符一样写出规范,而子类来进行继承的时候就会被要求覆盖和实现这些成员。

我们来举个栗子

这样虽然说变成了一个协议,但它确实可以让这个类无法被实例化,当然了,继承自这个协议的子类则不需要重写方法——因为方法本身就没有被实现,我们只需要自己实现一个即可。

这里我们的说法不太严谨,对于协议来讲是不能被继承的,而且也不是子类和父类的关系——目前你可以这样理解和使用,因为对于 Swift 本身来说,并没有抽象类的概念。

有不能被覆盖和继承的解决办法吗?

使用 final 前缀标记一个类或者方法,用来声明这个类或者方法是“最终”的版本,不能够被继承或者重写。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.