封装概念及其原理
一个Gun类的例子来详细说明这一环节:
#import <Foundation/Foundation.h>
@interface Gun : NSObject
{
@public
int _bulletCount;
}
-(void)shoot;//这是射击的方法,前提是有子弹(子弹>=0),子弹数目<0则没有意义,我们要让方法整体符合逻辑。
-(void)setGunBullet:(int)bullet;//我们虽然可以在shoot方法中将子弹数目的判定写上,但是这样做有一点点不符合常理。这是因为如果我们只写一个shoot方法,而我们传的值为-3,然后让shoot去接收-3这个值判断,如果在shoot方法内先打印一下子弹数,很明显子弹数为-3是不对的,是不安全的。我们根本不需要去接收这个不正确的值,接收了说明不严谨。所以说我们需要一个方法去预处理一下子弹的个数,这也是体现的封装的思想。
@end
@implementation Gun
-(void)shoot
{
if (_bulletCount>0) {
_bulletCount--;
NSLog(@"tututu ...");
}
else
{
NSLog(@"No bullet!");
}
}
-(void)setGunBullet:(int)bullet
//在setGunBullet:方法中,我们先接收输入的值判断,然后再将处理过的值传给实例变量_bulletCount,处理之后的值肯定是>=0的,符合了子弹数目的逻辑(有子弹>0,没有子弹=0)
{
if (bullet>0) {
_bulletCount=bullet;
}
else
{
_bulletCount=0;
}
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Gun *gun=[[Gun alloc]init];
[gun setGunBullet:3];
[gun shoot];
[gun shoot];
[gun shoot];
[gun shoot];
[gun shoot];
}
return 0;
}
———————————————————————————————————————————
封装的实现步骤
★★★这一部分是重点哦!重点记忆!★★★
★定义 设置实例变量(setter)方法 和 访问实例变量(setter)方法,在这里我们可以通俗的将set记为设置成员变量的值,将get记为获取成员变量的值。
(这里的实例变量就是声明类的时候的属性成员变量,叫法很多)
(1)setter方法(设置器)
在开发过程中,出于安全性的考虑,我们不会在成员变量名的前面使用 @public 、@protected 等关键字进行修饰,而是使用set方法来为对象提供成员变量的值,在set方法的内部也对一些不合理的赋值进行过滤。
set方法的作用:为外界提供一个设置成员变量值的方法。
★set方法的命名规范:
①set方法一定是一个对象方法( - 号开头)
②set方法一定 没有返回值(返回值为void类型)
③set方法的方法名必须set开头
④set方法的方法名在 写完set开头 后应该跟成员变量名去掉下划线后首字母大写的单词
(如:成员变量名为 _name,那么set方法名为 setName)
⑤set方法必须有参数,而且参数的类型要和该成员变量的类型保持一致
⑥参数的参数名是成员变量名去掉下划线后的单词
(如:成员变量名为 _age,那么set方法的参数名为 age。苹果官方推荐 成员变量名 前面加下划线 “ _ ” 以示区分)
⑦形参名不能和成员变量名同名(这一条和第⑥条差不多)
⑧set方法实现一定要通过形参给成员变量(实例变量)赋值(这也是set方法的作用~)
(2)getter方法(访问器)
get方法的作用:为外界提供一个获取(返回、得到)成员变量值的方法
★get方法的命名规范:
①get方法一定是一个对象方法 ( - 号开头)
②get方法一定 有返回值,且返回值类型和成员变量的类型一致
③get方法的方法名是去掉下划线的成员变量名
(如:成员变量名为 _name,那么get方法名为name,★注意没有get开头★,这里是和java不一样的)
④get方法一定没有参数
⑤get方法实现一定是返回(获取)成员变量(实例对象)的值
下面一个Person类的例子向大家详细介绍set、get方法的定义与使用:
#import <Foundation/Foundation.h>
typedef enum {kSexMan,kSexWoman,kSexYao}Sex;
@interface Person : NSObject
{
NSString *_name;
Sex _sex;
int _age;
float _height;
}
//以后设置(赋值)_name、_sex 等等成员变量(实例变量)的值,都统一使用其set方法
//_name的set方法
-(void)setName:(NSString *)name;
//_sex的set方法
-(void)setSex:(Sex)sex;
//_age的set方法
-(void)setAge:(int)age;
//_height的set方法
-(void)setHeight:(float)height;
//以后访问(获取)_name、_sex 等等成员变量(实例变量)的值,都统一使用其get方法
//_name的get方法
-(NSString *)name;
//_sex的get方法
-(Sex)sex;
//_age的get方法
-(int)age;
//_height的get方法
-(float)height;
@end
@implementation Person
//-----------------------set 方法的实现-----------------------
//_name的set方法
-(void)setName:(NSString *)name
{
_name=name;
}
//_sex的set方法
-(void)setSex:(Sex)sex
{
_sex=sex;
}
//_age的set方法
-(void)setAge:(int)age
{
_age=age;
}
//_height的set方法
-(void)setHeight:(float)height
{
_height=height;
}
//-----------------------get 方法的实现-----------------------
//_name的get方法
-(NSString *)name
{
return _name;
}
//_sex的get方法
-(Sex)sex
{
return _sex;
}
//_age的get方法
-(int)age
{
return _age;
}
//_height的get方法
-(float)height
{
return _height;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p=[Person new];
// 以后我们对实例变量操作都要用set、get方法,封装之后安全性高
[p setName:@"wang"];//调用_name的set方法,为其实例变量赋值
NSLog(@"name:%@",[p name]);//调用_name的get方法,获取返回值,并打印出来
[p setAge:21];
NSLog(@"name:%d",[p age]);
[p setSex:kSexMan];
NSLog(@"name:%d",[p sex]);
[p setHeight:179.5];
NSLog(@"name:%.2f",[p height]);
}
return 0;
}
———————————————————————————————————————————
封装的应用案例(股票k线计算)
#import <Foundation/Foundation.h>
@interface KLine : NSObject
{
float _minPrice;//最低股价,可读(get)写(set)
float _maxPrice;//最高股价,可读写
float _avPrice;//平均股价,只读(get)
}
-(void)setMinPrice:(float)minPrice;
-(float)minPrice;
-(void)setMaxPrice:(float)maxPrice;
-(float)maxPrice;
-(float)avPrice;
@end
@implementation KLine
-(void)setMinPrice:(float)minPrice
{
_minPrice=minPrice;
_avPrice=(_maxPrice+_minPrice)/2;//我们在_minPrice和_maxPrice的set方法中都加了一句计算平均值的语句,这样的话很好的向大家展示出只要两个值的其中一个发生了改变,平均值就立马发生变化,而不是等到我们读_avPrice的时候才发生变化。这样的写法才更符合逻辑
}
-(float)minPrice
{
return _minPrice;
}
-(void)setMaxPrice:(float)maxPrice
{
_maxPrice=maxPrice;
_avPrice=(_maxPrice+_minPrice)/2;
}
-(float)maxPrice
{
return _maxPrice;
}
-(float)avPrice
{
// _avPrice=(_maxPrice+_minPrice)/2;
// 我们完全可以直接在实例变量_avPrice的get方法内写上面这一句,这样只要_minPrice或者_maxPrice发生了变化,那么_avPrice的值就发生变化,但是这样意义体现的不是很明确。
return _avPrice;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
KLine *kline=[KLine new];
[kline setMaxPrice:55.9];
[kline setMinPrice:23.8];
NSLog(@"avPrice:%.2f",[kline avPrice]);
}
return 0;
}
我觉得上面这个程序需要着重注意的地方有两点:
①可读写的意思:读(get),写(set)
②注意在取平均值的时候,一定要符合逻辑性,结果可能都是一个样子,但是怎么出来的结果要格外严谨!
———————————————————————————————————————————
依赖关系
下面通过一个简短的小程序来解释一下这一部分。
#import <Foundation/Foundation.h>
@interface IPhone : NSObject
{
NSString *_phoneNum;
}
-(void)setPhoneNum:(NSString *)phoneNum;
-(void)callPhone;
-(void)sendMessage;
@end
@interface Girl : NSObject
-(void)callPhoneToTuhao:(IPhone *)phone;
-(void)sendMessageToTuhao:(IPhone *)phone;
@end
@implementation IPhone
-(void)setPhoneNum:(NSString *)phoneNum
{
_phoneNum=phoneNum;
}
-(void)callPhone
{
NSLog(@"给土豪打电话,电话为:%@",_phoneNum);
}
-(void)sendMessage
{
NSLog(@"给土豪发短信,电话为:%@",_phoneNum);
}
@end
@implementation Girl
-(void)callPhoneToTuhao:(IPhone *)phone
{
[phone setPhoneNum:@"18363861160"];
[phone callPhone];
}
-(void)sendMessageToTuhao:(IPhone *)phone
{
[phone setPhoneNum:@"18363861160"];
[phone sendMessage];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
//有这么两个类:Girl和IPhone
//美女要通过电话给土豪联系,所以说美女依赖于电话,电话是美女打电话时的一个参数!
IPhone *ip7=[IPhone new];
Girl *girl=[Girl new];
[girl callPhoneToTuhao:ip7];
[girl sendMessageToTuhao:ip7];
}
return 0;
}
//ip7 girl
//A对象 作为 B对象 的局部变量或者是方法形参时,B依赖于A,如刚刚的我们写的程序:
//[girl callPhoneToTuhao:ip7] girl对象依赖于ip7对象
———————————————————————————————————————————
关联关系
下面通过一个简短的小程序来解释一下这一部分。
#import <Foundation/Foundation.h>
@interface IPad : NSObject
{
NSString *_name;
}
-(void)setName:(NSString *)name;
-(void)showMusic;
-(void)showMovie;
-(void)playGames;
@end
@interface Person : NSObject
{
NSString *_name;
IPad *_ipad;
}
-(void)setName:(NSString *)name;
-(void)setIPad:(IPad *)ipad;
-(void)listenMusic:(IPad *)ipad;
@end
@implementation IPad
-(void)setName:(NSString *)name
{
_name=name;
}
-(void)showMusic
{
NSLog(@"正在用%@播放音乐!",_name);
}
-(void)showMovie
{
NSLog(@"正在用%@看电影!",_name);
}
-(void)playGames
{
NSLog(@"正在用%@打游戏!",_name);
}
@end
@implementation Person
-(void)setName:(NSString *)name
{
_name=name;
}
-(void)setIPad:(IPad *)ipad
{
_ipad=ipad;
}
-(void)listenMusic:(IPad *)ipad//在listenMusic方法内部我只写了一个showMusic方法,剩下的读者可以自行添加。
{
[ipad showMusic];
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p=[Person new];
IPad *i=[IPad new];
[i setName:@"ipad123"];
[p setName:@"wangzhongyao"];
[p setIPad:i];
[p listenMusic:i];
}
return 0;
}
这一部分也是很重要的,和依赖关系差不多,经常用到,记住里面类之间是怎么调用的。其实仔细看看就会发现,每个类只管自己的事情,需要什么就去拿什么,一个类需要另一个类就要加上所需的头文件,设置形参啊什么的也都一样,需要就设。慢慢理解,慢慢熟悉整个过程。还有一点,赋值一定要用set方法,记住记住!可能一开始不适应,长时间就好了!上面几个程序没有get方法,因为我们没有用到。
———————————————————————————————————————————
方法重载
★OC里面没有方法重载!
★在OC中方法名是不允许相同的!(与java不一样)
-(void)run:(int)a;
-(void)run:(float)a; //Duplicate declaration of method 'run:' 显然无法同名
注意:
① -(void)run:(int)num1; //方法名是 run:
② -(void)run:(int)num1 and:(float)num2; //方法名是 run: and:
③ -(void)run:(int)num1 : (int)num2 : (int)num3; //方法名是 run: : :
以上三个方法是可以同时存在的,因为方法名不同,尤其要注意第三个。
———————————————————————————————————————————
static关键字的使用
这一部分的知识不是很系统,大家在用到这方面的时候试一试就可以明确了。如果没错误说明可以使用,有错误自然无法使用,希望大家灵活学习。
#import <Foundation/Foundation.h>
static int num2=20;//定义全局变量也是可以的
@interface Dog : NSObject
{
// static int _speed; 这是错误的
//实例变量不能声明为静态
//在C语言中
//没有初始化的静态变量存在BSS段
//如果已经初始化了,存在数据区
}
-(void)run;
@end
@implementation Dog
-(void)run
{
static int num1=10;//定义静态局部变量,是可以的
NSLog(@"num=%d",num1);
num1++;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Dog *dog=[Dog new];
[dog run];
[dog run];
[dog run];
[dog run];//在run方法中num是静态的局部变量,所以每执行一次run方法,num++,num的值会改变。如果不定义成静态的,那么上面多次调用run方法,num值也是不会改变的
NSLog(@"num2=%d",num2);
}
return 0;
}
★总结一下:
①static不能修饰类的方法
②static不能修饰类的实例变量
③static可以修饰全局变量,但是只能在本文件中使用
④static可以修饰局部变量,在方法中可以保存方法上一次的运行结果(局部变量的生命周期延长)
———————————————————————————————————————————
版权声明:本文为博主原创文章,未经博主允许不得转载。