Value Object is quite popular design pattern, but it can be messy to implement it well.
This is my implementation of value objects.
A Value Object is a simple entity in which equality is based on its value, not on the identity of the object.
Value objects from the definition should be immutable which means, you cant change them after creation.
You should not compare value object identity with another one. Instead of that just create a method,
which compare values included inside those objects.
WHEN TO USE THEM?
Value objects can resolve many problems inside your code:
- they group methods connected with some concrete data type inside one class,
- they help to remove duplication from your code,
- of course, PORO object created as a value object can be tested in easy way.
HOW IT WORKS?
Creating a value object is quite simple:
# frozen_string_literal: true
class Shape
SHAPES = {
"square" => "kwadrat",
"triangle" => "trojkat",
"circle" => "okrąg"
}.freeze
def initialize(name)
@name = name
end
def polish_name
SHAPES[@name]
end
def ==(other)
name == other.name
end
attr_reader :name
end
As you can see in the example above, value object can look like a simple PORO.
As i wrote before, you need to create a method which will compare values inside Value Object.
def ==(other)
name == other.name
end
Thanks to this method, we can compare 2 objects:
Shape.new("square") == Shape.new("square")
# => true
Shape.new("circle") == Shape.new("square")
# => false