October 20th, 2008

Introduction

The Value Object pattern has, just like the Singleton, to do with referencing and instances. In a way, the Value Object is the opposite of the Singleton: its goal is to ensure NOT to use the same instance, under certain conditions.

Problem

How to prevent that objects serving as containers to certain values are unintentionally reused instead of re-instantiated.

If you have read OO PHP Part 1, you probably remember Snoopy and Lassie being attached at the mouth. It is because PHP 5 uses handles instead of copying every object like PHP 4 does that the Teeth property of Lassie wasn’t duplicated, causing both dogs’ Teeth property to refer to the same Teeth object.

This is essentially what you are trying to avoid when implementing the Value Object Pattern.

Solution

In Patterns of Enterprise Application Architecture, Martin Fowler makes a clear distinction between ‘reference objects’ and ‘Value Objects’. His short definition of a Value Object:

“A small simple object, like a money or date range, whose equality is not based on identity.”

The key being the equality. Normally, all objects persist and have their own identity, ignorant to equality of their content. An object should be a Value Object if it it’s equality is not based on identity, but on it’s ‘value’. If it is safe to equal óne hundred kudos to another hundred kudos, a Value Object – possibly called ‘Kudos’ – is warranted.

The below code is a scenario in which a Value Object is needed:

  1. /**
  2. * A toolbox. Unfortunately we only carry nails.
  3. *
  4. */
  5. class ToolBox
  6. {
  7. /**
  8. * A Nails object
  9. *
  10. * @var Nails
  11. */
  12. private $_nails;
  13. /**
  14. * Get the nails
  15. *
  16. * @return Nails
  17. */
  18. public function getNails()
  19. {
  20. return $this->_nails;
  21. }
  22. /**
  23. * Set the nails
  24. *
  25. * @param Nails $nails
  26. */
  27. public function setNails(Nails $nails)
  28. {
  29. $this->_nails = $nails;
  30. }
  31. }
  32. /**
  33. * Object representing a quantity of nails
  34. *
  35. */
  36. class Nails
  37. {
  38. /**
  39. * The quantity of nails
  40. *
  41. * @var int
  42. */
  43. private $_quantity;
  44. /**
  45. * Constructor
  46. *
  47. * @param int $quantity
  48. */
  49. public function __construct($quantity)
  50. {
  51. $this->_quantity = (int) $quantity;
  52. }
  53. /**
  54. * Add some nails
  55. *
  56. * @param Nails $quantity
  57. */
  58. public function add(Nails $nails)
  59. {
  60. $this->_quantity += $nails->count();
  61. }
  62. /**
  63. * Get the nail-count
  64. *
  65. * @return int
  66. */
  67. public function count()
  68. {
  69. return $this->_quantity;
  70. }
  71. /**
  72. * Get a string representation
  73. *
  74. * @return string
  75. */
  76. private function __toString()
  77. {
  78. return (string) $this->_quantity;
  79. }
  80. }
  81. $myToolBox = new ToolBox;
  82. $yourToolBox = new ToolBox;
  83. //Using twenty Nails
  84. $twentyNails = new Nails(20);
  85. //Start out with equal number of nails.
  86. $myToolBox->setNails($twentyNails);
  87. $yourToolBox->setNails($twentyNails);
  88. //Here’s another 100 nails.
  89. $yourToolBox->getNails()->add(new Nails(100));
  90. echo “Your nails: {$yourToolBox->getNails()}<br/>”;
  91. echo “My nails: {$myToolBox->getNails()}<br/>”;

You probably already noticed that problem is that we are both using the same Nails object. In this case the problem may be easy to spot and avoid, but as your application becomes bigger, preventing this type of mishap can save you a huge headache. Another mayor benefit of using Value Objects is they enable you to encapsulate type-specific operations. Martin Fowler does a great job at demonstrating this with his Money pattern, which encapsulates the handling of rounding currency.

The key to creating Value Objects is making them immutable. Because Value Objects’ equality don’t depend on their identity, simply creating a new object when the value changes, accomplishes this:

  1. /**
  2. * Add some nails
  3. *
  4. * @param Nails $quantity
  5. */
  6. public function add(Nails $nails)
  7. {
  8. return new Nails($this->_quantity + $nails->count());
  9. }

Now that Nails is immutable, the client code needs to be adapted also. Since the value of the object in the $screws property can not be changed, we’ll have to reset it instead:

  1. //Here’s another 100 nails.
  2. $yourToolBox->setNails(
  3. $yourToolBox->getNails()->add(new Nails(100))
  4. );

That’s all there is to it.

There are no comments yet, add one below.

Leave a Comment


You must be logged in to post a comment.