2

好吧,假设我正在为以下足球俱乐部建模:所有人都是个人。玩家是一个人,因此扩展了个人。会员是一个人,因此扩展了个人。

超类:

Individual {name, eyeColour}

子类:

Player extends Individual {position}
Member extends Individual {subscription}

汤姆是足球俱乐部的老板:

Individual i = new Individual("Tom", "Blue")

鲍勃和托尼是球员:

Player p1 = new Player("Bob", "Green", "Goalkeeper")
Player p2 = new Player("Tony", "Blue", "Striker")

史蒂夫是会员:

Member m = new Member("Steve", "Brown", 5.00)

个人、玩家和会员都使用 Objectify 持久化到 GAE 数据存储中的相同种类(个人)。

    姓名 eyeColor 位置订阅 ^d
    汤姆·布鲁[失踪][失踪]个人
    鲍勃格林守门员[失踪]球员
    托尼·蓝前锋 [失踪] 球员
    史蒂夫布朗 [失踪] 5.00 会员

例如,如果 Bob 决定成为会员和玩家怎么办?我要存储的是订阅。我不能将 Bob 上调给个人,然后再下调给会员。Java 不允许这样做。我无法创建新成员并复制 Bob 的 Player 对象的所有属性并使用相同的 id 将其存储回来 - 我将失去他的 Position 属性。我需要 Bob 在 datstore 中既是成员又是玩家,但不是对象形式(我不是在多重继承之后)我仍然想获取(Player.class,“Bob”)并拥有一个玩家对象(Member.class,"Bob") 并拥有一个 Member 对象。我不需要同时具有位置和订阅属性的对象。

我也想避免这是数据存储:

    姓名 eyeColor 位置订阅 ^d
    汤姆·布鲁[失踪][失踪]个人
    鲍勃格林守门员[失踪]球员
    鲍勃格林 [失踪] 10.00 会员
    托尼·蓝前锋 [失踪] 球员
    史蒂夫布朗 [失踪] 5.00 会员

因为 Bob 现在在 name 和 eyeColour 上有数据重复,这可能导致数据不一致。

关于如何建模的任何想法?

另外,如果汤姆成为球员,或者史蒂夫成为会员怎么办?

4

6 回答 6

5
Individual {name, eyeColour}
MemberRole {individual, position}
PlayerRole {individual, subscription}

很明显,继承不适合您的任务。例如,某人可能在两支不同的球队踢球或成为两支不同俱乐部的成员(而您的原始结构根本不允许拥有一个以上的足球俱乐部)。

个人是什么,他们有什么角色,是不同的事情。例如,您不希望某个全局数据库将您的姓名、stackoverflow 积分、婚姻状况和职业都存储在同Individual一张表中。

如果 Bob 决定成为会员,Bob 本身不会改变;它的作用。决定成为会员的鲍勃还是老鲍勃一样的好,只是他现在可以做一些他之前被禁止做的事情。

PS:您在答案中使用了订阅一词。这就是你的Player ——一个SubscriptionSubscriptions 显然不是 s 的某个特定子集IndividualSubscription是一个完全不同的实体。当然,它应该知道Individual它属于什么,但它不是一个Individual自身。

于 2012-06-28T08:57:02.613 回答
3

一开始我会把每个人都看成是一个Individual,但你想让某些人成为一个Player或一个Memberboth。您需要使用Interfaces. 因为我不喜欢 Java,我建议做一些类似于这段代码的事情:

interface IPlayable {void MakePlayable (string position)};
interface IMembership {void AddMembership (double subscription)};

class Individual implements IPlayable, IMembership{name, eyeColour, IPlayable.MakePlayable(string position), IMembership.AddMembership(double subscription)};

//Usage to make Tom a Player
Individual tom = new Individual("Tom", "Blue");
tom.MakePlayable("GoalKeeper");

//Usage to make Steve a Member
Individual steve = new Individual("Steve", "Brown");
steve.AddMembership(5.00);

//Usage to make Jim both a Player and a Member
Individual jim = new Individual("Jim", "Black");
jim.MakePlayable("Forward");
jim.AddMembership(4.00);

除了实现多接口场景之外,这里还需要使用接口,因为使用 Member 类会使个人成为某个俱乐部的永久成员,使用 IMembership 接口可以添加一个RemoveMembership()方法,该方法有助于Individual在需要时删除成员资格在未来。

于 2012-06-28T09:01:53.640 回答
0
public class Individual {
    Role role;
    int    position;     //empty for MEMBER,filled for PLAYER_MEMBER and PLAYER
    int    subscription; //empty for PLAYER,filled for PLAYER_MEMBER and MEMBER }

public enum Role {  MEMBER,PLAYER,PLAYER_MEMBER; }

因此,完成切换后,您只需更改角色并填写缺失的字段。应该进行验证。

于 2012-06-28T09:27:54.907 回答
0

请参阅GAE 文档中的JDO 中的实体关系:

您可以使用对象类型的字段对持久对象之间的关系进行建模。持久对象之间的关系可以描述为拥有,其中一个对象不能没有另一个而存在,或者是无主的,其中两个对象可以独立于它们彼此的关系而存在。JDO 接口的 App Engine 实现可以对拥有和无主的一对一关系和一对多关系进行建模,包括单向和双向。

我会说你有两个“拥有”的关系。Player并且Member都“拥有”一个Individual.

于 2012-06-28T09:10:19.940 回答
0

尝试这个...

个人是SuperClass

播放器和成员作为接口

假设 Bob 既是玩家又是成员。

现在..

Bob 是一个 Individual (即扩展 Individual

Bob实现了Player 和 Member接口(即 Bob 扮演 Player 和 Member 的角色)

于 2012-06-28T09:04:13.563 回答
0

创建一个个人类(名称、眼睛颜色)并创建所有者、玩家和成员的接口。您将拥有独特的个体,并且不断向他们添加功能。因此,您将拥有一个您想要的表格,最后一列将列出不同的实现。

使用接口比实现多重继承要好得多,java就是这样做的。所以最好用这个

于 2012-06-29T10:35:17.750 回答