从逻辑中分离数据

时间:2015-10-19 07:57:03

标签: architecture

假设我有一个具有“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”是否正确名称?

我希望你可以帮助一个一次又一次挑战我的问题,现在只能将它表达成一个查询。

麦克

1 个答案:

答案 0 :(得分:2)

所有三种情况可以用于更好的选择取决于凝聚力。换句话说,它取决于xpUser的关系(无论是属性还是聚合域实体,甚至属于其他域)。其他值(例如liveshealth等)可以有不同的解决方案。因此,您不必为所有内容应用相同的方法,此外,我确信他们在您的域模型中扮演不同的角色。

<强> 1。高内聚(属性),该值是父对象结构的一部分,父对象在没有它的情况下不能存在。然后它应该是第一个示例中的字段(属性)和/或方法集

然而,xp

似乎不是这样

<强> 2。聚合实体,该值高度连接到父(聚合根),但可以单独使用。这是XPComponent的第二个例子。因此,您可以决定XPComponent是否是您网域的聚合实体。我不会在这里看到Demeter定律的大问题,因为它对更高级别的系统架构有用see also

第3。单独的实体。它只有父母的引用。这不是xp的情况。

<强> 4。服务功能。因此它既不是实体也不是Domain模型的一部分。在这种情况下,您可以使用实际上是域服务的Helpers解决方案。