1. 程式人生 > >重構改善既有代碼設計--重構手法18:Self Encapsulate Field (自封裝字段)

重構改善既有代碼設計--重構手法18:Self Encapsulate Field (自封裝字段)

擁有 bsp range 設值 測試 void end sub tcap

你直接訪問一個值域(field),但與值域之間的耦合關系逐漸變得笨拙。

為這個值域建立取值/設值函數(getting/setting methods),並且只以這些函數來訪問值域。

private int _low, _high;
boolean includes(int arg) {
return arg >= _low && arg <= _high;
}

==〉

private int _low, _high;
boolean includes(int arg) {
return arg >= getLow() && arg <= getHigh();

}
int getLow() {return _low;}
int getHigh() {return _high;}

動機

如果你想訪問superclass中的一個值域,卻又想在subclass中將[對這個變量的訪問]改為一個計算後的值,這就是最該使用Self Encapsulate Field(171)的時候。[值域自我封裝]只是第一步。完成自我封裝之後,你可以在subclass中根據自己的需要隨意覆寫取值/設值函數(getting/setting methods)。

作法

1. 為[待封裝值域]建立取值/設值函數(getting/setting methods)。

2. 找出該值域的所有引用點,將它們全部替換為[對於取值/設值函數的調用]。

如果引用點是[讀值]值域值,就將它替換為[調用取值函數];如果引用點是[設定]值域值,就將它替換為[調用設值函數]。

你可以暫時為設值域改名,讓編譯器幫助你查找引用點。

3. 將該值域聲明為private。

4. 復查,確保找出所有引用點。

5. 編譯,測試。


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 {
private int _low, _high;

boolean includes(int arg) {
return arg >= _low && arg <= _high;
}

void grow(int factor) {
SetHigh(getHigh()*factor);
}

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,上述所有動作的價值就體現出來了。如下所示:

class 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的任何行為。

重構改善既有代碼設計--重構手法18:Self Encapsulate Field (自封裝字段)