我正在使用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分开,以便能够独立地修改和测试代码。此外,我觉得它让每个部分都更小更简单。
非常感谢任何可以提供的建议。
更新:代码块已更新,以提供有关代码的更多详细信息。
答案 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;
}
}