iOS開發入門 ☞ OC語言·筆記六,iosoc

來源:互聯網
上載者:User

iOS開發入門 ☞ OC語言·筆記六,iosoc
物件導向的三大特性: 封裝, 繼承, 多態1. 封裝

1.1 基本概念

將零散的東西組合起來。

  • 廣義上封裝指:將代碼封裝成函數,將執行個體變數和方法封裝成類,將類封裝成架構....
  • 物件導向中的封裝指:封裝屬性和方法放在一個對象中,只給外界公開訪問的介面,而且把具體實現隱藏起來。

1.2 封裝的好處

提高可讀性,可維護性,可擴充性

1.3 OC中的封裝

OC語言天然就是封裝好的。

定義一個類時,@interface部分就是給外界公開的提供者。@implementation部分就是隱藏起來的具體實現。

.h檔案中寫的是公開的介面

.m檔案中寫的是隱藏的實現

//私人方法,只要不在標頭檔的介面部分聲明的方法就是私人方法

2. 繼承

2.1 概念

繼承是一種代碼複用技術(代碼重複使用)。是類與類之間的一種關係(“is a”關係)。

B類繼承了A類。A類叫B類的父類,B類叫A類的子類。

其他語言中還有基類,衍生類別的概念

2.2 繼承的方式

    單繼承  OC, Java...., Swift    單繼承指一個類只能有一個父類.

    多繼承  C++支援多繼承      多繼承指一個類可以有多個父類.

    OC語言中的類在一顆樹上,只有一個祖宗NSObject; swift不只有一顆樹,是一片森林。

2.3 OC中繼承的文法

@interface 類名 : 父類名

 

@end

2.4 什麼情況下用繼承

理論上:

      如果兩個類之間擁有is a關係,這兩個類應該是繼承關係。

  狗是動物  Dog is a Animal.

        Animal是父類, Dog是子類

      如果兩個類之間擁有has a關係,應該用組合或彙總

  計算中有一個CPU  Computer has a CPU

  組合和彙總是另一種類與類之間的關係

實際開發中使用繼承:

先寫的父類,還是先寫的子類?//都可以

 

2.5 抽象類別

C++: 純虛函數,沒有函數體的函數。存在純虛函數的類是抽象類別,不可以執行個體化了對象。

Java: 抽象方法和抽象類別, abstract來聲明

OC: OC語言中沒有抽象類別和抽象方法的文法。

派生:在子類中添加新的屬性和方法

2.6 重寫:子類對父類的方法不滿意時,可重寫父類中的方法

           隱藏:當子類重寫父類的方法後,子類中將有兩個同名的方法,而從父類中繼承的方法不能在類外被調用

2.6.1 概念

1) override 重寫(覆蓋): 子類不滿意從父類中繼承來的方法,重新將此方法實現了。

要求:方法名和父類一樣,參數類型一樣,傳回值一樣。只有方法的實現不一樣。

2) overload 重載: OC中並不存在overload。

overload的概念是在一個範圍內(比如一個類中),出現多個方法名相同的方法,這些方法的參數類型不同,導致可以同時出現,我們說,這些方法之間形成了重載的關係。

OC中不允許同一個範圍存在多個方法名相同的方法。

-(id)initWithName:(NSString *)name andAge:(NSUInteger)age;

-(id)initWithName:(NSString *)name andGender:(BOOL)gender; //OC中方法名不同

OC中只有重寫,沒有重載

方法的重寫:子類對父類繼承的方法不滿意,可以在子類中重寫父類的方法。

如果重寫父類的方法,優先調用子類的方法,如果子類沒有重寫父類的方法,則調用父類的方法。

 

2.6.2 注意

雖然父類中的屬性是公開的,但產生的執行個體變數卻是私人的,在子類中不能訪問

2.6.3 普通方法的重寫

如同perimeter, area, show

方法名相同,參數類型相同,傳回值相同

2.6.4 屬性的重寫

如同TRSqaure中的width,height屬性

2.6.5 特殊方法的繼承和重寫

1) 初始化方法

在OC中初始化方法是會被繼承的。

繼承來的初始化方法有些可以用,有些不能用。

如果在子類中,繼承自父類的初始化方法不能用(不能完成要求的初始化任務),在子類中就需要重寫這個初始化方法。

2) 類方法(Factory 方法)

類方法也可以被繼承

Factory 方法自然也可以被繼承,但直接繼承的Factory 方法名不匹配,實際開發中很少這樣用。子類最好提供自己的Factory 方法。

2.7 繼承的缺陷

  1) 提高了程式的複雜度,維護性和擴充性降低。 

  2) 破壞類的封裝性  慎用繼承!

2.8 為什麼使用繼承?

  1) 代碼複用 

    將子類重複的代碼抽象到父類中

  2) 制定規範(規則)

    NSObject  

  3) 為了多態

    沒有繼承,就沒有多態

組合與彙總

  類與類之間的一種關係,比較常見;主要作用:代碼複用!

1.1 什麼是組合

  表示兩個對象之間是整體和部分的強關係,是“contains(包含) a”關係,要求兩個類同生共死。

生命週期完全一致,同生共死。部分的生命週期不能超越整體!

例如:一個視窗內有按鈕、標籤,當視窗關閉時,視窗與按鈕、標籤同時銷毀。

 

1.2 組合的定義:

@interface BRButton : NSObject

@end

@interface BREdit : NSObject

@end

@interface BRWindow : NSObject

/**

 *  組合是兩個類的強關係(要求定義成成員變數)

 *  1.在對象初始化時給執行個體變數賦值(同生共死)

 *  2.不能在類的外部對執行個體變數訪問/賦值

 */

{

    BRButton *button;

    BREdit *edit;

}

@end

 

  組合Demo:

    

    

1.3 組合的優缺點:

優點:

1)當前對象只能通過所包含的那個對象去調用其方法,所以所包含的對象的內部細節對當前對象是不可見的。

2)當前對象與包含的對象是一個低耦合關係,如果修改包含對象的類中代碼,不需要修改當前對象類的代碼。

3)當前對象可以在運行時動態綁定所包含的對象。可以通過set方法給所包含對象賦值。

缺點:

容易產生過多的對象

為了能組合多個對象,必須仔細對介面進行定義。

 

1.4 什麼是彙總

表示兩個對象之間是整體和部分的弱關係,是”has a”關係,不要求兩個類同生共死。

生命週期不一致,一個類無法控制另一個類的生死。部分的生命週期可以超越整體。

例如:電腦和滑鼠,電腦被銷毀時,滑鼠可以留下在其他電腦上繼續使用。

1.5 彙總的定義

@interface BRMouse : NSObject

@end

@interface BRComputer : NSObject

//彙總是兩個類的弱關係,在類的外部給執行個體變數賦值(要求定義成屬性)

@property BRMouse *mouse;

@end

 

  彙總Demo:

    

1.6 彙總的優缺點:

優點:

1)被包含的對象通過包含它們的類來訪問

2)很好的封裝

3)被包含的對象內部細節不可見

4)可以在運行時動態定義彙總的方式

缺點:

1)系統可能會包含太多個物件

2)當使用不同的對象時,必須小心定義的介面。

組合和彙總的生命週期不一樣,組合是同生共死(關係緊密);彙總沒有特別的關係。

 

1.7  類與類之間常見的三種關係:繼承、組合、彙總

  1) 繼承(繼承的主要目的:代碼複用,制定規範,為了多態)  慎用繼承!(is a關係才用繼承,否則濫用繼承)

  2) 組合和彙總(單純的為了代碼複用)

          組合和彙總的主要目的:是為了代碼的複用。

   

應用情境:(代碼的重複使用。如果想使用別人的代碼,組合、彙總在一起就可以了)

實際開發中,如果為了複用代碼,提倡使用組合或彙總來複用,而不用繼承。即是把一個類作為另一個類的屬性。(整體與部分)

 

一個類想使用另一個類的方法?怎麼實現...

1.繼承:我繼承你,我就可以直接調你的方法(提高程式的複雜度…不建議用!)

2.組合/彙總:把你變成我的一部分(即你是我的屬性),我可以通過訪問你去調用你的方法![我.你 你的方法];

 

組合:關係很緊密,同生共死。(cpu焊在主板上,主板壞了cpu也就壞了;綁在一起同生共死!)

彙總:關係很疏遠,不同生共死。(電腦是電腦,cpu是cpu;這個cpu可以用給這個電腦,也可以用給那個電腦,cpu可以從主板上拔下來給另一個電腦用)

3. 多態(Polymorphism)

3.1 什麼是多態

多種形態,引用的多種形態。對於一個引用變數,可以指向任何類的對象 (一個對外介面,多個內在實現)

 

    父類的引用指向本類或任何子類的對象,會調用不同的方法(表現出多種形態,這種表現叫多態)

TRAnimal *animal = [[TRDog alloc]init];//父類的引用指向子類的對象

[animal eat];//狗啃骨頭 (調用子類重寫的方法)

animal = [[TRCat alloc]init];

[animal eat];//貓吃魚

   多態的表現:同一個引用變數s,調用相同的方法(show),顯示不同的結果。

TRShape *s=[[TRRect alloc]init]; //父類的引用指向子類的對象

[s show]; //顯示矩形  調用子類重寫的方法

s=[TRCircle alloc]init];

[s show]; //顯示圓形

 

3.2 編譯期類型和運行期類型

編譯器編譯時間,引用的類型叫編譯期類型。

程式運行時,引用指向的類型叫運行期類型。

       

  程式編譯時間按編譯期類型找方法編譯,程式運行時按運行期類型找方法調用。

  父類的引用指向子類的對象時,只能調用父類中有的方法。

  因為編譯器在編譯時間是按父類來檢查的,雖然運行時調用的是子類的方法,但是編譯時間是按父類來檢查的。

3.3 為什麼用多態

為什麼用父類的引用指向子類的對象:

為了寫出更加能用(通用),相容性更好的代碼。

 

3.4 多態的各種表現【用途】

1)【多重參數變形】經常在方法的參數表現多態:參數類型使用父類型,可以傳任何子類的對象

NSObject *和id類型做為方法的參數區別在於:

NSObject *類型的引用只能調用NSObject類中有的方法。

id類型的引用可以調用任何存在(不能瞎寫)的方法。

(一般不用NSObject *類型,用id類型替代。id有風險的,編譯器根本不檢查對錯)

/** 方法的參數 表現多態 */

void showAnimal(TRAnimal *animal) {

    [animal eat];

    [animal sleep];

    //[animal watchHome];//父類中沒有這個方法編譯不通過

}

int main() {

    @autoreleasepool {

        TRDog *dog = [[TRDog alloc]init];

        showAnimal(dog);

        showAnimal([TRCat new]);

    }

    return 0;

}

 

  2)【傳回值多態】方法的傳回值上表現多態

    

3)【數組多態】在數組和集合中表現的多態

//數組 表現多態 [多個對象同時執行eat方法]

TRAnimal *animals[3] = {[TRAnimal new], [TRDog new], [TRCat new]};

for (int i = 0; i < 3; i++) {

[animals[i] eat];

}

  

 多態無處不在!

 

 

多態Demo

  

    

    

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.