2015-10-19 97 views
2

假设我有一个具有“xp”值的User对象。现在说我有一个包含XPLevels数组定义多少点都需要这个水平(除其他事项外)的XPLevelsModel:从逻辑中分离数据

class User 
{  
    xp : int; 
} 

class XPLevelsModel 
{ 
    levels : XPLevel; 
} 

class XPLevel 
{ 
    ... 
    xpRequired : int; 
    name : String; 
    ... 
} 

好了,所以现在说我有许多方法,如“getCurrentLevel ()“”getPercentProgressThroughLevel()“等等这些方法应该在哪里?

我可以把他们的用户对象上:

class User 
{ 
    constructor(levelsModel:XPLevelsModel) : {} 

    xp : int; 

    getCurrentLevel() : int {} 
    getPercentProgressThroughLevel() : Number {} 
    ... 
} 

但是我们添加更多的数据,如“生活”,“健康”等等等等,用户将开始有很多的功能(不是很好成长在SoC)

我可以尝试组这些东西成组分,如“XPComponent”,这是对用户的对象:

class User 
{ 
    xp : UserXPComponent; 
} 

class UserXPComponent 
{ 
    constructor(levelsModel:XPLevelsModel) {} 
    points : int; 

    getCurrentLevel() : int {} 
    getPercentProgressThroughLevel() : Number {} 
    ... 
} 

但问题是从静止访问该数据现在的游戏意味着user.xp.getCurrentLevel(),它打破了Demeter的定律,再加上它的丑陋,难以测试,如果深度更深,会发生什么?

还有一个选项,我想到了,能有这样的:

class User 
{ 
    xp : int 
} 

class UserXPHelpers 
{ 
    constructor(levelsModel:XPLevelsModel) {} 

    getCurrentLevel(user:User) : int {} 
    getPercentProgressThroughLevel(user:User) : Number {} 
} 

这里,我们已经分离出来的逻辑和数据,并通过方法传递给用户。唯一的是,这是不是打破封装?由于所有这些方法都依赖于用户传递给他们,他们不应该与用户住在一起吗?

如果这是正确的解决方案,“助手”是否正确的名称?

我希望你能帮助一次又一次地挑战我的问题,并且现在只能将它表达为一个查询。

迈克

+0

您使用哪种语言?如果您只关心第一个选项是类大小,只需使用[扩展方法](https://msdn.microsoft.com/en-gb/library/bb383977.aspx)。 – sdgfsdh

+0

我尽量保持抽象,语言无关紧要。它更多的是一个普遍的问题 – mikeysee

回答

2

三个案例可以用在更好的选择取决于凝聚力。换句话说,它取决于xpUser(无论是属性还是聚合域实体或甚至属于其他域)之间的关系。其他值如lives,health等可以有不同的解决方案。所以你不必适用于所有你的东西相同的方法,而且,我确定他们在你的域模型中扮演不同的角色。

1.高凝聚力(属性),该值是父对象结构的一部分,父对象结构中没有它的情况下不能存在。那么它应该与第一个例子中的字段(属性)和/或方法集一致。

尽管如此,xp似乎并非如此。

2.聚合实体,该值高度连接到父级(聚合根),但可以单独使用。这是你的第二个例子XPComponent。因此,您可以决定XPComponent是否为您网域的聚合实体。我没有看到德米特的法律在这里遇到很大的麻烦,因为它在更高级别的系统架构上有意义,see also

3.独立实体。它只对父级提及。这不是xp的情况。

4.服务功能。所以它既不是实体也不是域模型的一部分。在这种情况下,您可以使用您的Helpers解决方案,该解决方案实际上是一项域服务。