说了方法的重写,我们再回过头来看看那个继承树:
这个看起来应该还行,我们可以创建大刀的实例,创建手枪的实例……
但是如果我要这样写呢?
1 |
var 武器 = 武器() |
那么问题来了:挖掘机……
不,我们的问题是“武器”到底是个什么东西?
我们说“动物”,人是动物,鸟是动物,狗、猫都是动物,那有没有个动物是动物呢?
答案是没有——动物是个抽象的词汇。同样的,作为继承树顶端的类,它也必定是个极为抽象的家伙,从这里实例化出来的——不,绝不应该让它实例化!
所以,我们一定能找到一种办法来让类只能被继承,不能被初始化。
抽象类
针对我们的这个继承树来说,“武器”、“冷兵器”、“热兵器”、“枪械”、“远程”等这些类都不应该被实例化,它们都是抽象的东西,所以我们要把这些类作为抽象类来对待,让它必须被继承了才能使用,而且里边的方法必须被重写了才能调用!
也就是说只规定合同框架,要由子类自己去实现合同细则。
第一种方法
通过讲将初始化器搞成私有,这样我们在调用一个类来实例它的时候,编译器却找不到初始化器——目前我们还没有讲到初始化器,而且也没有写出来,现在你只需要知道,我们不写的话编译器会自己帮你实现一个基本的,如果写了,编译器就会用你的。
总之,我们用这样的方法实现了这个类无法被初始化。
1 2 3 4 5 6 |
class Weapon { private init () { } func fire() { } } |
要测试这种方法,不能在 playground 里,必须新建个项目使用不同的文件来操作才行!
第二种方法
换一种思路,把类替换为协议来声明——因为协议天生就是不能被实例化的……
协议
声明协议和声明类差不多的,都是大写开头的命名方法,不过 class 要换成 protocol 。
在协议里不能设定属性的值也不能实现方法,只能像占位符一样写出规范,而子类来进行继承的时候就会被要求覆盖和实现这些成员。
我们来举个栗子
1 2 3 4 |
protocol Weapon { var ammo:Int {get set} func fire() } |
这样虽然说变成了一个协议,但它确实可以让这个类无法被实例化,当然了,继承自这个协议的子类则不需要重写方法——因为方法本身就没有被实现,我们只需要自己实现一个即可。
这里我们的说法不太严谨,对于协议来讲是不能被继承的,而且也不是子类和父类的关系——目前你可以这样理解和使用,因为对于 Swift 本身来说,并没有抽象类的概念。
有不能被覆盖和继承的解决办法吗?
使用 final 前缀标记一个类或者方法,用来声明这个类或者方法是“最终”的版本,不能够被继承或者重写。
本文由 落格博客 原创撰写:落格博客 » 协议:不允许实例化的类以及必须被重写的方法
转载请保留出处和原文链接:https://www.logcg.com/archives/1127.html