在C#或OOP中,2个类应该相互引用吗?

时间:2010-03-04 16:49:48

标签: c# .net asp.net oop

我正在使用C#编写类库。我设计了3个主要类来帮助建模数据。设计它们使得类A包含类B实例的列表,而类B包含对类C实例的引用,即:

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或Billing中使用需要来自包含类的数据的方法时。在上面的示例中,这将是尝试使用PolicyTerm中的值的方法“doSomething”,例如请求或将数据保存到数据库中的术语的生效日期。

我想知道我是否因为这种情况而为我的班级设计了正确的设计。我是否应该在子类中添加对“父”类的引用,以使父数据可用?或者我是否需要重新考虑代码的整体结构和设计?

我觉得类设计适用于数据和业务规则的建模,但它确实会产生一些限制,如上述情况。我喜欢将PolicyTerm和Billing分开,以便能够独立地修改和测试代码。此外,我觉得它让每个部分都更小更简单。

非常感谢任何可以提供的建议。

更新:代码块已更新,以提供有关代码的更多详细信息。

6 个答案:

答案 0 :(得分:6)

如果doSomething()总是需要引用C对象的父对象,那么您应该将此引用放入C中,以确保它引用正确的B实例。 OTOH如果该引用并不总是父引用,但仍然总是引用相同的B实例,它仍然建议将其转换为C的成员。 OTOH如果可以使用不同的引用调用doSomething(),则该引用应保留为方法参数。

将一个引用从子级转换为父级,或者在两个类之间具有相互依赖关系本身并不坏 - 它取决于上下文。这样做的结果是两个类不能单独使用,因此实际上它们形成了组件。这可能是也可能不适合你。

组件通常可以包含多个类 - 带有项的集合和迭代器实际上是一个典型的例子。但是,建议在物理层面上表达这些类之间的逻辑依赖关系,例如:通过使一个类成为另一个类的内部类,或者在第三个类中使两个类成为内部类。

答案 1 :(得分:2)

这实际上取决于具体情况。一般来说,除非“B”和“C”类之间存在清晰明显的关系,否则C.doSomething()需要访问B的红旗,因为C 包含在< / em> B ......

然而,B中需要访问C的方法是有意义的,因为C是B中的成员。

话虽如此,有时候这是恰当的。如果不知道你的实际课程,以及他们所代表的内容,就很难说出来......

答案 2 :(得分:2)

两个类不应该,但两个接口都可以。

当然,界面越小越好。你会发现,如果界面足够小(应该是 - Interface Segregation Principal),你实际上不需要2个。

答案 3 :(得分:0)

创建对所需类的引用根本不是一个坏主意。如果需要,可以使C类的构造函数接受对B类的引用并将其存储在成员变量中。

我正在研究一个项目,有几个课程表现得像这样。

另一个可能更“理智”的选择是在C类上有一个事件,就像“SuchAndSuchDataRequired”。然后,当B类获得C实例时,B类可以监听该事件。当C类需要来自B,B的数据时,类C从doSomething()内部触发事件,然后在其事件处理程序和bingo中返回数据 - 类C具有数据,甚至不知道它来自B类。

答案 4 :(得分:0)

一般的经验法则是使数据尽可能接近将要使用它的函数/方法/类。这将使事物分离,你不必让两个类相互引用,这实际上使你必须创建一个可能没有必要的额外对象。

和ChaosPandion说:请发布一些更具体的代码,以便我们更好地帮助您。

编辑:

如果B引用C和C引用B,那么您可能需要考虑将两者放在一起作为一个对象。如果两个类没有完全不同,这种方法效果最好。如果没有真正可区分的差异,那么只需将它放在一个类中......这可以简化整个事情。

答案 5 :(得分:0)

在我看来,你的建模似乎有些偏差,即为什么在策略中有类型的属性,为什么在策略中有一个具体实现的列表,即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;
     }
}