Skip to content

Commit 4f8007d

Browse files
iluwatarohbus
andauthored
enhancement: Refactor and add explanation for value object (#1942)
Co-authored-by: Subhrodip Mohanta <[email protected]>
1 parent 2d2dec9 commit 4f8007d

File tree

3 files changed

+74
-26
lines changed

3 files changed

+74
-26
lines changed

value-object/README.md

+65-3
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,80 @@ tags:
1010
---
1111

1212
## Intent
13+
1314
Provide objects which follow value semantics rather than reference semantics.
14-
This means value objects' equality are not based on identity. Two value objects are
15+
This means value objects' equality is not based on identity. Two value objects are
1516
equal when they have the same value, not necessarily being the same object.
1617

18+
## Explanation
19+
20+
Real-world example
21+
22+
> There is a class for hero statistics in a role-playing game. The statistics contain attributes
23+
> such as strength, intelligence, and luck. The statistics of different heroes should be equal
24+
> when all the attributes are equal.
25+
26+
In plain words
27+
28+
> Value objects are equal when their attributes have the same value
29+
30+
Wikipedia says
31+
32+
> In computer science, a value object is a small object that represents a simple entity whose
33+
> equality is not based on identity: i.e. two value objects are equal when they have the same
34+
> value, not necessarily being the same object.
35+
36+
**Programmatic Example**
37+
38+
Here is the `HeroStat` class that is the value object. Notice the use of
39+
[Lombok's `@Value`](https://projectlombok.org/features/Value) annotation.
40+
41+
```java
42+
@Value(staticConstructor = "valueOf")
43+
class HeroStat {
44+
45+
int strength;
46+
int intelligence;
47+
int luck;
48+
}
49+
```
50+
51+
The example creates three different `HeroStat`s and compares their equality.
52+
53+
```java
54+
var statA = HeroStat.valueOf(10, 5, 0);
55+
var statB = HeroStat.valueOf(10, 5, 0);
56+
var statC = HeroStat.valueOf(5, 1, 8);
57+
58+
LOGGER.info(statA.toString());
59+
LOGGER.info(statB.toString());
60+
LOGGER.info(statC.toString());
61+
62+
LOGGER.info("Is statA and statB equal : {}", statA.equals(statB));
63+
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));
64+
```
65+
66+
Here's the console output.
67+
68+
```
69+
20:11:12.199 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
70+
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0)
71+
20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=5, intelligence=1, luck=8)
72+
20:11:12.202 [main] INFO com.iluwatar.value.object.App - Is statA and statB equal : true
73+
20:11:12.203 [main] INFO com.iluwatar.value.object.App - Is statA and statC equal : false
74+
```
75+
1776
## Class diagram
77+
1878
![alt text](./etc/value-object.png "Value Object")
1979

2080
## Applicability
81+
2182
Use the Value Object when
2283

23-
* You need to measure the objects' equality based on the objects' value
84+
* The object's equality needs to be based on the object's value
2485

25-
## Real world examples
86+
## Known uses
2687

2788
* [java.util.Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html)
2889
* [java.time.LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html)
@@ -31,6 +92,7 @@ Use the Value Object when
3192
## Credits
3293

3394
* [Patterns of Enterprise Application Architecture](http://www.martinfowler.com/books/eaa.html)
95+
* [ValueObject](https://martinfowler.com/bliki/ValueObject.html)
3496
* [VALJOs - Value Java Objects : Stephen Colebourne's blog](http://blog.joda.org/2014/03/valjos-value-java-objects.html)
3597
* [Value Object : Wikipedia](https://en.wikipedia.org/wiki/Value_object)
3698
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94)

value-object/src/main/java/com/iluwatar/value/object/App.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,16 @@
4343
public class App {
4444

4545
/**
46-
* This practice creates three HeroStats(Value object) and checks equality between those.
46+
* This example creates three HeroStats (value objects) and checks equality between those.
4747
*/
4848
public static void main(String[] args) {
4949
var statA = HeroStat.valueOf(10, 5, 0);
5050
var statB = HeroStat.valueOf(10, 5, 0);
5151
var statC = HeroStat.valueOf(5, 1, 8);
5252

5353
LOGGER.info(statA.toString());
54+
LOGGER.info(statB.toString());
55+
LOGGER.info(statC.toString());
5456

5557
LOGGER.info("Is statA and statB equal : {}", statA.equals(statB));
5658
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));

value-object/src/main/java/com/iluwatar/value/object/HeroStat.java

+6-22
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323

2424
package com.iluwatar.value.object;
2525

26-
import lombok.EqualsAndHashCode;
27-
import lombok.Getter;
28-
import lombok.RequiredArgsConstructor;
29-
import lombok.ToString;
26+
import lombok.Value;
3027

3128
/**
3229
* HeroStat is a value object.
@@ -35,23 +32,10 @@
3532
* http://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html
3633
* </a>
3734
*/
38-
@Getter
39-
@ToString
40-
@EqualsAndHashCode
41-
@RequiredArgsConstructor
42-
public class HeroStat {
43-
44-
// Stats for a hero
45-
46-
private final int strength;
47-
private final int intelligence;
48-
private final int luck;
49-
50-
// Static factory method to create new instances.
51-
public static HeroStat valueOf(int strength, int intelligence, int luck) {
52-
return new HeroStat(strength, intelligence, luck);
53-
}
54-
55-
// The clone() method should not be public. Just don't override it.
35+
@Value(staticConstructor = "valueOf")
36+
class HeroStat {
5637

38+
int strength;
39+
int intelligence;
40+
int luck;
5741
}

0 commit comments

Comments
 (0)