我經常需要爲對象設計這兩種策略之間做出選擇:OOP初始化策略
- 一個對象,它是完全初始化,準備其施工後使用。構造函數通常需要複雜的參數列表,因此對象初始化並不重要。所有將它作爲成員變量的對象也需要不平凡的構造函數。這可能會導致代碼的複雜性集中在對象構造函數上,通常會使代碼難以遵循。
- 具有默認構造函數的對象。對象變量通過
setter methods
單獨設置。這種方法的缺點是大多數方法需要檢查對象是否完全初始化,從而使代碼複雜化。
您在兩者之間有什麼個人喜好,以及您如何決定何時使用其中一種?
我經常需要爲對象設計這兩種策略之間做出選擇:OOP初始化策略
setter methods
單獨設置。這種方法的缺點是大多數方法需要檢查對象是否完全初始化,從而使代碼複雜化。您在兩者之間有什麼個人喜好,以及您如何決定何時使用其中一種?
在我看來,如果一個構造函數變得太臃腫,那麼就應該將對象分割爲更多不同的小對象。這在一些罕見的情況下可能是不可能的,但在大多數情況下可以完成。
初始化構造函數中的所有變量總是很好,但是初始化爲默認值。如果很難獲取變量的值(例如,您必須調用某個函數來獲取該值),則可以將該值設置爲無效值,然後再設置正確的值。
這不是一個好主意,使構造函數如此複雜,因爲你不能在構造函數中返回一個錯誤(我不知道是否可以在構造函數中拋出一個異常,因爲我特別是不喜歡在任何地方展示異常)。另外,你不能在那裏調用虛函數,等等。
當類的構造很複雜時,我喜歡創建一個「init」函數。然後我可以這樣做:
Person::Person()
{
age = -1;
...
}
int Person::Init()
{
age = functionThatReturnsTheAgeFromSomeDB();
if (age == -1)
{
return DB_ERROR;
}
...
}
依此類推。
如果一個構造函數採用—你調用這個不平凡的對象初始化—很多爭論,你不希望你的類分割成小的,再一個辦法是把參數爲Parameter Object,然後只傳該對象給構造函數。
其次,我認爲你應該分清,如果對象是應該做的工作是絕對必須設置
之間......
可由用戶選擇性地設置或覆蓋的對象屬性。雖然您可能會在構造函數中初始化這些屬性,但您不必爲它們設置單獨的構造函數參數。相反,您可以爲它們指定一個合理的默認值,這些默認值仍然可以由用戶通過setter方法覆蓋。
還有第一類型性質的(那些必須絕對具有用戶提供的值)的替代:性質,這是通過在一個派生類中重寫一個抽象吸氣劑提供:
abstract class ComplicatedFoo {
protected abstract T getSomeDependency(); // replaces required ctor parameter
}
PS:書"Dependency Injection" by Dhanji R. Prasanna (Manning Publications)給出瞭如何初始化一個對象的各種方法的很好的概述。
也沒有。 巨大的參數列表指示對象確實太多。在對象具有有效且有用的輸出之前需要設置的許多屬性表明它確實太多了。 因此,就我而言,這兩種方法都不是解決方案。
有很多方法可以打破這些問題,但在特定情況之外,唯一的規則是「它需要做」。
聚合到其他對象,「控制器」類,各種傳播者模式。是一些類別的第一類對象,可以隱藏在實現中。
我不接受您提出的兩個選項是唯一的選項,除了從實際的角度出發,讓代碼出門外。哪一個我然後被迫選擇,將取決於多少個調用構造函數的代碼所需的不同參數,與需要多少驗證才能確認所有屬性的設置,以及可能對單元測試的影響有關因爲對象是一團糟會很笨重或有限。
-1用於將ctor分成兩部分(ctor本身和'Init')。恕我直言,這違背了一個構造函數的意思:將對象置於有效狀態。當然,ctor不應該做太多的工作,所以如果你不容易確定一個「age」的值,那麼將一個「functor」對象傳遞給ctor,以後調用時會產生「age」 。也許甚至完全去掉「年齡」而選擇這種方法。但是*不要*引入另一個強制性的'Init'方法,它實際上只是ctor的延續。 (並且使用異常而不是「魔術」返回值。) – stakx 2012-10-13 10:15:23
(用例如傳遞給對象ctor的工廠方法替換'functionThatReturnsTheAgeFromSomeDB'的另外一個好處是你可以去除某些數據庫的隱藏依賴,從而使你的類設計更透明,更易於測試。) – stakx 2012-10-13 10:19:17
許多安全關鍵編碼標準(如JSF ++和Misra)避免使用異常。無論如何,如果你不喜歡使用「初始化」函數,爲什麼你建議使用異常?他會在構造函數中使用什麼異常? Consructors不能拋棄異常,所以這是另一個有「init」功能的原因 – 2012-10-14 22:51:19