天天看點

協定

        如果類的所有方法都是抽象的,在Swift和Object-C中稱為協定,在Java語言中稱為接口,在C++中稱為純虛類;隻有方法的定義沒有方法的具體實作,所在的類叫抽象類

        協定不能被執行個體化

        Swift和Object-C中實作抽象類的過程稱為遵守協定

一、聲明和遵守協定

        類、結構體和枚舉類型可以聲明與遵守某個協定,并提供該協定所需要的屬性和方法

        協定定義的文法如下:

            protocol 協定名 {

                //内容

}

            在聲明遵守協定時,格式如下:

             類型  類型名:協定1,協定2 {

                    //遵守協定内容

            類型包括類、結構體和枚舉,冒号後面是遵守的協定,如果有多個協定,協定之間用逗号隔開

            協定可以要求其遵守者提供執行個體屬性,靜态屬性,執行個體方法和靜态方法的實作,

二、協定方法

         協定可以要求其遵守者實作某些指定方法,包括執行個體方法和靜态方法,這些方法在協定中被定義,協定方法和普通方法類似,但不支援邊長參數和預設值參數,也不需要大括号和方法體

        1、執行個體協定方法

            protocol Figure {
                func onDraw()
}
             class Rectangle:Figure {
                    func onDraw(){
                        println("繪制矩形")
}
}
                class Circle:Figure {
                    func onDraw(){
                        println("繪制圓形")
}
}      

        2、靜态協定方法

            在協定中定義靜态方法與在類中定義靜态方法一樣,方法前需要添加class關鍵字,在遵守該協定的時候,遵守者靜态方法前加class或者static,與遵守者類型有有關系,如果是類,關鍵字就是class,如果是結構體或枚舉,關鍵字就是static.

            protocol Account {
                    class func interestBy(amount:Double)->Double
}
            class ClassImp:Account {
                    class func interestBy(amount:Double)->Double {
                    return 0.668 * amount
}
}
            class StructImp:Account {
                            static func interestBy(){
                                      return 0.668 * amount   
    }        
}      

        3、變異方法

            在結構體和枚舉類型中可以定義變異方法,而在類中沒有這種方法,原因是結構體和枚舉中的屬性是不可修改,通過定義變異方法,可以修改這些屬性,而類是引用類型,不需要變種方法就可以修改自己的屬性;

            在協定定義變種方法時,方法前要加上mutating關鍵字,類、結構體和枚舉都可以實作變異方法,類實作變異方法時,前面不需要加mutating關鍵字,結構體和枚舉在實作變異方法時,前面需要加mutating關鍵字

            protocol Editable {
                mutating func edit()
}
            class ClassImp:Editable{
                var name = "ClassImp"    
                func edit(){
                        println("編輯ClassImp...")
                        self.name = "編輯ClassImp"                    
    }
}
            struct StructImp:Editable {
                    var name = "StructImp"
                mutating func edit(){
                        println("編輯StructImp")
                        self.name = "編輯StructImp"
}
}      
     struct Enum:Editable {
                    case Monday
                    case Tuesday
                    case Wednesday
                    case Thursday
                    case Friday
                    mutating func edit(){
                        self = .Friday
        }
}      

            4、執行個體協定屬性

                協定可以要求其遵守者實作某些指定屬性,包括執行個體屬性和靜态屬性,在具體定義的時候,每一種屬性都可以有隻讀和讀寫之分

                對于遵守者而言,執行個體屬性時市場靈活的,無論是存儲屬性還是計算屬性,隻要能通過協定屬性的要求,就可以通過編譯,甚至是協定中定義了隻讀屬性,而遵守者提供了對該屬性的讀寫,這也是被允許的,因為遵守者通過了協定的隻讀屬性要求,協定隻規定了必須要做的事情,但沒有規定不能做的事情;

             protocol Person {
                    var firstName:String{get set}
                    var lastName:String {get set}
                    var fullName:String{get}
}
            class Employee:Person {
                    var no:Int = 0
                    var job:String?
                    var salary:Double = 0
                    
                    var firstName:String = "Tony"
                    var lastName:String = "zhang"
                    var fullName:String {
                            get {
                                return "\(firstName)\(lastName))"
}
                            set(newFullName){
                            var name = newFullName.componentsSeperatedByString(".")
                            self.firstName=name[0]
                            self.lastName=name[1]
                    }
            }
}      

三、協定屬性

        在協定中定義靜态屬性與在協定中定義靜态屬性類型,屬性前面要加class關鍵字還是static,與遵守者類型有關系,如果是類,關鍵字是class,如果是結構體和枚舉,關鍵字是static

            protocol Account {
                class var interestRate:Double {get}
                class func interestBy(amount:Double)->Double
}
            class ClassImp:Account{
                class var interestRate:Double {
                        return 0.668
}
                class func interestBy(amount:Double)->Double{
                        return ClassImp.interestRate * amount
}
}
                 struct StructImp:Account {
                        static var interestRate:Double = 0.668
                        static func interestBy(amount:Double)->Double {
                                return StructImp.interestRate * amount
}
}      

四、把協定作為類型使用

            雖然協定沒有具體的實作代碼,不能被執行個體化,但它的存在是為了規範其遵守者而設計的,它是面向接口程式設計必不可少的機制,面向接口程式設計的系統的定義與實作應該分離,協定作為資料類型暴露給使用者,使其不用關心具體的實作細節,進而提供系統的擴充性和複用性;

            在Swift中,協定作為資料類型使用,它可以出現在任意允許資料類型出現的地方:

            protocol Person {
                var firstName:String{get set}
                var lastName:String {get set}
                var fullName:String{get}
                fun description()->String 
}
           class Student:Person {
                    var school:String
                    var firstName:String
                    var lastName:String
                    var fullName:String {
                            return self.firstName + self.lastName
}
                    func description()->String {
                        return self.firstName+self.lastName+self.school
}
                    init(firstName:String,lastName:String,school:String){
                        self.firstName = firstName
                        self.lastName = lastName
                        self.schooll = school
}
}      

五、協定的繼承

            一個協定繼承就像是類繼承一樣:

           protocol Person {
                var firstName:String{get set}
                var lastName:String {get set}
                var fullName:String{get}
                fun description()->String 
}      
                        protocol Student:Person {
                                    var school:String
}
                        class Graduate:Student{
                                    
}      

六、協定的合成

        protocol Ship {
                var displacement:Double {get set}
}
        protocol Weapon {
                 var gunNumber{get set}
}
        class WarShip:Ship,Weapon{
                    var displacement = 100000.00
                    var gunNumber = 10
}
        func showWarResource(resource:protocol<Ship,Weapon>){
                    println("\(resource.displacement):\(resource.gunNumber)")
}
    let ship = WarShip()
    showWarResource(ship)      

繼續閱讀