Scott Balmos wrote:
> >
> >> The best example I can think of is say you have a military personnel
> >> app, with objects representing a soldier and their rank (ie class
> >> Soldier has get/setRank). Would you put, say, function promote() in
> > the
> >> Soldier or Rank object class itself, or in the personnel-management
> >> class(es), and have only get/set methods in Soldier and Rank?
> >
>
> --Scott
Hi, Scott,
Excellent question. I think you're hitting this problem, however,
because you're not asking the right question (even though the one you
have asked is ... excellent).
Before diving in, I should say that I like Filip's suggestion
(essentially splitting the Soldier into more single-responsibility
parts) though I wouldn't have used his class names. I'd have
preferred, "SoldierManager," to be just, "Solider;" but that's another
story.
Also, before getting wet, I wasn't sure which of your suggestions you
think is best. You gave the, "Logicless Soldier," example, and the,
"Smart Soldier," example, and said, "Makes sense ..." Which
alternative did you think best?
Anyway, IMHO, to decide which is best, you have to ask a question that
you haven't touched on at all, and realise that this is *not* just a
question of the logical decomposition of a Solder-entity: this is a
question of encapsulation. You have to ask, "How can I maximise this
behaviour's encapsulation?"
Let's presume that you have all these soldier-related classes in a
package called, "fight," which contains the public interface,
"Solier." Your question boils down to asking: should Solider have a
promote() method, or a getRank() method?
This entirely depends on whether the Rank class is used by many
clients outside the fight package: in other words, it depends entirely
on how well encapsulated you want the Rank class (or more specifically,
the ranking behaviour) to be.
If you have many clients outside the fight package that need the
specifics of rankings and ranking behaviours (such as the ranking
succession you alluded to in your example), then it makes sense to
have a public Rank class (or better yet, a public Rank interface) in
the fight package (actually, there are better places for it than the
fight package but that's, again, another story); and so it makes sense
for the Soldier interface to have getRank() method.
If, however, no one cares about the ranking behaviour of your Soldier
outside your fight package, then this behaviour should be as
encapsulated as possible: your Soldier interface should just have a
promote() method.
This doesn't mean either that there must or must not be a Rank
interface, it's just that, if you want a Rank interface, it will be
package-private to the fight package and Soldier will delegate to it
(a second principle, in fact, will come into play here: the principle
of variance encapsulation; if you think that promotion behaviour is
likely to change, then there *should* be a separate, package-private
Rank interface, but that's another blah blah blah).
Also, cilents must make significant use of the Rank interface to
warrant making it a public interface: if the view package (for
example) wants to print a soldier's status, it will certainly want to
know his rank, but it would be more flexible if the view package gave
a some sort of TextStream to the Soldier to let it print out whatever
details it likes (or alternatively, and slighty more ugly, have Soldier
expose method: String getRank()) - this is not sufficient cause to
explose a public
interface.
..ed
--
www.EdmundKirwan.com - Home of The Fractal Class Composition.