2010-03-04 61 views
14

我正在使用C#編寫一個類庫。我設計了3個主要類來幫助建模我們的數據。它們被設計成類A包含B類實例的列表,以及B類包含引用到C類的實例,即:在C#或OOP中,兩個類應該相互引用哪些是相關的?

public class Policy 
{ 
    public List <PolicyTerm> myTerms; 
    person Customer; 
    string PolicyNumber; 
} 

public class PolicyTerm 
{ 
    public Billing myBill; 
    Datetime effectivedate; 
    List <Activities> termActivities; 
    public doAction() 
    { 
      use value from Policy, like PolicyNumber; 
    } 

} 

public class Billing 
{ 
    float remainingBalance; 
    Datetime nextDueDate; 
    public void doSomething() 
    { 
     reference value from PolicyTerm, such as effective date; 
     use value from Policy, such as PolicyNumber; 
    } 
} 

我的問題是,當我嘗試使用PolicyTerm內的方法或需要來自包含類的數據的帳單。在上面的例子中,這將是「doSomething」嘗試使用PolicyTerm中的值的方法,例如向數據庫請求或保存數據的術語生效日期。

我想知道是否因爲這種情況而爲我的課程設計了正確的設計。我應該在子類中添加對「父」類的引用,以便使父數據可用?還是我需要重新考慮代碼的整體結構和設計?

我覺得類設計適用於數據建模和業務規則建模,但它確實會造成像上述情況一樣的侷限性。我喜歡將PolicyTerm和Billing分開,以便能夠獨立修改和測試代碼。另外,我覺得它讓每個部分都變得更小更簡單。

任何意見,可以提供將不勝感激。

更新:代碼塊已更新,以提供有關代碼的更多詳細信息。

+3

爲什麼你不瘦下來實際你想使用的代碼並告訴我們?這樣的事情真的取決於情況。 – ChaosPandion 2010-03-04 16:51:52

回答

6

如果doSomething()總是需要對對象的父對象的引用,那麼你應該把這個引用放到C中,你可以確保它引用到正確的B實例。 OTOH如果參考並不總是父母,但它仍然總是要引用相同的B情況下,它仍然建議把它變成的C成員。 OTOH如果doSomething()可以使用不同的引用來調用,那麼引用應該保留爲方法參數。

把孩子引用給父母或者在兩個類之間有一個相互依賴關係本身並不壞 - 這取決於上下文。這樣做的結果是,這兩個類不能被分開使用,所以實際上它們形成部件。這可能會或可能不會被你接受。

組件在一般可以由多個類的 - 與它的項目和迭代器(多個)集合實際上是一個典型的例子。但是,建議在物理層次上表示這些類之間的邏輯依賴關係,例如,通過使一個類成爲另一個類的內部類,或者在第三個類中創建兩個類內部類。

0

創建一個你所需的類的引用根本不是一個壞主意。如果需要的話,你可以讓C類的構造函數接受對類B的引用並將其存儲在一個成員變量中。

我正在研究一個項目,現在有幾個類的行爲就像這樣。

另一個可能更加「理智」的選擇是在類C上有一個事件,就像「SuchAndSuchDataRequired」。然後B類可以在獲取C的實例時監聽事件。當C需要來自B的數據時,C從類doSomething()中觸發事件,B然後返回它的事件處理函數中的數據,並且賓果類C具有數據,甚至不知道它來自類B.

+0

我喜歡事件的想法,但這可能比它需要的更復雜。再次,這完全取決於他想要做什麼。 – 2010-03-04 16:56:07

0

一般的經驗法則是保持數據儘可能接近將使用它的函數/方法/類。這樣可以保持事物的解耦,而且不必讓兩個類互相引用,這實際上使得您必須創建一個可能不必要的額外對象。

就像ChaosPandion說的:請張貼一些更具體的代碼,以便我們可以更好地幫助你。

編輯:

如果b號C和C引用B,那麼你可能要考慮把兩者結合起來作爲一個對象。如果這兩個類沒有完全不同,這種效果最好。如果沒有真正可區分的差異,那就把它放在一個班級......這可以簡化整個事情。

+0

代碼已更新以提供更多詳細信息。我同意PolicyTerm(B類)和Billing(C類)彼此密切相關,但我覺得把它們作爲單獨的類是很好的。 – Swoop 2010-03-04 19:33:24

2

這真的取決於情況。一般情況下,除非類別「B」和「C」之間有明確的關係,否則C.doSomething()將需要訪問B,因爲C是,它包含在 B之內。

然而,在B中的方法需要訪問到C是有意義的,這是由於C內B.

如此說來,有時候,這是適當的部件。不知道你的實際類別和它們代表什麼,難以說更多...

+0

問題已更新以提供更多詳細信息。我同意關於紅旗的評論。雖然我可以讓代碼工作,但我覺得有些事情是不對的。 – Swoop 2010-03-04 19:29:27

+0

@Swoop:對你來說,它似乎像計費應該是客戶的一部分,Billing.doSomething應傳遞一個PolicyTerm作爲參數... – 2010-03-04 20:03:15

1

兩個班不應該,但兩個接口是OK。

當然,接口越小越好。你會發現如果接口足夠小(它們應該是 - 參見Interface Segregation Principal),你實際上不需要2個相同的接口。

0

在我看來,你的建模看起來有點歪斜,即爲什麼在策略中有一個人類屬性,爲什麼在Policy中有一個具體實現列表,即PolicyTerm。這會將這些班級結合在一起,並且感覺不對 - 即政策有顧客嗎?應客戶有一個政策

我可以建議如下(快速建模和未經測試,但你應該能明白我在得到)

public class Customer() 
{ 
    prop name,etc,etc; 
    public List<IPolicyTerm> Policies{get;set;}//I use public getters and setters throughout but you need to choose what level of encapsulation you want 
    private Account customerAccount{get;set}   

    public Customer() 
    { 
     //ctor 
     customerAccount = doDbCall; 
     Policies = doDbCall; 
    } 

    public decimal GetCurrentPolicyCost() 
    { 
     decimal cost = 0; 
     foreach(var policy in Policies) 
     { 
      if(policy.DueDate < DateTime.Now){ 
      cost += policy.GetCost(); //for example but you can call whatever is defined at the interface level 
      } 
     } 
     return cost; 
    } 

    public bool HasEnoughFunds() 
    { 
     return customerAccount.Balance >= GetCurrentPolicyCost(); 
    } 

    //keeping Account hidden in Person as Person has a reference to Account. 
    //By doing so there is type coupling between the two classes 
    //BUT you can still modify Policies away from Person 
    private class Account 
    { 
     //should only contain properties and I assume only one 'Account' per person 
    } 
} 

public interface IPolicyTerm 
{ 
    object Id{get;set} 
    DateTime DueDate {get;set;} 
    decimal GetCost(); 
} 

///now we can have polymorphic Policies i.e. the cost of one can be calculated differently based on policy 

public class LifeCoverPolicy : IPolicyTerm 
{ 

    public object Id; 
    public DateTime DueDate{get;set;}   

    public decimal GetCost() 
    { 
      return 10; 
    } 
}