简体   繁体   中英

If not polymorphism, how do I model these classes

Ok so say I'm modelling the following Football Club: All people are Individuals. A Player is a person and therefore extends an Individual. A Member is a person and therefore extends an Individual.

Superclass:

Individual {name, eyeColour}

Subclasses:

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

Tom is the owner of the Football Club:

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

Bob & Tony are Players:

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

Steve is a Member:

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

Individuals, Players and Members are all persisted to the same Kind (Individual) in the GAE datastore using Objectify.

name    eyeColour   position        subscription    ^d
    Tom     Blue        [missing]       [missing]       Individual
    Bob     Green       Goalkeeper      [missing]       Player
    Tony    Blue        Striker         [missing]       Player
    Steve   Brown       [missing]       5.00            Member

What if eg Bob decides to become a Member as well as a Player? I want to store is subscription. I can't upcast Bob to an Individual and then downcast to a Member. Java doesn't allow this. I can't create a new Member and copy all the properties of Bob's Player object and store it back with the same id - I'll lose his Position property. I need Bob to be both a Member and a Player in the datstore but NOT in object form (I'm not after multi-inheritance) I still want to get(Player.class,"Bob") and have a Player object or get(Member.class,"Bob") and have a Member object. I won't need an Object that has both the position and subscription properties at the same time.

I also want to avoid this is the datastore:

name    eyeColour   position    subscription    ^d
    Tom     Blue        [missing]   [missing]   Individual
    Bob     Green       Goalkeeper  [missing]   Player
    Bob     Green       [missing]   10.00       Member
    Tony    Blue        Striker     [missing]   Player
    Steve   Brown       [missing]   5.00        Member

because Bob now has data duplication on name and eyeColour which could lead to data inconsistancy.

Any ideas for how to model this?

Also what if Tom becomes a player, or Steve becomes a member?

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

It is clear that inheritance is not suitable for your task. For example, someone may play in two different teams or be a member of two different clubs (and your original structure won't allow having more than one football club at all).

What the individuals are, and what roles do they have, are different things. For example, you wouldn't want for some global DB to store your name, your stackoverflow points, your marital status and your occupation all in the same Individual table.

If Bob decides to become a member, Bob itself doesn't change; its roles do. Bob decided to become a member is still the same good old Bob, it is just he now will be able to do something he was forbidden to earlier.

PS: You are using the term subscription in your answer. That's what your Player is -- a Subscription . Subscription s is obviously not some specific subset of Individual s, Subscription is a completely different entity. Of course, it should know about what Individual does it belong to, but it is not an Individual itself.

At the outset I would see everyone as an Individual , but you want to make certain individuals either a Player or a Member or both . You would need to model this scenario using Interfaces . As I am not into Java, I would suggest doing something similar to this code:

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);

Other than implementing multiple interface scenario, using an interface is also required here, because using a Member class would otherwise make an individual a permanent member of some club, using IMembership interface you can add a RemoveMembership() method that would help to remove membership of an Individual whenever required in future.

Try this...

Individual be the SuperClass .

Player and Member as Interfaces .

Assume Bob as a Player and also as a Member.

Now..

Bob is a Individual (ie extends Individual )

Bob implements Player and Member Interfaces (ie Bob Plays roles of Player and Member both)

See Entity Relationships in JDO in the GAE documentation:

You can model relationships between persistent objects using fields of the object types. A relationship between persistent objects can be described as owned, where one of the objects cannot exist without the other, or unowned, where both objects can exist independently of their relationship with one another. The App Engine implementation of the JDO interface can model both owned and unowned one-to-one relationships and one-to-many relationships, both unidirectional and bidirectional.

I'd say that you have two "owned" relationships. Player and Member both "own" an Individual .

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; }

So when a switch is done you just change the role and complete the missing field. A validation should be done thought.

make an class Indiviual (name, eyecolor) and create interfaces of Owner, Player, and Member. You will have unique individuals and you keep on adding functionalities to them. Hence you will have a table as you want and the last column will list the different implementations.

Using interfaces is much better than implementing multiple inheritance, and java does this. So, it's best you use this

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM