52个有效方法(18) - 尽量使用不可变对象
2018-09-04 本文已影响9人
SkyMing一C
-
设计类的时候,应充分运用属性来封装数据。
-
在使用属性时,则可将其声明为“只读”。
-
默认情况下,属性是“既可读又可写的”,这样设计出来的类都是“可变的”(mutable)。
-
不过一般情况下,我们要建模的数据未必需要改变。所以,一般情况下,对外公开的接口一般声明为readOnly。
-
可以在类内部实现重新声明为readwrite,这样可以在类内部修改参数。这样,就只能在类的实现代码内部设置这些属性了。
#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;
- (id)initWithFirstName:(NSString*)firstName
andLastName:(NSString*)lastName;
- (void)addFriend:(EOCPerson*)person;
- (void)removeFriend:(EOCPerson*)person;
@end
// EOCPerson.m
#import "EOCPerson.h"
@interface EOCPerson ()
@property (nonatomic, copy, readwrite) NSString *firstName;
@property (nonatomic, copy, readwrite) NSString *lastName;
@end
@implementation EOCPerson {
NSMutableSet *_internalFriends
}
- (NSSet*)friends {
return [_internalFriends copy];
}
- (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])) {
_firstName = firstName;
_lastName = lastName;
_internalFriends = [NSMutableSet new];
}
return self;
}
@end
-
对于设置了readonly修饰词的属性,依然可以通过“键值编码”(Key-Value Coding,KVC)技术设置这些属性值,使用
setValue:forKey:
方法来修改。 -
或者通过类别信息查询功能查出对应的实例变量在内存中的偏移量来修改对应的实例变量的值。
-
上面额外的加入了绕过公共API来设置属性的两种方式。但这是一种破坏,可能出现问题。所以建议,还是尽量编写不可变的对象。
要点
-
尽量创建不可变的对象。
-
若某属性仅可于对象内部修改,则在“class-continuation分类”中将其readonly属性扩展为readwrite属性。
-
不要把不可变的collection作为属性公开,而应提供相关方法,以此修改对象中的可变collection。