views:

199

answers:

4
+4  Q: 

State vs. Behavior

Sometimes objects consist of pure data. Such objects have fields, accessors, and virtually no other methods.

Sometimes objects consist of pure behavior. They have other objects representing their state, or data is passed as method parameters. Usually such objects represent algorithms or some kind of policies.

What state/behavior ratio do you prefer?
What is more maintainable?
What is more error-prone?

A: 

I like objects which (in order of priority):

  1. Have detailed instructions on how to use them so you don't reach an invalid state.
  2. Throw exceptions when they are not in the correct state when you call a method.
  3. Have methods allowing you to assert that they are in the correct state before you call a method.

When these measures are in place, it's much harder to mess things up.

Objects with no behaviours may as well be hash tables, objects with no state may as well be a collection of functions.

too much php
It's even better when object is implemented in such a way that it never gets into an inconsistent state, even if an exception occurred.
vsg
A: 

I like objects that do one or the other - either represent something which has behavior (ideally, only exposes void methods), or represents pure state (ideally, is immutable and has no code apart from maintaining its state and possible validation).

The first type of objects pass the other type around to each other. This is pretty close the the Actor model, and doing this solves a lot of problems. (if doing this in Java/C#, you can pass around interfaces to the first type as 'values.')

I find it's objects in the middle (that are both state and behavioral) that you run into problems... some state in behavioral objects is okay, so long as the primary purpose for it isn't to be queried.

kyoryu
+1  A: 

If you are designing objects that are all behavior and no state or all state and no behavior I think there's a flaw somewhere in your designing. It's really not common to run into these kinds of objects in the real world, and if these are not supplementary objects that you are describing but representations of real-world objects then I think there's something wrong somewhere.

I don't have any set ratio for state/behavior. I think every object takes its own shape and this could differ rather radically among objects. But I think as time goes by and if you're working on the object a lot the verbs will tend to be more than the nounds/adjectives, i.e. behavior will dominate state.

That's what I have observed in my programs.

Cyril Gupta
What you're saying is true for imperative-style OO.
kyoryu
Imperative OO is gold standard. Not meaning that it must be used everywhere, but that everything must be compared to it. If you deviate from OO, you should know what are you doing it for. Splitting state and behavior does not not have inherent, absolute, value, and should be applied to specific cases where it is advantageous, not trying to satisfy some metric.
ima
A: 

Behavior should be implemented as a separate class only if it is generic and can be applied to objects of different classes. If it is the case, you don't get to choose "ratio" - it depends solely on number of generic strategies in specific system.

Otherwise, a case of premature generalization, and even worse, unwarranted violation of OO principles. Yes, it is error-prone.

ima
I would argue about "only". Consider a case when you have a difficult piece of functionality. So, instead of having a GOD object you divide it into separate collaborating objects. Some of them are mostly state and others are mostly behaviors. The actual separation depends on specific case you have. But note that all those objects (and corresponding classes) are extremely non-generic.
vsg
I don't see how this scenario requires separation of behavior and state. Complex object can just as well break down into number of good OO objects having both of them.I'd say it's approaching problem from the wrong end. In good OO, you don't build object to implement functionality - you design system of connected objects where desired functionality emerges almost automatically.
ima
Well, I would agree in a sense that such separation can happen in other cases as a by-product or trade-off. But it's still something to avoid.
ima
Separation of state and behavior(s) could also be made to achieve separation of concerns. How that contradicts OOP?
vsg
"I don't see how this scenario requires separation of behavior and state." Sure it doesn't *always* require, but it's easy to imagine how it *could* require. That's why I gave that example.
vsg
Because object which doesn't contain behavior is not a real object? It can be an object in programming language terms, it can have member functions, but from design or analysis point of view - it's still a data structure. "Separation of concerns" in OOP concerns design of objects, so it's not applicable here. If it were, one can use it to argue about breaking down objects into separate variables and functions, for more thorough separation.
ima
In fact, it's a particular case of a more generic problem. Object is something self-sufficient, something with inherent meaning, use or domain analogy. If you make two objects which only make sense when used together - and that what happens with class-specific behavior in separate class - you introduce potential errors and misuse scenarios of somebody trying to use one class without the other.
ima
"If you make two objects...you introduce potential errors and misuse scenarios". That's why there are protected and package-private visibility for classes in Java (other languages have similar features). That's why there are *.impl packages, which along with implementation of interfaces contain "private" stuff. That's why there are *.internal packages in OSGi.
vsg
"Object is something self-sufficient...". This would mean no collaborating objects. I don't mean no collaboration of objects at all. I mean huge GOD objects which are not allowed to break into separate, because we need to preserve self-sufficiency. Maintainability + separation of concerns vs. OOP + object's self-sufficiency => self-sufficiency wins! Praise GOD objects!? Am I getting it wrong? "Separation of concerns ... it's not applicable here". Does that mean separation of concerns contradicts OOP?
vsg
"...breaking down objects into separate variables and functions, for more thorough separation" - you're obviously exaggerating here.
vsg
Why that's why? Repetition is not an argument. What exactly are you going to hide? Visibility of data-only-class and behavior-only-class must be same (so they can be used at all), and in that scope of visibility you get the problem I described above. Visibility won't help you when you've organized classes into puzzle, which only works when each unique piece is in it's unique place.
ima
"This would mean no collaborating objects." - Absolutely not. That means that objects collaboration is part of object's _coded_ behavior, not esoteric knowledge.
ima
"GOD objects", "Does that mean separation of concerns contradicts OOP" - that's your straw man.Are you implying that having behavior and state in the same object leads to GOD objects? That's just plain wrong. If it does in your experience, you are doing your design very wrong. GOD object can't happen in OOP, it's basically structured programming module posing as object.
ima
"Object is something self-sufficient...". How about design patterns? Many of them are objects which you would not consider "real objects": facade, bridge, mediator. They too, sort of contradict OOP object definition, which is object=data+methods to operate that encapsulated data. Each instance of these patterns is specific used with particular specific set of objects or interfaces, and really are not data+methods, but rather add-ons to "real" objects.
vsg
"Are you implying that having behavior and state in the same object leads to GOD objects?". I'm arguing that if there is a GOD object, it should be broken down into smaller objects. This can be achieved in some cases by "outsourcing" part of behavior into a separate object.
vsg
"How about design patterns?" - Yes, many design patterns break OOP (many don't though), and like said a few times already OOP is not something that should be blindly used everywhere. If using certain design pattern brings you important advantages, OOP principles can and must be bended and violated. My very answer that started those comments describes one such situation.
ima
" I'm arguing that if there is a GOD object, it should be broken down into smaller objects." Yes"This can be achieved in some cases by "outsourcing" part of behavior into a separate object." Can - yes, should - absolutely no. Unless this behavior is logically generic and independent, analyze GOD object and find another way to break it down in smaller objects. Besides, you should not _design_ GOD objects in the first place, not try to deal with them afterwards.
ima
More on GOD objects, if you just break certain methods into separate class, you are not dealing with the problem, you are sweeping it under the carpet. The GOD object is still there, only some of it's methods now have another prefix.
ima
Ok then, let me sum it up. There are OOP principles (obj=data+methods, etc.). In most usual cases they should be followed. But, there are cases when they could be violated. E.g. design patterns, or breaking objects for better maintainability. Will we agree on that? The very first my comment was about big bold "only" word in your answer, then I gave a specific (not usual, or at least should not be usual) example of breaking a big object for maintainability. You were arguing one should never ever use only-behavior objects, except of the case you mentioned in the answer. Is that correct?
vsg
"Can - yes, should - absolutely no. Unless this behavior is logically generic and independent." This was the thing I wanted to hear. That's concerning the "only". Never say never.
vsg
"OOP principles... violated... for breaking objects for better maintainability" - No we won't agree on that point. OOP itself strongly discourages big objects, so there is never need to violate it for that purpose. If you end up with big objects after OO design, fix your design instead of splitting objects. "Can - yes, should - absolutely no. " - my original answer has "Should only be implemented..." Don't you think those two phrases mean the same thing? Anyway, this site is awful for discussions, so I'd say it's time to can this one.
ima
I would not argue if the "should" was as big and bold as the "only". Also from your answer one could conclude that violating OOP is something absolutely inexcusable, which turned to be not so during discussion. And I didn't say that separated from the big object behavior should not be "logically generic and independent". I just made a counter-example. "I'd say it's time to can this one." - agree.
vsg
An interesting pattern - every comment (both yours and mine) becomes correct if you add more details. I guess that's how holy wars appear :)
vsg
Looks like you missed not just "should", but also "unwarranted". Reading is important.
ima
Sorry, I'm not a native English speaker. Does "should be implemented ... only if it is generic ..." mean "should be implemented ... if it is generic ... and in some other cases"?
vsg
I understand that "should be implemented only if X" is same as "should not be implemented if not X". This wouldn't be true without the "only". Please, correct me if I wrong.
vsg
Also consider a builder pattern. To be precise, it doesn't also require behavior-only implementation, but it often is. Often, its only state is the reference to the object being built. Its implementation is non-generic. That's one more counter-example. I don't argue that one should do behavior-only objects whenever he likes, but it is completely Ok to do so, if the behavior is logically independent.
vsg
If you want to know how patterns are applied, read a book.
ima