Since
OO modeling is about observing real world, then why the Photo is the responsable for moving itself from one album to another, instead of the AlbumOwner being the responsable for the movement?
That is a very interesting question, that many have stumbled on and had opened many fierce debates (some of them philosophical) between soul mates :)
Quick answer
"Because the photo may be moved by many parties, not just the owner" :))))
You see, as the system evolves, other parties (say AlbumOwnerFriends) might be able to move photos around. Can you imagine implementing the move operation in each of them? For what reason?
The operation o
f adding a photo to an album should actually be implemented by a Photo Role (Say AlbumItem) in context ... check bellow.
Long answer
People that invented the OO stuff decades ago where actually quite smart. From then on, many people wrote books and texts totally distorting the initial ideas due to lack of understanding most of the times. This including myself and some current prominent DDD people. Since 2001 I decided to get back to basics due to several reasons.
One of the basics is that if you are making an operation over an object, give the object responsibility to make such operation.
This is spread all over well designed OO Frameworks (including some parts of
MS.NET) yet a lot of people that I meet have difficulties using this basic OO vision in their designs. Take a look at operator overloading, take a look at a collections (peoplecollection.Add(), strings (stringname.Concat(...)), all of these objects that we use daily have those operation not by chance. You see, they could have all be put in some domain service with double dispatch, library, or human role :). The question is why they where not and the answer follows.
So using this rule, what is necessary to move a photo? We have two albums (source, dest), a photo and a user. User is totally OUT of the question since the operation is NOT done specifically over it (it is just a participant). We are left with the two Albums and the Photo. Either
of the Albums have many photos, further more, now they may only contain photos, whose to say it might not have videos later?
So we are up to the Photo, the most specific item of the three. If you are moving a Photo between album give the photo the responsibility to move itself (notice the principle?)
If you have two competing forces for the operation, such as Album, User and Photo, have the most specific object participating in the business event, implement or direct it. Sometimes its difficult to choose which is more specific but at least you did not went to the Human Role or the Collection directly.
Why is this good you may ask?
The quick answer above
points to the reason ... FLEXIBILITY. You see, if the most specific object implements or directs the operation it can be changed locally with maximum effect. Furthermore, the other participants in the operation can be generalized with great effect.
If we went for the other option we would to either re-implement in each kind Role of Person as the system grown in complexity (dumn designer) or put the code in a domain service and have every roles call it. The later is a smarter designer but not quite there in understanding and appreciation of OO.
Why is it not there?
Now is the fun part. Double Dispatch is NOT only a hack to fit in some dynamic behavior or to avoid some dependency injection. Double disp
atch is an effective design pattern (including the visitor pattern) to all things concerned!
If we followed the principle above, double dispatch can be used to make some neat stuff, solving design problems that would be hard to solve otherwise.
Take for instance your Album, your Photo and your User. Take the use cases, If we drop a photo, either we move or we add the photo to the Album, if you drop an Album on a User we add the user as a AlbumOwnerFriend, if you drop the Album we add the user as a AlbumOwnerFriend.
So instead of putting all this behavior in the Album we spread it amongst the most specific parties. If a new kind of item, as for instance Video comes in, we simply need it to impl
ement the drop methods, double dispatch takes care of the rest :)
I wrote above:
"The operation of adding a photo to an album should actually be implemented by a Photo Role in context ... check bellow."
Strange design decision? Philosophical? No reallly.
Later if you want to abstract the album abilities to introduce for instance, Video, Stamps etc etc .....
class Album
{
....
void Add(AlbumOfItem p, AlbumOwner u)
{
p.AddToAlbum(this, u) // double dispatch
}
void Add(AlbumOfItem p, AlbumOwnerFriend u)
{
p.AddToAlbum(this, u) // double dispatch
}
}
class Photo : AlbumItem
{
....
void AddToAlbum(AlbumOfItem a, AlbumOwner u)
{
..... // you favorite business rule methodology .. I already gave examples of mine
}
void AddToAlbum(AlbumOfItem a, AlbumOwnerFriend u)
{
..... // you favorite business rule methodology .. I already gave examples of mine
}
}
interface AlbumItem
{
....
void AddToAlbum(AlbumOfItem a, AlbumOwner u);
void AddToAlbum(AlbumOfItem a, AlbumOwnerFriend u);
}
All this made easy because you followed "blindly" a simple rule:
If you are making an operation over an object, give the object responsibility to make such operation.
Does this answer your question?
Hope this post makes more sense.
Cheers,
Nuno