task1.setStartDate(new Date("1 Jan 98"); task2.setStartDate(task1.getTaskDate()); //then somewhere in the task class void delay(int delayDays) { _startDate.setDate(_startDate.getDate() + delayDays); }and now you find task1's start date has changed.// then somewhere task2.delay(5);
This is doubly nasty because it is really hard to find the cause of the trouble.
So if you design an object that should be a value object, don't provide any methods that change its state, ie make it immutable.
Users will have to write
void delay(int delayDays) { _startDate := (new Date(_startDate.getYear(), _startDate.getMonth(), _startDate.getDate + delayDays); }If you are using a ValueObject that is mutable, treat it like it is immutable. You may not realize why, but you will save a lot of time and money.
-- MartinFowler
I have observed another manifestation of this in Java:
Problem: Returning an object by means of an accessor method. You intend to return a value but you return a Java object reference.
Symptoms: the client object is given a reference to an attribute. This attribute may have been declared private. The client of the class could invoke methods through this reference to change the value of the attribute.
Solution: The accessor method returns a copy of the attribute and not a reference to the attribute itself.
(See [http://www.drst.demon.co.uk/soft/java/index.html#References] (for a concrete example) and ReturnNewObjectsFromAccessorMethods for further details. (Also of interest: JavaIdioms.)
I'm not convinced ValueObject classes are classes at all since:
-- DafyddRees
This doesn't make any sense to me. The way that Java models an AbstractDataType is with a class. "Class" is a language feature in Java, while AbstractDataType is not. So, how can you choose to model anything as an AbstractDataType?
Further, it is very useful to model an AbstractDataType as a class, because that way you get polymorphism for free. Sometimes inheritance is useful, too. As a long-time Smalltalker, I realize that it is a little funny to use the same language mechanism to represent integers and customers, but there are advantages to having as few mechanisms as possible, and there are some fairly simple idioms for implementing a ValueObject, so I long ago decided that it was unnecessary to have two language mechanisms, one for objects and one for AbstractDataType.
-- RalphJohnson
To make things clearer, I should have pointed out that I'm talking about conceptual models rather than code.
There are types in Java that behave like ADTs. Consider the primitive data types (i.e. boolean, char, byte, short, int, long, float and double), for example: they have values, the values can be related using constants and side-effect free functions. Above all, their (logical) states can't be changed.
This use of ADTs fits well with the attributes allowed in the Class Diagrams of OMT and the FusionMethodology. (Especially since you are told in the OMT book (ISBN 0136298419 ) that attributes in OOA class diagrams are types of "pure data values" rather than other objects.)
Hope that helps.
-- DafyddRees
How does SmalltalkLanguage handle ValueObjects? For example integers, boolean values. How are these defined? (What other classes make up their definition?)
-- DafyddRees
SmallIntegers? are primitives in Smalltalk. Although there is a class SmallInteger, you can't subclass it and a lot of the methods can't be changed. On the other hand, Boolean, True and False are just normal Smalltalk classes. Moreover, I consider classes like Date and Fraction to be ValueObjects, too. To me, a ValueObject is not a language feature, it is a design feature. I call an object a ValueObject when I want to treat it like a value, and that means making it be immutable. It is theoretically possible to modify a Date or a Fraction, though I've never seen it done, so in practice they are immutable. Point should also be immutable, though I've seen a Point modified. It shouldn't be; if you want a Point with a different value, make a new one. The problem with Point is that it has an x: and a y: message that lets you change its value. Those methods should be deleted and the only way you should be able to set those fields is to create a new object.
-- RalphJohnson
It is interesting to note that the classic CircleAndEllipseProblem is a variation on the same theme. Ellipses that can be modified really represent the mathematical notion of a family of ellipses rather than a single concrete instance. -- MichaelFeathers
It is even more interesting that constness hasn't been brought up in this discussion at all.
This page mirrored in JavaIdioms as of April 29, 2006