我知道Swift中没有抽象类和Abstract
关键字。以下问题就像实现抽象属性一样。
为方便起见,假设有以下三个类:
class SuperClass: NSManagedObject { // the compiler will complain without 'NSManagedObject', and I don't know why.
public let superInt: Int = 1 // use superInt to represent other stored property for SuperClass.
}
class SubClass1: SuperClass {
let subInt1: Int = 2 // use 'subInt1' to represent other stored property for SubClass1.
}
class SubClass2: SuperClass {
let subInt2: Int = 3 // use 'subInt2' to represent other stored property for SubClass2.
}
protocol TestProtocol {
var count: Int { get } // a computed property
func printInt() // a custom method
}
这里,这些类都是CoreData中定义的对象,尤其是SuperClass是一个抽象实体。我想为SuperClass扩展一些接口(上面的TestProtocol
),以便我可以使用多态。我想出了两种方法:
方法1:让SuperClass确认TestProtocol
。
extension SuperClass: TestProtocol {
var count: Int { return superInt }
func printInt() { print("Here is SuperClass. Count: \(count)") }
}
extension SubClass1 {
override var count: Int { return subInt1 }
override func printInt() { print("Here is SubClass1. Count is \(count)") }
}
extension SubClass2 {
override var count: Int { return subInt2 }
override func printInt() { print("Here is SubClass2. Count is \(count)") }
}
// Here is the test code
let subClasses: [SuperClass] = [SubClass1(), SubClass2()]
subClasses.forEach { $0.printInt() }
方法2:将子类转换为协议对象。
extension SubClass1: TestProtocol {
var count: Int { return subInt1 }
func printInt() { print("Here is SubClass1. Count is \(count)") }
}
extension SubClass2: TestProtocol {
var count: Int { return subInt2 }
func printInt() { print("Here is SubClass1. Count is \(count)") }
}
// Here is the test code
let subClasses: [SuperClass] = [SubClass1(), SubClass2()]
subClasses.forEach { ($0 as! TestProtocol).printInt() }
在方法1中,一切看起来都不错。但我必须在SuperClass中实现完全没用的代码。这个方法看起来像是一个小小的语法技巧。
在方法2中,所有代码都很有用,但最后一行的转换破坏了代码的优雅。这让我疯狂地继续使用像($0 as! TestProtocol).printInt()
这样的代码。
我对这两种方法都不满意。那么这是推荐的方式还是有更好的方法呢?
答案 0 :(得分:0)
在你的第二种方法中,你实际上不需要使用强制转换(($0 as! TestProtocol).printInt()
)。方法如下:
let subClasses: [TestProtocol] = [SubClass1(), SubClass2()]
subClasses.forEach { $0.printInt() }
通过键入subClasses
数组到TestProtocol
而不是SuperClass
,您可以消除对转换的需要,因为编译器现在知道subClasses
中的每个元素都符合{{ 1}}因此,有一个方法TestProtocol
。
答案 1 :(得分:0)
您的超类在方法1和方法2中都没有任何用途。在您定义的两种方法中,您希望最终调用printInt(),其中应该是所有子类的共同。请注意我已突出显示"应该是常见的"。协议的目的是指定符合类型必须实现的要求。因此,协议足以形成您的类1和2应该实现var count和func printInt()的契约。协议也是一种类型,因此您不需要超类来保存对其他两个类的引用,如下所示:
let subClasses: [SuperClass] = [SubClass1(), SubClass2()]
在我看来,这是一个更好的方法:
protocol TestProtocol {
var count: Int { get } // a computed property
func printInt() // a custom method
}
Class1: TestProtocol {
var subInt = 2
var count: Int { return subInt1 }
func printInt() { print("Here is SubClass1. Count is \(count)") }
}
Class2: TestProtocol {
var subInt = 3
var count: Int { return subInt2 }
func printInt() { print("Here is SubClass2. Count is \(count)") }
}
let smallClasses: [TestProtocol] = [Class1(), Class2()]
smallClasses.forEach { $0.printInt() }
这种做法在Swift中实现了面向协议的编程方式,这是一种受欢迎的方法。一般来说,在iOS设计模式中避免继承和子类化,我将引导您访问此博客文章,以便您可以了解有关https://krakendev.io/blog/subclassing-can-suck-and-heres-why
的更多信息。修改强>
你已经澄清了你的问题,所以我会尝试更好地回答它。您正在寻找Java中抽象类的等价物,它是包含一个或多个抽象方法的类。 Java中的抽象方法是声明的方法,但不包含任何实现。抽象类可能无法实例化,并且需要子类来提供抽象方法的实现。
Swift没有相同的功能,但是功能相当的东西需要一个超类,其中所有子类都被迫实现必须对所有子类共同的属性或方法。这当然是通过我上面显示的协议方法实现的,但是你还需要能够从子类调用超类中的属性或方法,这意味着每个子类必须能够同时转换为协议类型和超类班级类型。
以下是我用Swift 3编写的解决方案:
protocol TestProtocol {
var count: Int { get } // a computed property
func printInt() // a custom method
}
//base class
class SuperClass: TestProtocol {
var sharedInt: Int = 0
var subInt: Int = 1
var count: Int { return subInt }
func printInt() { print("Here is SubClass. Count is \(count)") }
}
class class1: SuperClass {
override init(){
super.init()
self.subInt = 2
}
}
class class2: SuperClass {
override init(){
super.init()
self.subInt = 3
}
}
//I can get count and printInt() which superClass, class1 and class2 share becuase of the protocol.
let smallClasses: [TestProtocol] = [SuperClass(), class1(), class2()]
smallClasses.forEach { $0.printInt() }
//I can convert the sub classes to super class type and call their printInt method
let smallClasses2: [SuperClass] = [class1(), class2()]
smallClasses2.forEach { $0.printInt() }
//I can get to the shared values the sub classes have from the super class
smallClasses2.forEach { print($0.sharedInt) }
如果您将上面的代码复制并粘贴到Xcode的Playground中,您将收到以下输出:
Here is SubClass. Count is 1
Here is SubClass. Count is 2
Here is SubClass. Count is 3
Here is SubClass. Count is 2
Here is SubClass. Count is 3
0
0