類有三大特性:繼承郭怪,封裝,多態(tài):
封裝
封裝就是對(duì)類中的一些字段呻畸,方法進(jìn)行保護(hù)移盆,不被外界所訪問到,有一種權(quán)限的控制功能伤为,Java中有四種訪問權(quán)限修飾符:
public咒循,default,protected绞愚,private
訪問權(quán)限依次遞減叙甸,我們?cè)诙x類時(shí),哪些字段和方法不想暴露出去位衩,哪些字段和方法可以暴露裆蒸,可以通過修飾符來完成,這就是封裝糖驴;
在OC語言中僚祷,使用@interface和@implementation來處理類佛致。
@interface就好像暴露在外面的時(shí)鐘表面,像外界提供展示以及接口辙谜。@implementation就好像隱藏在時(shí)鐘內(nèi)部的構(gòu)造實(shí)現(xiàn)俺榆,把具體的實(shí)現(xiàn)封裝了起來。
(ps:@interface 中是成員變量装哆,@implementation 是全局變量)
Car.h
#import
@interface?Car?:?NSObject{
//這個(gè)屬性就是對(duì)外進(jìn)行保密的相當(dāng)于private罐脊,所以我們需要在外部訪問的話,必須定義get/set方法
//默認(rèn)的是private的蜕琴,但是我們可以使用@public設(shè)置為public屬性的,那么在外部可以直接訪問:person->capcity?=?2.8;
//當(dāng)然我們一般不這么使用萍桌,因?yàn)檫@會(huì)破壞封裝性,這種用法相當(dāng)于C中的結(jié)構(gòu)體中權(quán)限
//一共四種:@public,@protected,@private,@package,這個(gè)和Java中是相同的
@public
float?_capcity;?//油量屬性
}
-?(void)run:(float)t;
@end
這里我們可以看到凌简,OC中也是有四種訪問權(quán)限修飾符:
@public上炎、@protected、@private号醉、@package
其中默認(rèn)的修飾符是@private
但是這里要注意的是:OC中的方法是沒有修飾符的概念的反症,這個(gè)和Java有很大的區(qū)別,一般都是公開訪問的畔派,即public铅碍,如果想讓一個(gè)方法不被外界訪問的話,只需要在.m文件中實(shí)現(xiàn)這個(gè)方法线椰,不要在頭文件中進(jìn)行定義胞谈,說白了就是:該方法有實(shí)現(xiàn),沒定義憨愉,這樣外界在導(dǎo)入頭文件的時(shí)候烦绳,是沒有這個(gè)方法的,但是這個(gè)方法我們可以在自己的.m文件中進(jìn)行使用配紫。
開發(fā)過程中径密,考慮到安全性要求,一般不在成員變量名前面使用@public躺孝、@protected等關(guān)鍵字修飾享扔,而是使用Set方法來為對(duì)象提供成員變量的值。在set方法的內(nèi)部也可以對(duì)一些不合理的賦值進(jìn)行篩選過濾植袍。
命名規(guī)范:
(1)方法名必須以set開頭
(2)Set后面跟上成員變量的名稱惧眠,首字母大寫
(3)返回值一定是void
(4)一定要接收一個(gè)參數(shù),而且參數(shù)類型需要和成員變量的類型一致
(5)形參名不能和成員變量名一樣(蘋果官方推薦成員變量名前加_以示區(qū)分)
繼承
繼承是類中的一個(gè)重要的特性于个,他的出現(xiàn)使得我們沒必要?jiǎng)e寫重復(fù)的代碼氛魁,可重用性很高。當(dāng)然OC中的繼承和Java中是一樣的,沒多大區(qū)別秀存,這里在看一個(gè)例子吧:
父類:Car
Car.h
#import
@interface?Car?:?NSObject{
NSString?*_brand;
NSString?*_color;
}
-?(void)setBrand:(NSString?*)brand;
-?(void)setColor:(NSString?*)color;
-?(void)brake;
-?(void)quicken;
@end
Car.m
#import "Car.h"
//引入頭文件
@implementation?Car
-?(void)setBrand:(NSString?*)brand{
_brand?=?brand;
}
-?(void)setColor:(NSString?*)color{
_color?=?color;
}
-?(void)brake{
NSLog(@"剎車");
}
-?(void)quicken{
NSLog(@"加速");
}
@end
方法的實(shí)現(xiàn)
在來看一下子類:
Taxi.h
#import "Car.h"
@interface?Taxi?:?Car{
NSString?*_company;//所屬公司
}
//打印發(fā)票
-?(void)printTick;
@end
Taxi類繼承了父類Car, 需要導(dǎo)入父類的頭文件捶码,在Taxi類中多了Car 的一個(gè)屬性和方法
Taxi.m
#import "Taxi.h"
@implementation?Taxi
-?(void)printTick{
[super?brake];
[self?brake];
NSLog(@"%@出租車打印了發(fā)票,公司為:%@,顏色為:%@",_brand,_company,_color);
}
@end
對(duì)方法的實(shí)現(xiàn)或链,看到實(shí)現(xiàn)文件中是不需要導(dǎo)入父類Car的頭文件的宙项,因?yàn)榭梢哉J(rèn)為,Taxi.h頭文件中已經(jīng)包含了Car的頭文件了株扛。
而且,這里可以使用super關(guān)鍵字來調(diào)用父類的方法汇荐,也是可以用self關(guān)鍵字來調(diào)用洞就,這里看到其實(shí)這兩種方式調(diào)用的效果是一樣的,當(dāng)子類重新實(shí)現(xiàn)brake方法的時(shí)候(Java中的重寫概念)掀淘。
那么這時(shí)候super關(guān)鍵字調(diào)用的還是父類的方法旬蟋,而self調(diào)用的就是重寫之后的brake方法了。同樣革娄,我們也是可以使用父類中的屬性倾贰。
附上一句理解的話就是,老爸就是超級(jí)的拦惋,自己的就是self
Train.h
#import "Car.h"
//火車類繼承Car
@interface?Train?:?Car{
float?_maxWeight;//最大載貨量
}
//覆蓋父類的方法brake
//優(yōu)先調(diào)用子類的方法
-?(void)brake;
-?(void)unload;
@end
自己定義了一個(gè)brake方法匆浙,這時(shí)候就會(huì)覆蓋父類中的brake方法了。
Train.h
#import "Train.h"
@implementation Train
-?(void)brake{
[super?brake];
NSLog(@"Train類中的brake方法");
}
-?(void)unload{
[super?brake];//調(diào)用父類的方法
[self?brake];//也是可以的
NSLog(@"%@的火車卸貨了厕妖,載貨量:%.2f,車的顏色:%@",_brand,_maxWeight,_color);
}
@end
可以看到首尼,在brake方法中調(diào)用一下父類的brake方法,然后在實(shí)現(xiàn)自己的邏輯代碼言秸。
多態(tài)
大學(xué)上了三年多的課软能,無時(shí)無刻都在聽到多態(tài)這個(gè)詞,但是以前感覺自己不認(rèn)真举畸,也沒怎么重視這個(gè)東西查排,其實(shí)這東西一直很重要這是真的。
Printer.h
#import
@interface?Printer?:?NSObject
-?(void)?print;
@end
Printer.m
#import "Printer.h"
@implementation?Printer
-?(void)print{
NSLog(@"打印機(jī)打印紙張");
}
@end
PrinterCorl.h
#import "PrinterCor.h"
//修改父類的打印行為
@interface?ColorPrinter?:?Printer
-?(void)print;
@end
PrinterCorl.m
#import "PrinterCorl.h"
@implementation ColorPrinter
-?(void)print{
NSLog(@"彩印");
}
@end
BlackPrinter.h
#import "BlackPrinter.h"
@implementation?BlackPrinter
-?(void)print{
NSLog(@"黑白打印機(jī)");
}
@end
這里我們?cè)诙x一個(gè)Person類抄沮,用來操作具體的打印機(jī)
Person.h
@implementation Person
- (void)doPrint:(Printer *)printer{
}
@end
Person.m
#import "Person.h"
@implementation?Person
/*
-?(void)?printWithColor:(ColorPrinter?*)PrintCorl{
[colorPrint?print];
}
-?(void)?printWithBlack:(BlackPrinter?*)blackPrint{
[blackPrint?print];
}
*/
-?(void)?doPrint:(Printer?*)printer{
[printer?print];
}
@end
main.m
#import "Person.h"
#import?"BlackPrinter.h"
#import?"PrinterCorl.h"
int?main(int?argc,?const?charchar?*?argv[])?{
@autoreleasepool?{
Person?*person?=[[Person?alloc]?init];
PrinterCorl *colorPrint?=?[[ColorPrinter?alloc]?init];
BlackPrinter?*blackPrint?=?[[BlackPrinter?alloc]?init];
//多態(tài)的定義
/*
Printer?*p1?=?[[ColorPrinter?alloc]?init];
Printer?*p2?=?[[BlackPrinter?alloc]?init];
[person?doPrint:p1];
[person?doPrint:p2];
*/
//通過控制臺(tái)輸入的命令來控制使用哪個(gè)打印機(jī)
int?cmd;
do{
scanf("%d",&cmd);
if(cmd?==?1){
[person?doPrint:colorPrint];
}else?if(cmd?==?2){
[person?doPrint:blackPrint];
}
}while?(1);
}
return?0;
}
下面就來詳細(xì)講解一下多態(tài)的好處
上面的例子是一個(gè)彩色打印機(jī)和黑白打印機(jī)這兩種打印機(jī)跋核,然后Person類中有一個(gè)操作打印的方法,當(dāng)然這個(gè)方法是需要打印機(jī)對(duì)象的合是,如果不用多態(tài)機(jī)制實(shí)現(xiàn)的話(Person.h中注釋的代碼部分)了罪,就是給兩種打印機(jī)單獨(dú)定義個(gè)操作的方法,然后在Person.m(代碼中注釋的部分)中用具體的打印機(jī)對(duì)象進(jìn)行操作聪全,在main.m文件中泊藕,我們看到,當(dāng)Person需要使用哪個(gè)打印機(jī)的時(shí)候,就去調(diào)用指定的方法:
這種設(shè)計(jì)就不好了娃圆,為什么呢玫锋?假如現(xiàn)在又有一種打印機(jī),那么還需要在Person.h中定義一種操作這種打印機(jī)的方法讼呢,那么后續(xù)如果在添加新的打印機(jī)呢撩鹿?還在添加方法嗎?那么Person.h文件就會(huì)變得很臃腫悦屏。所以這時(shí)候多態(tài)就體現(xiàn)到好處了节沦,使用父類類型,在Person.h中定義一個(gè)方法就可以了:
-?(void)?doPrint:(Printer?*)printer;
這里看到了础爬,這個(gè)方法的參數(shù)類型就是父類的類型甫贯,這就是多態(tài),定義類型為父類類型看蚜,實(shí)際類型為子類類型
-?(void)?doPrint:(Printer?*)printer{
[printer?print];
}
這里調(diào)用print方法叫搁,就是傳遞進(jìn)來的實(shí)際類型的print方法。
Printer?*p1?=?[[ColorPrinter?alloc]?init];
Printer?*p2?=?[[BlackPrinter?alloc]?init];
[person?doPrint:p1];
[person?doPrint:p2];