类的设计
面向对象的基本概念
对象:在现实世界中对象是我们认识世界的基本单元,在面向对象程序设计中对象是接收消息的单元;每个对象都是独一无二的;对象都有属性和行为;对象都属于某个类。
类:类是对一组具有共同属性和行为的对象的抽象,它是创建对象的蓝图和模板。
消息:对象与对象之间存在着一定的联系,这种联系通过消息的传递来实现。面向对象世界中的所有操作都是通过向对象发送消息来实现,对象接收到消息后,会执行对应的行为。
面向对象的三大支柱
封装:把一个事物包装起来,使外界不了解它的内部的具体情况。在面向对象的程序设计中,封装就是把相关的数据和代码结合成一个有机的整体,形成数据和操作代码的封装体,对外只提供一个可以控制的接口,内部大部分的实现细节对外隐蔽,达到对数据访问权的合理控制。封装使程序中各部分之间的相互联系达到最小,提高了程序的安全性,简化了程序代码的编写工作。
继承:从已有的类创建新类的过程,提供继承信息的称为父类,得到继承信息的称为子类,子类和父类之间是IS-A关系,继承使得类与类之间形成一个层次结构。与此同时,继承也让变化中的系统具有了稳定性和延续性。
多态:不同结构的对象可以以各自不同的方式响应同一个消息,或者说同一个消息可以根据发送消息的对象的不同而采用多种不同的操作行为,这是面向对象最精髓的部分。
定义和使用类
定义类的过程是一个抽象的过程,需要进行数据抽象和行为抽象,数据抽象是找到和对象相关的属性,行为抽象是找到和对象相关的方法。要完成数据抽象和行为抽象,通常可以从对问题的描述中找名词和动词,名词会成为类或者类中的属性,动词会成为类中的方法。
类的声明部分(.h文件)
#import <Foundation/Foundation.h>
@interface CDStudent : NSObject {
@private
NSString *_name;
NSUInteger _age;
}
- (instancetype) initWithName: (NSString *) name
age: (NSUInteger) age;
- (NSString *) name;
- (void) play: (NSString *) game;
- (BOOL) study: (NSString *) course
forHours: (NSUInteger) hours;
@end
类的实现部分(.m文件)
#import "CDStudent.h"
const static int MIN_STUDY_HOURS = 120;
@implementation CDStudent
- (instancetype) initWithName: (NSString *) name
age: (NSUInteger) age {
if (self = [super init]) {
_name = name;
_age = age;
}
return self;
}
- (NSString *) name {
return _name;
}
- (void) play: (NSString *) game {
NSLog(@"%@ is playing %@.", _name, game);
}
- (BOOL) study: (NSString *) course
forHours: (NSUInteger) hours {
NSLog(@"%@ is studying %@.", _name, course);
return hours >= MIN_STUDY_HOURS;
}
@end
初始化方法
上面类的定义中,以init打头的方法称为初始化方法,初始化方法在创建对象时调用以完成对对象的初始化(给对象的属性赋初始值)
创建对象
CDStudent *stu = [[CDStudent alloc] initWithName:@"Alice" age:18];
给对象发消息
#import <Foundation/Foundation.h>
#import "CDStudent.h"
int main(int argc, char *argv[]) {
@autoreleasepool {
CDStudent *stu = [[CDStudent alloc] initWithName:@"Alice" age:18];
[stu play:@"LoL"];
BOOL hasFinished = [stu study:@"Objective-C" forHours:64];
NSLog(@"%@ %@ mastered Objective-C.", [stu name], hasFinished ? @"has" : @"hasn't");
}
return 0;
}
使用访问修饰符
定义类时,可以给类中的属性添加访问修饰符,包括:
- @private:私有,对外界来说是不可见的(不可访问)。
- @protected:受保护,对子类公开对其他类相当于私有。
- @public:公开,对外界来说是可见的(可以访问)。
实例方法和类方法
定义类时,可以在方法的返回类型前添加-或+分别表示方法是实例方法或类方法。所谓实例方法就是对象的方法,即发给对象的消息,因此要创建对象才能调用;而类方法是类的方法,即发给类的消息,可以直接通过类名进行调用,不需要创建该类的对象。我们可以再添加一个类方法来创建学生对象,具体的代码如下所示。
+ (instancetype) studentWithName: (NSString *) name
age: (NSUInteger) age;
+ (instancetype) studentWithName: (NSString *) name
age: (NSUInteger) age {
// 类方法中的self代表CDStudent类
return [[self alloc] initWithName:name age:age];
}
// 直接给类发消息来创建和初始化学生对象
CDStudent *stu = [CDStudent studentWitWithName:@"Alice" age:18];
那么问题来了,哪些方法应该设计成实例方法,哪些方法应该设计成类方法呢?通常来说,一个方法与对象状态无关只跟类有关就要设计成类方法,反之就要设计成实例方法。