Flag 參數
2011 年 6 月 23 日
Flag 參數是一種函式參數,會告知函式根據其值執行不同的操作。想像一下我們想要預訂一場音樂會。有兩種預訂方式:一般和高級。若要在此處使用 Flag 參數,我們會得到類似以下內容的方法宣告
//pseudo-code class Concert... public Booking book (Customer aCustomer, boolean isPremium) {...}
我對 Flag 參數的普遍反應是避免使用它們。我比較喜歡定義不同的方法,而不是使用 Flag 參數。
class Concert... public Booking regularBook(Customer aCustomer) {...} public Booking premiumBook(Customer aCustomer) {...}
我這麼做的理由是,當我呼叫時,不同的方法會更清楚地傳達我的意圖。當我看到 book(martin, false)
時,我不必記住 Flag 變數的意義,我可以輕鬆地讀取 regularBook(martin)
。
糾結的實作
我普遍不喜歡 Flag 參數確實有一些細微差別和後果,第一個後果是該如何處理糾結的實作。
在最簡單的情況下,對 Flag 的反應實際上是呼叫不同的方法。
public Booking book (Customer aCustomer, boolean isPremium) { if(isPremium) // logic for premium book else // logic for regular booking }
但有時候邏輯會更糾結
public Booking book (Customer aCustomer, boolean isPremium) { lorem().ipsum(); dolor(); if(isPremium) sitAmet(); consectetur(); if(isPremium) adipiscing().elit(); else { aenean(); vitaeTortor().mauris(); } eu.adipiscing();
在這種情況下,嘗試將一般和高級預訂方法萃取到不同的方法中可能會很混亂,而且這兩個方法之間會出現大量的重複。在這種情況下,一個選項是保留具有 Flag 參數的方法,但將其隱藏起來。
class Order... public Booking regularBook(Customer aCustomer) { return hiddenBookImpl(aCustomer, false); } public Booking premiumBook(Customer aCustomer) { return hiddenBookImpl(aCustomer, true); } private Booking hiddenBookImpl(Customer aCustomer, boolean isPremium) {...}
重點在於,只有一般和高級預訂方法應該呼叫 hiddenBookImpl
。我喜歡使用醜陋的名稱來傳達這一點,而且這樣做的好處是,如果你必須這麼做,你可以輕鬆地新增一個正規表示式探測,以確保沒有其他人呼叫它。
衍生 Flag
如果是否使用高級預訂流程的決定取決於客戶的狀態,該怎麼辦?我們假設菁英客戶獲得高級預訂,而一般客戶獲得一般待遇。在這種情況下,我們當然不應該使用布林 Flag,但客戶物件本身是否充當 Flag?
我會將此視為捕捉呼叫者的意圖。如果預訂方式僅取決於客戶狀態,則呼叫者無需在意高級預訂和一般預訂之間的差異 - 因此,預訂常式根據客戶狀態推導其真實方法是完全合理的。只有在呼叫者需要指定她想要哪一個方法時,您才需要不同的方法。
布林設定方法
與此相關的是布林設定方法的命名方式。在此我同意 Kent 的建議 - 我寧願看到
void setOn(); void setOff();
而不是看到
void setSwitch(boolean on);
但再次同意 Kent,這取決於方法的使用方式。如果您從布林來源(例如 UI 控制項或資料來源)擷取資料,我寧可使用 setSwitch(aValue)
而不是
if (aValue) setOn(); else setOff();
這是一個 API 應撰寫為讓呼叫者更輕鬆的範例,因此如果我們知道呼叫者的來源,我們應在考量此資訊的情況下設計 API。這也表示如果我們以兩種方式取得呼叫者,我們有時可能會提供兩種樣式。
相同的邏輯適用於 book
。如果螢幕上有核取方塊,而我們只是將其值傳遞給 book
,則標記引數有一些道理。在此範例中,我不會說這是一個簡單的選擇 - 我會爭論,大多時候 book
的標記引數比簡單的布林設定器難懂多了,因此值得使用明確的方法。