GeekBand.Swift-面向对象

2016/5/16 posted in  iOS学习笔记  

面向对象三大特性:封装、继承、多态

封装

封装值得是隐藏类的一部分内部结构,避免外部访问或者外部直接访问,只有类自身可以操作。
通常,我们使用gettersetter来达到封装的目的。

访问控制符

  1. private —— private访问级别所修饰的属性或者方法只能在当前的Swift源文件里可以访问。
  2. internal(默认访问级别,internal修饰符可写可不写)—— internal访问级别所修饰的属性或方法在源代码所在的整个模块都可以访问。如果是框架或者库代码,则在整个框架内部都可以访问,框架由外部代码所引用时,则不可以访问。如果是App代码,也是在整个App代码,也是在整个App内部可以访问。
  3. public —— 可以被任何人使用

一个例子

假设我们想要创建一个代表圆的类,那么圆的半径应该是可以改变的。而且,该圆的面积和周长应该可以从圆的实例中获取,而这两个属性不应该被类本身以外所更改。出于性能考虑,面积和周长也应该只计算一次。

class Circle {
    private var area: Double = 0;
    private var diameter: Double = 0;
    var radius: Double {
        didSet {
            calculateFigures();
        }
    }
    init(radius:Double) {
        self.radius = radius;
        calculateFigures();
    }
    private func calculateFigures() {
        area = M_PI * radius * radius;
        diameter = 2 * M_PI * radius;
    }

    func getArea() -> Double {
        return self.area;
    }

    func getDiameter() -> Double {
        return self.diameter;
    } 
}

Swift还为我们提供了简便方法。
通过在属性前面使用private(set),属性就被设置为默认访问等级的 getter方法,但是setter方法是私有的。所以我们可以去掉两个 getter方法:

class Circle {
    private(set) var area: Double = 0;
    private(set) var diameter: Double = 0;
    var radius: Double {
        didSet {
            calculateFigures()
        }
    }
    init(radius:Double) {
        self.radius = radius
        calculateFigures()
    }
    private func calculateFigures() {
        area = M_PI * radius * radius
        diameter = 2 * M_PI * radius
    }
}

当然也可以为属性设置公有的getter方法:

public private(set) var area: Double = 0
public private(set) var diameter: Double = 0

继承

面向对象中,非常重要的一个概念。通过继承,子类可以拥有父类(超类)中的方法和属性,对代码进行复用。
在Swift中,子类继承父类的属性、方法、下标。

一个例子

struct Point{
    var x=0;
    var y=0;
}
class Shape{
    var no=0;
    func move() {
        print("NO: \(no) Shape.move");
    }
}
class Rectangle: Shape{
    var leftUp=Point();
    var width=0;
    var height=0;
    
}
class Circle: Shape{
    var center=Point();
    var radius=0;
}

Rectangle和Circle就继承了Shape中的方法和属性。

方法重写

有的时候,我们需要在子类中对父类的某一个方法进行加工。就需要进行方法的重写。在Swift中,对于方法的重写,必须添加Override关键字。

class Shape{
    var no=0;
    //用final关键字修饰,子类无法重写
    final func show(){
        print("Shape.show");
    }
    func move() {
        print("Shape.move");
    }
}
class Rectangle: Shape{
    //重写父类的no属性
    override var no: Int {
        get{
            print("Rectangle.no.get()");
            return super.no;
        }
        set{
            print("Rectangle.no.set()");
            super.no=newValue;
        }
    }
    override func move() {
        print("Rectangle.move");
    }
    
}
class Circle: Shape{
    override func move() {
        print("Circle.move");
    }
}

继承中的初始化器和析构器

初始化器

  • 如果子类没有定义初始化器,则自动继承父类的初始化器
  • 如果子类定义了初始化器,则不再继承。此时子类的初始化器必须调用父类的一个初始化器。如果手工不调用,编译器将自动生成调用。
  • 如果子类的初始化器与父类的初始化器原型一致,必须使用override
  • 在子类中使用父类属性,必须确保首先调用父类初始化器

析构器

  • 如果子类没有定义析构器,会自动继承父类的析构器
  • 子类析构器执行完毕后,会自动调用父类析构器
  • 子类析构器自动具有多态性

多态

多态,也是面向对象的三大特性之一。即父类引用指向子类对象。在Swift中,每个属性都有两个类型,一个是声明类型,一个是实际类型。这两个类型在值类型中是相等的。但是在类中,可能不同。但是实际类型一定是声明类型本身或其子类。

//如下代码是没有问题的
var rect:Shape;
rect = Rectangle();
//当我们调用rect的move方法的时候,实际调用的是Rectangle中的Move方法。
rect.move();

也可以将多态描述为:子类在同一行为接口下,表现不同的实现方式。