面向物件程式設計/"狀態"是邪惡的!
外觀
< 面向物件程式設計
我們沒有足夠強調的一點是:狀態(與變化相反)是邪惡的!或者,(也許說更準確)維護不必要的狀態是所有(呃……許多)錯誤的根源。讓我們看一個例子,現在在 Ruby 中
我們正在顯示一個隨時間推移的東西,所以我們正在處理畫素和秒。根據縮放級別,它們之間存在關聯:每秒畫素數,或 PPS。
class Timeline
{
PPS;
current_position_in_seconds;
current_position_in_pixels;
public:
GetPosInSeconds() {current_position_in_seconds;}
SetPosInSeconds(s) {current_position_in_seconds = s;} # oops, we're out of sync
GetPosInPixels() {current_position_in_pixels;}
SetPosInPixels(p) {current_position_in_pixels = p;} # oops, we're out of sync
}
在這個例子中,我們正在維護不必要的 state - 也就是說,我們正在用秒和畫素來儲存位置。這很方便,對於這個類的使用者來說也很重要,但我們在這裡搞砸了封裝。無論何時你設定一個單位的值,你都會破壞另一個單位的正確性。好吧,你說,這裡有一個簡單的解決方法
class Timeline
{
PPS;
current_position_in_seconds;
current_position_in_pixels;
public:
GetPosInSeconds() {current_position_in_seconds;}
SetPosInSeconds(s)
{
current_position_in_seconds = s;
current_position_in_pixels = s*PPS;
}
GetPosInPixels() {current_position_in_pixels;}
SetPosInPixels(p)
{
current_position_in_pixels = p;
current_position_in_seconds = p/PPS;
}
}
這修復了上一個例子的明顯錯誤,但你給自己帶來了很多工作。現在你必須在 Timeline 類中的每個方法中保留每個計算,以保持一致性。可能會有數十個地方會出現這種情況(相信我)。那麼當你新增其他單位時,比如英寸怎麼辦?你必須再次重複所有這些。可以推測,你已經看到了事情的發展方向:計算屬性、邏輯屬性、虛擬屬性,無論你喜歡叫它們什麼。讓我們再看一遍這個例子
class Timeline
{
PPS; # Pixels Per Second
IPS; # Inches Per Second
current_position_in_seconds;
public:
GetPosInSeconds() {current_position_in_seconds;}
SetPosInSeconds(s) {current_position_in_seconds = s;}
GetPosInPixels() {current_position_in_seconds*PPS;}
SetPosInPixels(p) {current_position_in_seconds = p/PPS; }
GetPosInInches() {current_position_in_seconds*IPS;}
SetPosInInches(i) {current_position_in_seconds = i/IPS; }
}
現在,我們假設 PPS 和 IPS 的轉換因子設定正確,為了簡化問題,否則我們已經大大簡化了問題。現在我們在其他二十個函式中編寫,我們只需要關心秒,沒有一致性問題要擔心。此外,如果我們需要將基本單位從秒更改為畫素,Timeline 使用者永遠不會知道。