2015-05-11 120 views
0

我想創建用最少的代碼重複的有效類。鏈接重載構造

我已經此定義:

Public Class Foo 
    Private _firstName as string = "" 
    Private _lastName as string = "" 

    Public Sub New(ByVal userGUID As Guid) 
     'query DB to get firstName and lastName 
     Me.New(dt.Rows(0)("FirstName").ToString(),dt.Rows(0)("LastName").ToString()) 
    End Sub 

    Public Sub New(ByVal firstName As String, ByVal lastName As String) 
     _firstName = firstName.toUpper() 
     _lastName = lastName.toUpper() 
     Validate() 
    End Sub 

    Private Sub Validate() 
     ' Throw error if something is wrong 
    End Sub 
End Class 

的構造與firstName和lastName參數是終點的構造,做驗證。將userGUID作爲參數的構造函數將查詢DB以獲取名稱並調用最終的構造函數。通過這種方式,所有的執行都應該指向實際執行所有驗證等的構造函數之一。其背後的想法是,如果我添加新的構造函數,我只需要提取必要的數據(名字/姓氏)並調用最終的構造函數即可做驗證。

然而,有一個編譯錯誤阻止我使用在線Me.New(dt.Rows(0)("FirstName").ToString(),dt.Rows(0)("LastName").ToString())這個系統。顯然這條線必須是構造函數中的第一行。但是,如果我將此作爲第一行,它將打破驗證過程,因爲驗證將因沒有名/姓而引發錯誤。我必須查詢數據庫才能獲取該信息。

我知道我可以在這裏指定的值,並從這個構造函數調用過驗證,但是這將有效地從最終一個隔離此構造,從而複製代碼,並增加維護了一下。僅供參考,在下面的例子中,我只有2個構造函數,但實際上我還有幾個構造函數。如果每個人都能完成自己的任務,那麼只需要多加維護。

那麼,有沒有辦法實現通過執行一些代碼,然後調用一個重載的構造我的任務是什麼?

謝謝你的任何見解

更新1:

每the_lotus評論,我包括DT定義。這個問題有一個解決方法。基本上我會從最終的構造函數中進行驗證和賦值,並將其放入函數中。所有的構造函數都會調用這個函數,從而消除鏈構造函數的需要。它看起來不錯,但我想明白爲什麼要鏈構造函數,我必須將構造函數調用放在第一行。

這裏是新代碼:

公共類Foo 私人_FirstName作爲字符串= 「」 私人_lastName作爲字符串= 「」

Public Sub New(ByVal userGUID As Guid) 
    Dim dt As New DataTable 
    ' query DB to get firstName and lastName 
    ' Assume I populate dt with at least one DataRow 
    AssignAndValidate(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString()) 
    'Me.New(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString()) 
End Sub 

Public Sub New(ByVal firstName As String, ByVal lastName As String) 
    AssignAndValidate(firstName, lastName) 
End Sub 

Private Sub Validate() 
    ' Throw error if something is wrong 
End Sub 

Private Sub AssignAndValidate(ByVal firstName As String, ByVal lastName As String) 
    _firstName = firstName.ToUpper() 
    _lastName = lastName.ToUpper() 
    Validate() 
End Sub 

末級

一個好奇更不用說:在線代碼轉換器(vb.net到C#)沒有問題轉換鏈接的構造函數調用不在第一行。 C#代碼返回爲this.#ctor(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString());但是,如果我嘗試轉換回VB.NET,它將失敗。

+0

你沒有顯示dt從哪裏來。你可以有私有的Initialize方法或者有一個共享的工廠方法。 –

+0

dt在這裏不是問題。這就是爲什麼我包含'查詢數據庫獲取名字和姓氏'代碼...我試圖保持代碼簡短。假設我將dt定義爲DataTable並查詢數據庫以獲取值。還假設我至少得到一行數據和值。問題出在Me.New上,編譯器想把它放在構造函數的第一行。我將用dt更新我的答案定義 – George

+0

是的,您需要有構造函數重載調用遵循您的構造函數聲明 - 這是規則。然後,從那裏設計你的物體,而不是其他方式。 –

回答

3

你要找一個工廠方法

Public Class Foo 

    Public Shared Function GetFooFromGuid(ByVal userGUID As Guid) As Foo 

     ' Query db 

     return New Foo(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString()) 
    End Function 

End Class 

或初始化函數

Public Class Foo 

    Public Sub New(ByVal userGUID As Guid) 
     ' query DB to get firstName and lastName 
     Initialize(dt.Rows(0)("FirstName").ToString(), dt.Rows(0)("LastName").ToString()) 
    End Sub 

    Public Sub New(ByVal firstName As String, ByVal lastName As String) 
     Initialize(firstName, lastName) 
    End Sub 

    Private Sub Initialize(ByVal firstName As String, ByVal lastName As String) 
    End Sub 

End Class 

就個人而言,我不會把數據庫裏面一個新的。

+1

'就我個人而言,我不會在新的裏面調用數據庫。過於「忙碌」或者雄心勃勃 – Plutonix

+0

我試圖讓邏輯變得簡單...有人訪問我的課程只需要用必要的參數實例化它。錯誤的機會較少,因爲某人不需要實例化,賦值,調用驗證等等。從OOP的角度來看,強迫你的類的用戶完全按照你想要的去做是有道理的 - 用適當的參數實例化,總是驗證,一定要確保該類使用適當的值進行實例化。運行時錯誤的機會減少,因爲有人實例化了我的類,但沒有分配正確的值。 – George

+0

這就是說,我對'我不會在新評論中調用數據庫'感到困惑。僅僅是因爲技術限制還是設計不好?如果是這樣,爲什麼?實質上,解決方案是將DB操作從NEW移動到NEW調用的子操作。我的書中同樣的東西。這是一個糟糕的設計嗎? – George

0

我不喜歡的事實是,你在構造函數訪問數據庫,並您在構造函數中進行驗證。我將此視爲設計問題。下面有3個重載構造函數的例子。所有三個工作。你可能需要#3。使用靜態(vb - shared)方法初始化您的dt。你也可以用你的fname/lname參數替換一個包含兩個參數的參數。並且這將與#3一起工作

public class A 
{ 
    public A() : this ("xxx") 
    { 

    } 
    public A(string x) 
    { 

    } 
} 

public class A 
{ 
    public A() 
    { 

    } 
    public A(string x): this() 
    { 

    } 
} 

public class A 
{ 
    public A() : this(GetXxx()) 
    { 

    } 
    public A(string x) 
    { 

    } 

    private static string GetXxx() 
    { 
     return "xxx"; 
    } 
} 

爲什麼構造函數鏈?因爲你的對象在許多屬性中可以有默認值,並且你可能有許多構造函數,每個構造函數都添加一個屬性。在內部,一個構造函數可以設置5個屬性,其他4個構造函數只設置1個屬性。

例如:

public class Door 
{ 
    private string _material = "wood"; 
    private int _locks = 1; 
    private int _hinges = 3; 

    public Door() 
    { 

    } 
    public Door(int locks) : this() 
    { 
     _locks = locks; 
    } 
    public Door(int locks, int hinges) : this(locks) 
    { 
     _hinges = hinges; 
    } 
} 
+0

這個例子對我所遇到的場景來說不是很準確。假設你有一個新的構造函數'public Door(GUID account)',在這個構造函數中,在調用'Door(int locks,int hinges)'之前,你實際上需要查詢數據庫來獲取這些值。它不適用於VB.NET,因爲它希望在第一行代碼中看到構造函數調用。 – George

+0

@George首先,在構造函數上調用DB永遠不是一個好主意。這是你的設計問題。這是你需要理解的。但是如果你想推動你的設計,它仍然是可能的。您可以分開加載邏輯和模型。使用工廠方法「the_lotus」提供或靜態對象。我想,我的帖子告訴你,你選擇了錯誤的設計,這就是爲什麼你在簡單情況下遭受的痛苦 –