views:

102

answers:

4

I need some advice on modeling the following movies domain. I have a person entity. This person can be an Actor, Director, Producer and Writer and will often be all. I don't want to dup data in each entity so feel it best to create an abstract base class called Person that each of the Director, Actor and Writer classes inherit from. This has started to smell a when I look at the following test:

[Test] public void Can_Do_It()
{
   var actor = new Actor("Clint Eastwood");  
   var director = //?? Can new it up as he already exists as actor  }

Is it more preferable to have a Person Class and then have Classes like Writer that take in an instance of person i.e.

public class Writer(Person person, string attribute1, string attrribute2) {...}

+1  A: 

You should look at a composition rather than inheritance based model for this. Fairly standard design pattern for this sort of thing - in fact, I suspect (don't have a copy to hand) that it's in the Gang of Four design patterns book if you want more information.

David M
Thanks for the reply - from what I have now seen my code would read:var person = new Person("Clint Eastwood")var actor = new Actor(person);var director = new Director(person);?
Chev
+10  A: 

A common solution would be to introduce the concept of 'role' (quite fitting in this case). A person can be an Actor in 0+ movies, and/or fill a Director Role.

That also allows you to add attributes to the role, like character-name, dates etc


Edit:

The Role class would have 2-way associations with both Person and Movie.

class Role
{
     public Person Contributor { ... } 
     public Movie  Feature { ... }
     public RoleType Activity { ... }
}  

class Person
{
    public List<Role> Contributions { ... }
}        

class Movie
{
    public List<Role> Contributors { ... }
    ...
}
Henk Holterman
Thanks henk for the reply. What would the classes look like for a Person and Actor?
Chev
@Chev : The class would have a property of a collection type of roles... maybe : List<Role> Roles
Andrei Rinea
@Chev: see the Edit. Actor could be a class (class Actor: Role) or just a value of a RoleType enum.
Henk Holterman
I like this model quite a bit, as a Person could Act, Produce, Write and Direct their own film, but may well not be considered by others in the business to 'be' an Actor, Producer, Writer or Director. In fact, I suspect this is a surprisingly common category in LA.
Dan Bryant
@Henk-Thanks for the response. I have actually used this pattern many times before (especially with Permissions). My issues here:1) A role only exists in the context of a Movie. i.e. an Actor is only an actor if they are assigned to a movie as an actor.So in order to get a list of actors, you cannot call actors.ToList(), but have to call movies.where(x=>x.Contributions.RoleType==RoleType.Actor).ToList() 2)Entity specific attributes would be shared across all types.If writers have a WGALicence attribute, this would need to exist in the Person class and may not be applicable to a Director role.
Chev
@Henk Continued. Another problem shows its head in the following scenario. An Actor plays a Character. So Character, ie. james bond, will be an entity. An Actor performs in a Role as a Character. Therefor the Role class would need to have a Charater property. This only pertains to Actor RoleTypes though. Do you suggest simply creating all different attributes for the various RoleTypes in the Role class?
Chev
@Chev, I think you already made some good analysis of your domain but it seems you need to do even more. Do you require the distinction between IS actor and WAS an actor? Is somebody with a license but who has never written an (accepted) script a Writer? I expect you will end up with a composition system, but keep thinking and sketching until it fits.
Henk Holterman
And you say "So Character[...] will be an entity. I would not be so hasty. It could be a simple attribute (of a Role). And you could model Role-types with inheritance or simple attributes too.
Henk Holterman
+2  A: 

You could have a concrete class Person with all the common details of a person, and then the person class would also have a collection/list of roles. The roles would be Actor, Writer, etc. and they would have all the necessary extra attributes + behaviour.

Grzenio
@Grzenio - thanks for the reply. Do you see the roles as concrete classes are enumns?
Chev
I was thinking about concrete classes, because this way they can store additional information and encapsulate some behaviour.
Grzenio
+1  A: 

If your "roles" are finite and can be defined up-front (as seems the case in your example), you could use a bitwise enum flag on the Person class.

class Person {
   [Flags]
   public enum EnumRole {
      None = 0,
      Actor,
      Director,
      Producer,
      Writer
   }

   public Person( EnumRole role ) {
      Role = role;
   }

   public EnumRole Role { get; set; }

   public bool CanDo( EnumRole role ) {
      return (Role & role) != EnumRole.None;
   }
}

Then create your person with the required roles:

Person p = new Person(Person.EnumRole.Actor | Person.EnumRole.Director);

... and check if they have a required role ...

bool canDoIt = p.CanDo(Person.EnumRole.Actor);
PjL