简介
这篇文章同样适合于那些对“Class”和"Struct"的区别不太清楚的同学,我们知道结构体不支持“继承”,为什么呢?
如果你不知道答案的话,请阅读下面的代码
class HumanClass {
var name: String
init(name: String) {
self.name = name
}
}
var classyHuman = HumanClass(name: "Bob")
classyHuman.name // "Bob"
var newClassyHuman = classyHuman // Created a "copied" object
newClassyHuman.name = "Bobby"
classyHuman.name // "Bobby"
当我们把"newClassyHuman.name"改成"Bobby"时, classyHuman.name同样也变成了"Bobby"
现在让我们再看看结构体
struct HumanStruct {
var name: String
}
var humanStruct = HumanStruct(name: "Bob" )
var newHumanStruct = humanStruct // Copy and paste
newHumanStruct.name = "Bobby"
humanStruct.name // "Bob"
很明显,新复制的对象"newHumanStruct"中"name"属性的变化并没有影响原来的结构体"humanStruct"的变化
类中,当你复制一个对象,两个对象指针在内存中都会指向同一个对象,所以当一个对象的某个属性变化了,另外一个对象的属性也跟着变化(这里只是对索引进行了copy),然而,在结构体中,通过创建一个新的独立对象来进行复制粘贴(这里对索引所关联的对象也进行了复制)
Bye,OOP
当然面向对象编程有很多好处,但是它同样存在劣势
- 继承中,子类会继承父类中很多自己并不需要的属性或方法,不可避免的使子类变得冗余
- 当有很多父类的时候,在编码或者修复bug的时候,你很难理清楚这些类的层级关系
- 当你进行复制的时候,由于这些索引在内存中指向同一块地址空间,所以当其中一个发生微小的变化,剩下的都会跟着变化。
接下来,让我们看一下,UIKit framework在OOP中的继承关系
Welcome, POP
不同于类和结构体,POP扁平化并且有效的降低代码的耦合性
“A protocol defines a blueprint of methods, properties…
The protocol can then be adopted by a class,
structure, or enumeration” — Apple
这里 "blueprint"是需要重点关注的
让我们继续用“human”为例来创建自己的"blueprint"
protocol Human {
var name: String {get set}
var race: String {get set}
func sayHi()
}
正如你所见,协议中并没有什么惊艳的操作,它仅仅是告诉你这些属性或方法的客观存在。所以暂时不需要关心它的{get set},它仅仅表明你可以给这些属性赋值或通过“get”方法拿到对应的值。所以在你需要处理这些值之前不需要关注它的具体实现。
接下来我们创建一个遵从"Human"协议的结构体 "Chinese"
struct Chinese: Human {
var name: String = "Bob Lee"
var race: String = "Asian"
func sayHi() {
print("Hi, I'm \(name)")
}
}
一旦这个结构体遵从了"Human"协议,它就必须实现协议里的方法和所有的属性,如果不这样,Xcode就会报错