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) 類方法(工廠方法)
類方法也可以被繼承
工廠方法自然也可以被繼承,但直接繼承的工廠方法名不匹配,實際開發中很少這樣用。子類最好提供自己的工廠方法。
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
【iOS開發入門 ☞ OC語言·筆記六】的相關資料介紹到這裡,希望對您有所幫助! 提示:不會對讀者因本文所帶來的任何損失負責。如果您支持就請把本站添加至收藏夾哦!