views:

336

answers:

12

This may simply be a matter of preference, however, I am interested to know what is the best-practise way of when to use either approach.

e.g.

var person = new Person();
person.Run();

as opposed to

var person = new Person();
Excercise.Run(person);

The above example may not be the best, but my general point is when should you decide to give the object the responsibility as opposed to another class?

+5  A: 

Normally a class, in this case Person, has behaviour;

And in this case, the behavior is Run and thus the person should have the method Run

var p = new Person();
p.Run();
Andreas Grech
+1, but I'd prefer to be more explicit that a method is the behaviour of a thing, and doesn't make sense attached to another thing
annakata
+4  A: 

The first one carries so much more conceptual clarity. A person runs, a running exercise doesn't consume a person.

colithium
person.Consume(new Hotdog());
Matthew Whited
Haha yes, exactly. myHotDog.GetEatenBy(bob)
colithium
+2  A: 

If the it's the person's responsibility to Run then i would suggest person.Run() if Run though can handle other types of objects and it's somehow reusable outside the person object then it could stand on it's own and call it as Excercise.Run(person);

For me, i would go with person.Run();

Konstantinos
+7  A: 

Generally speaking, this OOPish construct:

person.Run(distance);

is just a syntactic sugar for:

Person.Run(person, distance);

where person becomes an implicit this reference. There are some subtleties with virtual functions and such, but you get the idea.

As for your question, you're basically having a rich domain model versus an anemic one, and this is a subject of a great many debates.

Anton Gogolev
+3  A: 

The comparision is ideally not correct for few reasons: 1. Ideally each object would be responsible for it's own activities for example in case of human, human would be responsible for human.walk(), human.eat(), human.sleep() etc. 2. The parameter that is being passed to the activity is a consumed resource for that activity. It would not be wise to say Life.walk(human), as walk is not Life's activity and human is not consumable resource. Here human is the object. However it would be wise to say human.eat(food); where food is a consumable resource. 3. The sample you have given seems to potray that in second case Run is a static method and for object functioning you rarely want to implement it as a static method design.

Ideally design patterns would guide you, if implemented correctly, that which way a function will be called on an instance, but mostly what will get passed to a method is a resource that is req. to do that activity and not the action object.

I hope that clears up your doubt. For more details on design patterns you can some books by Martin fowler. http://www.martinfowler.com/books.html

Priyank
Try not to focus too heavily on the example as I have admittedly said its not the best. I am really looking to discover when you should give the object the functionality or when it should be outsourced to another class which consumes the object.
James
Ideal and simple way is think where an object is a driver for an activity or if a resource for an activity. This is a simple think-check. If you feel object in real world would like to do it itself, then probably method should be object's responsibility else if in real world object would be consumed or used in activity then we would pass the object.If someone else should do it for object then maybe that would be an object attribute which would be called with it function to do it?Does that help?
Priyank
Just to pick up on something you said...why is it not ideal to use static methods when dealing with objects?
James
To answer James.Static void encapsulation. The core "duties" of an object is to maintain the encapsulation. This results in loose coupling and almost a component type existence. With implementation of statics in objects you break the encapsulation, make it visible to outside world and objects' implementation becomes dependent on his behavior or coupling with other objects. In an ideal situation; you would want an object to be self sustaining, if it needs something else; some other object should provide it.I hope I am clear. Base is about encapsulation and loose coupling.
Priyank
+12  A: 

Don't do things for your objects. They're there to do things for you.

That sounds quite simplistic, but it's a useful maxim to follow. It means (as you've identified) calling methods on an object and it will use all the knowledge available to it to produce a result. It reinforces encapsulation and separation/containment of responsibilities

An indicator that this is not happening is code like this:

priceBond(bond.getPrincipal(), bond.getMaturity(), bond.getCoupons(), interestRate)

where the bond object is yielding all it's information to some third party. Code like the above will end up beng duplicated everywhere. Instead write

bond.priceBond(interestRate)

and keep all the information tied up in the one object.

If your objects suffer from huge numbers of getters, then it's a possible indicator that your objects aren't doing what they're supposed to.

Brian Agnew
On this occassion tho could priceBond not consume a bond object and then deal with it internally?
James
But how does it determine the coupons/maturity etc.? It would still have to query the bond object. And (without getting into financial specifics) if the bond is a convertible, then its pricing is completely different. The point I'm trying to demonstrate is that the bond has all the knowledge required, and consequently should do the work for you.
Brian Agnew
A: 

There is a slight differences:

  • person.Run() receives a single parameter: this
  • if Excercise.Run(person) is a static method, it also receives a single parameter
  • if Excercise is an instance, it receives two parameters: this and person

Obviously the third approach is only needed if you have to pass both parameters. I would say the first approach is better OOP and I would only chose the second one in very special circumstances (for exmaple, if Person was sealed).

DrJokepu
I don't think statics are relevant here. They are a language-specific feature and the question is language-agnostic.
finnw
I think it is safe to assume that the OP meant a static method, given the context. And I wouldn't consider them language-specific; most OOP languages have static methods
DrJokepu
+1  A: 

I agree with the first answer that if the act of running is best 'understood' by the person object then that is where it should reside, for both functionality and clarity.

The second case is more suited to interpretations outside of the object and is best performed through interfaces. So instead of taking a person object the Excersize methods should take an interface, say IExcersizable that, for example, moves limbs. The Excesize.run(IExersizable) method could move one leg and then the other in quick succession. The Excesize.walk(IExersizable) could to the same but slower.

The person objec could then implement the interface to deal with the specifics of 'limb' movement.

Adrian Regan
A: 

Two things:

  1. This is not a matter of taste but has actual technical consequences. The differences between a member fucntion and a free function have been discussed at great length already, I recommend having a look at the Effective C++ book and/or an article by Scott Meyers at http://www.ddj.com/cpp/184401197 In short, if you make a function a member function, you'd better have a darn good reason to do so.

  2. The readability argument should be taken with care. It depends very much on the name of the member function. Remember the SPO - Subject Predicate Object rule: there's little doubt that person.run() looks better than run(person); (at least to an english-speaking person), but what if you have other verbs than 'run'. Some verb which takes an object, for instance 'to call' in case you want to make a phone call? Compare call( person ); vs. person.call();. The former looks much nicer.

Frerich Raabe
A: 

I agree with Brian. Just for reference, I wanted to point out this article on "Tell, Don't Ask" and "Law of Demeter". Both are applicable here.

Pragmatic Programmer: Tell, Don't Ask

Nick Stamas
+1  A: 
supercat
A: 

Since a Person will be doing the running, it is better to have a run method in there.

fastcodejava