第18条:尽量使用不可变对象
- 尽量把对外公布出来的属性设为只读,而且只在确有必要时才将属性对外公布。
- 对象中表示各种collection的那些属性,通常情况下,提供一个readonly属性供外界使用,该属性将返回一个不可变的collection,而此collection则是内部那个可变collection的一份拷贝。
- 强调:不要在返回的对象上查询类型以确定是否可变。
例子
EOCPerson类
/* EOCPerson头文件 */
#import <Foundation/Foundation.h>
@interface EOCPerson : NSObject
@property(nonatomic ,copy, readonly) NSString *firstName;
@property(nonatomic ,copy, readonly) NSString *lastName;
@property(nonatomic ,strong, readonly) NSSet *friends; // 不可变set
- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName;
- (void)addFriend:(EOCPerson *)person;
- (void)removeFriend:(EOCPerson *)person;
@end
#import "EOCPerson.h"
@interface EOCPerson ()
// 改为readwrite属性
@property(nonatomic ,copy, readwrite) NSString *firstName;
@property(nonatomic ,copy, readwrite) NSString *lastName;
@end
/* EOCPerson实现文件 */
@implementation EOCPerson
{// 实例变量
NSMutableSet *_internalFriends; // 可变set
}
- (NSSet *)friends{
return [_internalFriends copy]; // 拷贝一份不可变的set
}
- (void)addFriend:(EOCPerson *)person{
[_internalFriends addObject:person];
}
- (void)removeFriend:(EOCPerson *)person{
[_internalFriends removeObject:person];
}
- (id)initWithFirstName:(NSString *)firstName andLastName:(NSString *)lastName{
if (self = [super init]) {
#warning 不需要再copy一份
_firstName = firstName;
_lastName = lastName;
_internalFriends = [NSMutableSet new]; // 延迟初始化
}
return self;
}
// 覆写description方法
- (NSString *)description{
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
@end
main函数
#import <Foundation/Foundation.h>
#import "EOCPerson.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 1.创建3个EOCPerson对象
EOCPerson *person = [[EOCPerson alloc] initWithFirstName:@"Bob" andLastName:@"Simth"];
NSLog(@"person = %@ %@", person.firstName, person.lastName);
EOCPerson *person2 = [[EOCPerson alloc] initWithFirstName:@"Bill" andLastName:@"Jobs"];
NSLog(@"person2 = %@ %@", person2.firstName, person2.lastName);
EOCPerson *person3 = [[EOCPerson alloc] initWithFirstName:@"Jane" andLastName:@"Galloway"];
NSLog(@"person3 = %@ %@", person3.firstName, person3.lastName);
// 2.通过addFriend:方法给person添加2个朋友(person2&person3)
[person addFriend:person2];
[person addFriend:person3];
NSLog(@"the friends of person = %@", person.friends);
}
return 0;
}
输出结果:
要点
- 尽量创建不可变的对象。
- 若某属性仅可于对象内部修改,则在“class-continue分类”中将其由readonly属性扩展为readwrite属性。
- 不要把可变的collection作为属性公开,而应提供相关方法,以此修改对象中的可变collection。