views:

352

answers:

11

I understand the basics of inheritance but this one is confusing me. How would you go about saying:

  • An album object has one or more artist objects
  • An album object has one or more song objects

My current code only will only allow one song per object:

class Song extends Album{}
class Album extends Artist{}

I'm sure i'm overlooking something important. Any thoughts?

I'm doing this in PHP

+2  A: 

I don't think there is any inheritance in these three classes. Is a Song an Album? No I don't think it is so Song should not inherit from Album. Is an Album an Artist? No I don't think that is either so Album should not inherit from Artist.

Instead you want to look at encapsulation. An Album references zero or more Artists. An Album contains zero ore more songs. An artist references zero or more Albums.

Brian Ensink
+24  A: 

An album has one or more artist objects. Inheritance would mean an album is an artist. What you need is (EDIT) aggregation:

class Album
{
  public $artists = array(); // Array of Artist instances
  public $songs   = array(); // Array of Song instances
}

Aggregation means every Artist and Song instance may belong to other Albums. With composition, an artist or song may belong to a single Album.

Victor Nicollet
+1 - Exactly correct.
Topher Fangio
This model doesn't really point out which artists were involved with which songs. I'd think it would be better to have something like `class Song { string[] artists; string name; int genre }` along with `class Album { Song[] songs; string catalog; string publisher }`
Tom the Junglist
+1, probably the clearest way to say what several others (including myself) also said.
Brian Ensink
Wouldn't this rather be an aggregate?
Gordon
@Gordon : a song might appear on several albums. An artist may participate in several albums. I don't believe aggregation is adequate.
Victor Nicollet
@Victor your explanation is exactly why it should be an aggregate. The album doesn't own Song or Artist and neither vanishes when the album is destroyed.
Gordon
@Gordon: I can't believe I got the two mixed up... you are right.
Victor Nicollet
The best aggregation I can think of would be something like `class Song { string Album, string[] Artists, string Name; //etc }` and then both Album and Artist would have to be retrieved by searching all of the tracks. It is certainly less convenient than making the Song a child of the Album it is in, but it allows for greater flexibility in organizing the data- particularly when music that is not on an album comes into the system. What do you guys think?
Nathan Taylor
A: 

I'm not sure you're using OOP correctly. Generally, an object extends a parent when it has the same functionality of that parent, but some extra (or specific) functionality.

For example, let's use the auto industry:

class Automobile {}

class Truck extends Automobile {}
class Car extends Automobile {}

class Lexus extends Car{}

See how Lexus is the most specific, so it builds a hierarchy as it goes up?

What you are wanting is similar to a has_many relationship. An artist has many albums, an album has many songs, etc.

Edit 1: As Victor Nicollet said, you want composition.

Edit 2: As stated in the comments, you actually want aggregation. The provided article explains the difference between the two.

Topher Fangio
It's Aggregation, not Composition. An album does not own the songs.
Gordon
A fair explanation, actually. The OP would have learned that inheritance wasn't relevant, even if this wasn't quite the answer to his question.
David Caunt
@Gordon - Good point, I was a bit hasty using the same words other were. Thanks for pointing it out!
Topher Fangio
+3  A: 

Try thinking of it in terms of which objects have which properties. I.e. "The car HAS a color" or "The balloon HAS a string".

Song HAS Artist

Album HAS Songs

So your Song class would have an Artist object, and your Album class would contain a collection of Song objects.

Nathan Taylor
But aren't the reverses of your statements also true? `Artist **has** Songs`, in a way that color doesn't 'have' car. In your model does a Song have an Artist, but an Artist doesn't have Songs? If I wanted to know what songs an artist has, how would I express that?
I did not completely model the entire structure and what you say is true, `Artist has Songs`. When you construct your model it would probably make the most sense to have the Song object be the top level entity and each Song would have an Album object and an Artist object. In the case of `Album has Songs` and `Artist has Songs` you would perform a search on you base Song collection to find the appropriate tracks for that Artist or Album. Does that make decent enough sense?
Nathan Taylor
A: 

Here's my view.

Album contains Song(s) but a Song is not an Album.
Album is associated with Artist(s), but an Album is not an Artist.

You are mixing inheritance with relationships.

o.k.w
+5  A: 

Don't use inheritance for this kind of relationship, for the sake of all that is fried and filled with delicious cream!

A song is not an extension of an album, it's a part of album. Likewise an album isn't an extension of an artist, it's created by an artist. Moreover a song can appear on multiple albums, and a single album can have multiple artists.

You should be using a has-a relationship instead of inheritance for this situation. For example, you might have an Album object that has an array of Song objects as a member. That would convey the idea that songs belong to albums appropriately.

Welbog
Mmmmm donuts! +1
Byron Whitlock
A: 

This sounds like a database modeling question, not one of OOP. This is because you would most likely have a database of songs artists and albums. Not a class hierarchy.

Byron Whitlock
I wouldn't say that. There is nothing specific about databases when speaking about inheritance or composition. I think he is just confused on OOP in general.
Topher Fangio
Very true. Especially since ORM's turn your data into objects anyways.
Byron Whitlock
There is nothing wrong in having a Domain Model of Artist, Song and Album objects that is ignorant and different from the Persistence Layer, e.g. a database.
Gordon
+1  A: 

inheritance relationship are named "IS-A" while the relationship you're looking for is HAS-A

You need something like this:

Album
    artists: Artist[1..*]
    songs  : Song[1..*]

Where an Album HAS from 1 to many ( * ) artists ( defined by the Artist array ) and 1 album has from 1 to many ( * ) songs, ( defined by the Song array )

OscarRyz
+11  A: 

As I mentioned in one of my comments, if you had to model it via OOP I would say,

class Song {
    string[] artists;
    string title;
    int genre;
}

class Album {
    Song[] tracks;
}
Tom the Junglist
+1 I was just going to write this. An album is a collection of Songs and Songs have a title and are performed by Artists.
Gordon
+1  A: 

Favor composition over inheritance.

By what you said it should be like:

An album object has one or more artist objects. An album object has one or more song objects

class Album { Artist[] Artists; Song[] Songs; }

However that's not exactly how I envision this. I think each Album has one or more songs that is performed by one or more artists. I would do it like:

class Album { Songs[] Songs; // other album specific properties }

class Song { Artist[] Artists; // other song specific properties }

class Artist { // artist specific properties }

And I highly recommend in looking at OOD principles.

Vitaly
A: 

If you let us know what you are wishing to accomplish, that may help us arrive at the correct answer. However, these relationships would normally be stored in your database.

Martin Bean