Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it good practice to use domain objects as keys?

Is is good practice to use domain objects as keys for maps (or "get" methods), or is it better to just use the id of the domain object?

It's simpler to explain with an example. Let's say I have Person class, a Club class, and a Membership class (that connects the other two). I.e.,

public class Person {
    private int id; // primary key
    private String name;
}

public class Club {
    private String name; // primary key
}

public class Membership {
    private Person person;
    private Club club;
    private Date expires;
}

Or something like that. Now, I want to add a method getMembership to Club. The question is, should this method take a Person object:

public Membership getMembership(Person person);

or, the id of a person:

public Membership getMembership(int personId);

Which is most idiomatic, which is most convenient, which is most suitable?

Edit: Many very good answers. I went with not exposing the id, because the "Person" (as you might have realized, my real domain does not have anything to do with people and clubs...) instances are easily available, but for now it is internally stored in a HashMap hashed on the id - but at least I am exposing it correctly in the interface.

like image 864
waxwing Avatar asked Jun 21 '10 19:06

waxwing


People also ask

Should domain objects have Ids?

Ids in domain entities is a design smell. In most cases, they indicate poor entity encapsulation. If you want proper separation of concerns, you should reduce the number of Ids in your domain entities to as low as possible. Heavy Ids usage is common for anemic model.

What are domain specific objects?

Objects from the business specific area that represent something meaningful to the domain expert. Domain objects are mostly represented by entities and value objects. Generaly speaking, most objects that live in domain layer contribute to the model and are domain objects.


1 Answers

Don't use the id's man, this is just a bad idea for all the reasons mentioned. You'll lock yourself into a design. Let me give an example.

Right now you define you're Membership as a mapping between Clubs to People. Rightfully, your Membership should be a map of Clubs to "Members", but you are assuming that all Members are People and that since all of the people id's are unique you think you can just use the ID.

But what if in the future you want to extend your membership concept to "family memberships", for which you create a Family table and a Family class. In good OO fashion you extract an interface of Family and Person called Member. As long as both classes implement the equals and hashCode methods properly, no other code will have to be touched. Personally, I would have defined the Member interface right up front.

public interface Member {
}

public class Person implements Member {
    private int id; // primary key
    private String name;
}

public class Family implements Member {
   private int id;
   private String name;
}

public class Club {
    private String name; // primary key
}

public class Membership {
   private Member member;
   private Club club;
   private Date expires;
}

If, you had used ID's in your interface, you will either need to enforce cross-table uniqueness of key values, or maintain two separate Maps and forgo the nice polymorphic interface stuff.

Believe me, unless you are writing one-off, disposable applications, you want to avoid using ID's in your interface.

like image 56
dsmith Avatar answered Oct 21 '22 01:10

dsmith