避免肿的域对象


12

我们正在尝试使用DDD方法将数据从庞大的Service层移至Domain层。当前,我们的服务中有很多业务逻辑,这些业务逻辑遍布各地,并且无法从继承中受益。

我们有一个中心的Domain类,这是我们大多数工作的重点-Trade。贸易对象将知道如何定价,如何估计风险,验证自身等。然后,我们可以用多态性替换条件。例如:SimpleTrade将以一种方式定价,而ComplexTrade将以另一种定价。

但是,我们担心这会使贸易类膨胀。它确实应该负责自己的处理,但是随着添加更多功能,类的大小将成倍增加。

所以我们有选择:

  1. 将处理逻辑放在贸易类中。现在,根据交易类型,处理逻辑是多态的,但是交易类别现在具有多种责任(定价,风险等)并且规模很大
  2. 将处理逻辑放入其他类,例如TradePricingService。Trade继承树不再具有多态性,而是类更小并且更易于测试。

建议的方法是什么?


没问题-我很高兴接受迁移!


1
“随着更多功能的增加,类的大小将成倍增加”-任何程序员都应该比这样滥用“指数”一词更了解。
Michael Borgwardt

@Piskvor真是愚蠢
Arnis Lapsa 2011年

@Arnis L .:谢谢您的周到评论。请注意,这是“从11月22日22:19从stackoverflow.com迁移”,并附有我的评论。我现在删除了我的评论,“对程序员来说,这样做会更好”。现在,您有什么要补充的,还是您要表达的唯一想法?
Piskvor在2011

Answers:


8

如果您要进行“域驱动”,请考虑将您的“贸易”类别视为一个总根,并将其职责划分为其他类别。

您不想以价格和风险的每种组合都以Trade子类结尾,因此Trade可能包含Price和Risk对象(组成)。“价格”和“风险”对象进行实际计算,但除“交易”以外的任何类别都不可见。您可以减少交易量,同时又不会将新课程暴露给外界。

尝试使用组合以避免大的继承树。太多的继承会导致您试图以不符合模型的行为为shoe脚。最好将这些职责归为新类。


我同意。根据构成解决方案的行为(定价,RiskAssessment)来思考对象,而不是尝试对问题进行建模,可以避免这些单一的类。
加勒特音乐厅

也同意。组成,许多较小的类具有特定,单一的责任,利用有限的私有方法,很多的快乐接口等的
伊恩·

4

您的问题肯定使我想到了战略模式。然后,您可以交换各种交易/定价策略,类似于您所说的TradePricingService

我绝对认为您会在这里得到的建议是使用组合而不是继承。


2

我在类似情况下使用的一种可能的解决方案是适配器设计模式(所引用的页面包含许多示例代码)。可能与委托设计模式结合使用,可以轻松访问主要方法。

基本上,您将交易者功能划分为多个不同的区域-例如,价格,风险,验证的处理都可能是不同的区域。然后,对于每个区域,您可以实现一个单独的类层次结构,以不同的所需变体形式处理确切的功能-所有这些都是每个区域的通用接口。然后,将主要的Trader类简化为最基本的数据,并引用许多处理程序对象,可以在需要时构造这些对象。喜欢

interface IPriceCalculator {
  double getPrice(ITrader t);
}
interface ITrader {
  IPriceCalculator getPriceCalculator();
}
class Tracer implements ITrader {
  private IPriceCalculator myPriceCalculator = null;
  IPriceCalculator getPriceCalculator() {
    if (myPriceCalculator == null)
      myPriceCalculator = PriceCalculatorFactory.get(this);
    return myPriceCalculator;
  }
}

这种方法的一个主要优点是,例如价格和价格上涨的可能组合被完全分开,因此可以根据需要进行组合。对于大多数编程语言的单线程继承而言,这相当困难。使用哪种组合的决定甚至可以在很晚的时候得出:-)

我通常尝试使适配器类(例如上述子类)保持IPriceCalculator无状态。也就是说,这些类应尽可能不包含任何本地数据,以减少必须创建的实例数。因此,我通常在所有方法中都将经过修改的主要对象作为参数提供-像getPrice(ITrader)上面一样。


2

关于您的域不能说太多,但是

我们有一个中心的Domain类,这是我们大多数工作的重点-Trade。

...对我来说是一种气味。我可能会尝试勾勒出班级的不同职责,并最终将其分解为不同的汇总。然后,将围绕所涉利益相关者/领域专家的角色和/或观点来设计汇总。如果Price和Risk涉及相同的行为/用例,则它们可能属于同一集合。但是,如果它们解耦,它们可能属于单独的集合。

也许RiskEvaluation可能是您域中的一个单独实体,最终具有特定的生命周期(我不能说,我只是推测...您知道您的域,我不知道),但是关键是要隐式地创建概念显式的,并避免耦合不是由行为驱动的,而仅由遗留数据耦合驱动。

通常,我会考虑预期的行为以及所涉及组件的不同生命周期。仅在分组数据之上添加行为会创建creates肿的对象。但是数据已经按照现有的数据驱动设计进行了分组,因此没有必要坚持下去。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.