美文网首页
类(二)

类(二)

作者: 小橘子成长记 | 来源:发表于2018-05-23 11:31 被阅读62次

    了解状态和副作用

    类的引用和可变特性导致了大量的编程问题。如果用一个新值更新类的实例,那么对该实例的每个引用也将看到新值。

    你可以利用这个优势。把一个学生的实例传递给一个运动队,一个成绩单和一个班级花名册。所有这些实体都需要知道学生的成绩,由于它们都指向同一个实例,所以它们都将看到新的分数,跟学生实例中的一样。


    QQ20180523-100938@2x.png

    共享的结果是类实例拥有状态(比如学生的成绩就是一个状态,某一时刻某个实例的状态就是成绩等于3)。状态的改变可以有时是显而易见的,但有时候不是。

    为了说明这一点,在Student类上增加一个credits:

    var credits = 0.0
    

    更新 recordGrade(_:) 方法去使用新的属性:

    func recordGrade(_ grade: Grade) {
      grades.append(grade)
      credits += grade.credits
    }
    

    在这个稍微修改过的Student的例子中,recordGrade(:)现在将credits(每科学分)的数量添加到credits(学生学分)属性中。调用recordGrade(:)具有更新credits的副作用。

    现在,观察一下副作用是如何导致不明显的行为的:

    jane.credits // 7
    // The teacher made a mistake; math has 5 credits
    math = Grade(letter: "A", points: 20.0, credits: 5.0)
    jane.recordGrade(math)
    jane.credits // 12, not 8!
    

    无论谁修改Student类,大家都认为相同学科的分数不会被记录两次。其实被记录了两次,一开始Math是4分,后来的Math是5分,增加了1分,正确的应该由原来的7分变成8分。但是,现在是7分直接加了Math的5分。

    虽然在一个小的例子中混淆了,当类的大小和复杂性增加时,可变性和状态可能会非常不和谐。学生的grade是20个存储属性,有10个方法,这样的情况会更常见。

    使用extension扩展一个类

    正如你看到的结构,可以使用extension关键字重新打开类,以添加方法和计算属性。向Student添加一个完整的计算属性:

    extension Student {
      var fullName: String {
        return "\(firstName) \(lastName)"
      }
    }
    

    还可以使用继承将功能添加到类中。你至可以添加新的存储属性来继承类。在下一章中,将详细探讨这一技术。

    何时使用类和结构

    既然你已经了解了类和结构之间的区别和相似之处,你可能会想“我怎么知道该使用哪一个呢?”

    值和对象

    虽然没有严格的规则,但是有一种方法,可以思考一下值和引用语义,使用结构作为值,使用类作为具有标识的对象。对象是引用类型的实例。这样的实例标识。这意味着每个对象都是唯一的,没有两个对象因为它们持有相同的状态被认为是相等的。这就是为什么要使用===来查看对象是否真正相等,而不只是包含相同的状态。这与值类型的实例相反,值类型是值,根据定义,如果它们是相同的值那么它们就是相等的。

    例如:配送范围是一个值,应该作为一个struct来实现,而student是一个对象,应该作为一个类来实现。没有两个学生因为他们有相同的名字就被认为是相等的!

    速度

    速度方面也需要考虑,因为结构依赖于更快的堆栈,而类依赖于较慢的堆。如果你创建一个类型的多个实例(数百到数千个),或者如果这些实例只在内存中存在很短的时间,那么你通常应该倾向于使用struct。如果你的实例在内存中具有更长的生命周期,或者你创建相对较少的实例,那么在堆上创建类实例通常不会产生过多的开销。

    例如,你可能希望使用一个struct来计算运行路线的总距离,使用许多基于gps的路标,比如“结构”中使用的位置结构。你不仅会创建许多路径点,而且还会在修改路线时快速创建和销毁它们。

    相反,您可以使用类作为对象来存储路径历史,因为每个用户只有一个对象,并且你可能会在用户中使用相同的路径对象。

    极简主义的方法

    另一种方法是只使用你所需要的。如果你的数据永远不变,或者你需要一个简单的数据存储,那么就使用结构。如果你需要更新你的数据,你需要它包含逻辑来更新它自己的状态,那么使用类。通常,最好从结构开始。如果稍后你需要一个类的附加功能,那么将struct转换为一个类。

    结构与类重点

    结构
    •用于表示值。
    •隐式复制值。
    •当用let声明时,变得完全不可变。
    •快速内存分配(堆栈)


    •用于表示具有标识的对象。
    •隐式共享对象。
    •内部可以保持可变,即使使用let声明。
    •内存分配较慢(堆)

    关键点

    •与结构类似,类是一个命名类型,它可以具有属性和方法。
    •类在使用时共享引用。
    •类实例称为对象。
    •对象是可变的。
    •可变性引入状态,在管理对象时增加了另一层次的复杂性。
    •当需要引用语义时使用类,当需要值语义时使用结构。

    相关文章

      网友评论

          本文标题:类(二)

          本文链接:https://www.haomeiwen.com/subject/mnnljftx.html