web用框架做网站步骤/网络营销的渠道有哪些
重构数据-Self Encapsulate Field自封装值域一
1.自封装值域
1.1.什么是自封装值域
我们在访问类中的属性时有两种方式直接访问和间接访问。
直接访问:直接访问类中的属性
间接访问:通过get和set方法封装属性,然后通过调用该方法来访问属性,这就是自封装值域
1.1.使用场景
直接访问变量的好处则是:代码比较容易阅读。
间接访问变量的好处是,子类可以通过覆写一个函数而改变获取数据的途径;它还支持更灵活的数据管理方式,例如延迟初始化(意思是:只有在需要用到某值时,才对它初始化)
如何选择
面临选择时,我总是做两手准备。
通常情况下我会很乐意按照团队中其他人的意愿来做。就我自己而言,我比较喜欢先使用直接访问方式,直到这种方式给我带来麻烦为止,此时我就会转而使用间接访问方式。重构给了我改变主意的自由。
如果你想访问超类中的一个字段,却又想在子类中将对这个变量的访问改为一个计算后的值,这就是最该使用Self Encapsulate Field (171)的时候。“字段自我封装”只是第一步。完成自我封装之后,你可以在子类中根据自己的需要随意覆写取值/设值函数。
1.2.如何做
- 为待封装字段建立取值/设值函数。
- 找出该字段的所有引用点,将它们全部改为调用取值/设值函数。
- 如果引用点要读取字段值,就将它替换为调用取值函数;如果引用点要给字段赋值,就将它替换为调用设值函数。
- 你可以暂时将该字段改名,让编译器帮助你查找引用点。
- 将该字段声明为private。
- 复查,确保找出所有引用点。
- 编译,测试。
1.3.示例
class IntRange {// 定义属性private int _low, _high;// 下面都是直接使用属性的方法boolean includes (int arg) {return arg >= _low && arg <= _high;}void grow(int factor) {_high = _high * factor;}IntRange (int low, int high) {_low = low;_high = high;}
为了封装_low和_high这两个值域,我先定义「取值/设值函数」(如果此前没有定义的话),并使用它们
class IntRange {boolean includes (int arg) {return arg >= getLow() && arg <= getHigh();}void grow(int factor) {setHigh (getHigh() * factor);}// 定义属性private int _low, _high;// 定义属性对应的get和set方法int getLow() {return _low;}int getHigh() {return _high;}void setLow(int arg) {_low = arg;}void setHigh(int arg) {_high = arg;}
使用本项重构时,你必须小心对待在构造函数中使用设值函数
的情况。
一般说来,设值函数被认为应该在对象创建后
才使用,所以初始化过程中的行为
有可能与设值函数的行为
不同。在这种情况下,我也许在构造函数中直接访问值域,要不就是建立另一个独立的初始化函数
// 在构造器中调用初始化方法,初始化属性值
IntRange (int low, int high) {initialize (low, high);
}
// 创建一个独立的初始化方法,对属性值初始化
private void initialize (int low, int high) {_low = low;_high = high;
}
一旦你拥有一个subclass,上述所有动作的价值就体现出来了。如下所示
// 创建子类继承IntRangeclass CappedRange extends IntRange {CappedRange (int low, int high, int cap) {// 调用父类构造器初始化属性super (low, high);_cap = cap;}private int _cap;int getCap() {return _cap;}int getHigh() {// 在子类中调用父类方法能够操作属性return Math.min(super.getHigh(), getCap());}}
现在,我可以在CappedRange class中覆写getHigh(),从而加入对cap的考虑,而不必修改IntRange class的任何行为。