第18条:尽量使用不可变对象

1、设计类的时候,应充分运用属性来封装数据。

2应该尽量把对外公布出来的属性设为只读,而且只在确有必要时才将属性对外公布。

3若属性仅可于对象内部修改,则在“class-continuation分类”中将其由readonly属性扩展为readwrite属性。

这种做法下,如果该属性是nonatomic,那么可能会产生“竞争条件”(race condition, 竞态条件)。在对象内部写入属性时,对象外的观察者也许正读取该属性。若想避免此问题,可以在必要时通过“派发队列”(dispatch queue,参见第41条)等手段,将(包括对象内部的)所有数据存取操作都设为同步操作。

a)现在,只能于实现代码内部设置这些属性了。其实更准确地说,在对象外部,仍然能通过“键值编码”(Key-Value Coding, KVC)技术设置这些属性值。这样做等于违规地绕过了本类所提供的API。

b)还可以使用类型信息查询功能查出属性属性所对应的实例变量在内存布局中的偏移量,以此来人为设置这个实例变量的值。这样做绕过本类的公共API还要不合规范。

上面额外的加入了绕过公共API来设置属性的两种方式。
但这是一种破坏,可能出现问题。所以建议,还是尽量编写不可变的对象。

4不要把可变的collection作为属性公开,而就提供相关的方法,以此修改对象中的可变collection。

例:
.h
Person 类中
有一个属性
@property(nonatomic, strong, readonly)NSSet *friends;
两个方法
- addFriend
- removeFriend

.m
变量
NSMutableSet *_internalFriends;
- (NSSet*)friends {
  return [_internalFriends copy];
}

- addFriend {
  _internalFriends
}

- removeFriend {
  _internalFriends
}

也可以直接用NSMutableSet来实现friends属性,令该类不借助addFriend: removeFriedn: 方法而直接操作此属性。
但是,这种过分解耦(decouple)数据的做法很容易出bug。比方说,在添加或删除朋友时,Person对象可能还要执行其他相关操作,若是采用这种做法,那就等于直接从底层修改了其内部用于存放朋友对象的set。在Person对象不知情时,直接从底层修改set可能会令对象内的各数据之间互不一致。

所以建议:不要在返回的对象上查询类型以确定其是否可变。
例:
  NSSet *friends = person.friends;
  if ([friends isKindOfClass:[NSMutableSet class]]) {
    NSMutableSet *mutableFriends = (NSMutableSet*)firends;
    // .....
  }
应该竭力避免这种做法。不要假设friends所用的那个NSSet一定是可变的。
5这依然说明:不宜从底层直接修改对象中的数据。

时间: 2024-11-05 07:31:06

第18条:尽量使用不可变对象的相关文章

第18条:尽量使用不可变对象

本条要点:(作者总结) 设计类的时候,应充分运用属性来封装数据.而在使用属性是,则可将其声明为 "只读"(read-only).默认情况下,属性是 "即可读又可写的"(read-write),这样设计出来的类都是"可变的"(mutable).不过,一般情况下我们要建模的数据未必需要改变.比方说,某数据所表示的对象源自一项只读的网络服务(web service),里面可能包含一系列需要显示在地图上的相关点,像这种对象就没必要改变其内容.即使修改了,

iBatis2之SqlMap配置总结(18条)

iBatis2之SqlMap配置总结(18条)   SqlMap的配置是iBatis中应用的核心.这部分任务占据了iBatis开发的70的工作量. 1.命名空间:   <sqlMap namespace="Account">,在此空间外要引用此空间的元素,则需要加上命名空间名. 2.实体的别名: <typeAlias alias="Account" type="com.lavasoft.ibatissut.simple.domain.en

Objective-C:OC内部可变对象和不可变对象的深(复制)拷贝问题思考:

OC内部:可变对象和不可变对象的深(复制)拷贝问题思考: 不可变对象: 例如NSString对象,因为NSString对象是常量字符串,所以,不可以更改其内容,但是可以修改指向该字符串的指针指向.当对NSString对象做深拷贝时,如果是copy复制方式,其实就是浅复制,只是复制了同一个对象的指针:如果是mutableCopy复制方式,系统会分配一个新的内存空间用来存放复制出来的NSMutableString对象,此时地址是新的,内容是一样的,他们正在被不同的实例变量字符串指针指着. 可变对象:

1.不要使用可变对象作为函数默认值

1 In [1]: def append_to_list(value, def_list=[]): 2 ...: def_list.append(value) 3 ...: return def_list 4 ...: 5 In [2]: my_list = append_to_list(1) 6 In [3]: my_list 7 Out[3]: [1] 8 In [4]: my_other_list = append_to_list(2) 9 In [5]: my_other_list 10

关于python的可变和不可变对象

在python中所有都是对象,在python中只有list和dict是可变对象,其他都是不可变对象. 具体参照:http://www.cnblogs.com/lovemo1314/archive/2012/07/18/2597111.html

注意不要编写返回引用可变对象的访问器方法

在看<Java核心技术(原书第9版中文版)>的时候,看到113页的一个警告,“注意不要编写返回引用可变对象的访问器方法”.以前没看到过,原来Date对象是可变对象.就可变对象这个概念,查了一下网,我认为可变对象,就是在类中可以不通过域更改器方法就能改变值的对象. 1 package com.csst.sort; 2 3 import java.util.Date; 4 import java.util.GregorianCalendar; 5 6 public class Employee {

独立开发者低成本推广APP的18条技巧

导语:知道并不等于执行,有些最基本的推广方法往往会被忽略.这些,是自国外开发者总结出的这18条经验. 现在市面上充满了大牌子大公司和大制作的手机游戏,经常有游戏花300万成本开发,然后再花2000万推广;这些游戏都梦想着上线之后就有4000万月流水疯狂吸金.但是作为独立开发者,就算没有多少推广的费用,也有很多推广的策略和方法能让你不花钱就获得效果.这些技巧和方法并不是什么奇妙高招,或多或少开发者你都会知道,但是知道并不等于执行,有些最基本的推广方法也往往会被忽略.我们将来自国外开发者总结出的这1

Python中的可变、不可变对象和赋值技巧序列解包

可变对象和不可变对象 在python中一切皆对象.在Python中不存在所谓的值传递调用,一切传递都是对象的引用,也可认为是传址. python中,对象分为可变(mutable)和不可变(immutable)两种类型,元组(tuple).数值型(number).字符串(string)均为不可变对象,而字典型(dictionary)和列表型(list)的对象是可变对象. 不可变对象 见一个例子,分析不可变对象的特点 python内置id()函数,用于返回对象的唯一标识(identity).id()

python函数默认参数为可变对象的理解

1.代码在执行的过程中,遇到函数定义,初始化函数生成存储函数名,默认参数初识值,函数地址的函数对象. 2.代码执行不在初始化函数,而是直接执行函数体. 代码实例 这要从函数的特性说起,在 Python 中,函数是第一类对象(function is the first class object),换而言之,函数也是对象,跟整数.字符串一样可以赋值给变量.当做参数传递.还可以作为返回值.函数也有自己的属性,比如函数的名字.函数的默认参数列表. # 函数的名字 >>> func.__name_