假设我有一个具有“xp”值的User对象。现在说我有一个XPLevelsModel,它包含一个XPLevels数组,用于定义该级别所需的点数(以及其他内容):
Map<Long,String> a = new HashMap<> ();
a.put(1L,branchName);
好的,现在说我有很多方法,比如“getCurrentLevel()”“getPercentProgressThroughLevel()”等等。这些方法应该在哪里生效?
我可以将它们放在User对象上:
class User
{
xp : int;
}
class XPLevelsModel
{
levels : XPLevel;
}
class XPLevel
{
...
xpRequired : int;
name : String;
...
}
但随着我们添加更多数据,如“生命”,“健康”等等,用户将开始增加许多功能(对SoC不太好)
我可以尝试将这些内容分组到组件中,例如“XPComponent”,它是User上的一个对象:
class User
{
constructor(levelsModel:XPLevelsModel) : {}
xp : int;
getCurrentLevel() : int {}
getPercentProgressThroughLevel() : Number {}
...
}
但问题是从游戏的其余部分访问这些数据现在意味着user.xp.getCurrentLevel(),这违反了Demeter的规律,加上它的丑陋,难以测试,如果你去更深层次会发生什么?
还有一个我想到的选择,就是:
class User
{
xp : UserXPComponent;
}
class UserXPComponent
{
constructor(levelsModel:XPLevelsModel) {}
points : int;
getCurrentLevel() : int {}
getPercentProgressThroughLevel() : Number {}
...
}
这里我们已经分离出逻辑和数据,并通过方法传递给用户。唯一的问题是,这不会破坏封装吗?由于所有这些方法都依赖于将用户传递给他们,他们不应该和用户一起生活吗?
如果这是正确的解决方案,那么“Helpers”是否正确名称?
我希望你可以帮助一个一次又一次挑战我的问题,现在只能将它表达成一个查询。
麦克
答案 0 :(得分:2)
所有三种情况可以用于更好的选择取决于凝聚力。换句话说,它取决于xp
与User
的关系(无论是属性还是聚合域实体,甚至属于其他域)。其他值(例如lives
,health
等)可以有不同的解决方案。因此,您不必为所有内容应用相同的方法,此外,我确信他们在您的域模型中扮演不同的角色。
<强> 1。高内聚(属性),该值是父对象结构的一部分,父对象在没有它的情况下不能存在。然后它应该是第一个示例中的字段(属性)和/或方法集。
然而,xp
。
<强> 2。聚合实体,该值高度连接到父(聚合根),但可以单独使用。这是XPComponent
的第二个例子。因此,您可以决定XPComponent
是否是您网域的聚合实体。我不会在这里看到Demeter定律的大问题,因为它对更高级别的系统架构有用see also。
第3。单独的实体。它只有父母的引用。这不是xp
的情况。
<强> 4。服务功能。因此它既不是实体也不是Domain模型的一部分。在这种情况下,您可以使用实际上是域服务的Helpers
解决方案。