From d2fab302cee35d64dd89a713a2d7dd3733e83f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Tue, 4 Jan 2022 20:36:57 +0200 Subject: [PATCH] Refactor and add explanation for value object --- value-object/README.md | 68 ++++++++++++++++++- .../java/com/iluwatar/value/object/App.java | 4 +- .../com/iluwatar/value/object/HeroStat.java | 28 ++------ 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/value-object/README.md b/value-object/README.md index 9b85d82b1..c98674381 100644 --- a/value-object/README.md +++ b/value-object/README.md @@ -10,19 +10,80 @@ tags: --- ## Intent + Provide objects which follow value semantics rather than reference semantics. -This means value objects' equality are not based on identity. Two value objects are +This means value objects' equality is not based on identity. Two value objects are equal when they have the same value, not necessarily being the same object. +## Explanation + +Real-world example + +> There is a class for hero statistics in a role-playing game. The statistics contain attributes +> such as strength, intelligence, and luck. The statistics of different heroes should be equal +> when all the attributes are equal. + +In plain words + +> Value objects are equal when their attributes have the same value + +Wikipedia says + +> In computer science, a value object is a small object that represents a simple entity whose +> equality is not based on identity: i.e. two value objects are equal when they have the same +> value, not necessarily being the same object. + +**Programmatic Example** + +Here is the `HeroStat` class that is the value object. Notice the use of +[Lombok's `@Value`](https://projectlombok.org/features/Value) annotation. + +```java +@Value(staticConstructor = "valueOf") +class HeroStat { + + int strength; + int intelligence; + int luck; +} +``` + +The example creates three different `HeroStat`s and compares their equality. + +```java +var statA = HeroStat.valueOf(10, 5, 0); +var statB = HeroStat.valueOf(10, 5, 0); +var statC = HeroStat.valueOf(5, 1, 8); + +LOGGER.info(statA.toString()); +LOGGER.info(statB.toString()); +LOGGER.info(statC.toString()); + +LOGGER.info("Is statA and statB equal : {}", statA.equals(statB)); +LOGGER.info("Is statA and statC equal : {}", statA.equals(statC)); +``` + +Here's the console output. + +``` +20:11:12.199 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0) +20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=10, intelligence=5, luck=0) +20:11:12.202 [main] INFO com.iluwatar.value.object.App - HeroStat(strength=5, intelligence=1, luck=8) +20:11:12.202 [main] INFO com.iluwatar.value.object.App - Is statA and statB equal : true +20:11:12.203 [main] INFO com.iluwatar.value.object.App - Is statA and statC equal : false +``` + ## Class diagram + ![alt text](./etc/value-object.png "Value Object") ## Applicability + Use the Value Object when -* You need to measure the objects' equality based on the objects' value +* The object's equality needs to be based on the object's value -## Real world examples +## Known uses * [java.util.Optional](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) * [java.time.LocalDate](https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html) @@ -31,6 +92,7 @@ Use the Value Object when ## Credits * [Patterns of Enterprise Application Architecture](http://www.martinfowler.com/books/eaa.html) +* [ValueObject](https://martinfowler.com/bliki/ValueObject.html) * [VALJOs - Value Java Objects : Stephen Colebourne's blog](http://blog.joda.org/2014/03/valjos-value-java-objects.html) * [Value Object : Wikipedia](https://en.wikipedia.org/wiki/Value_object) * [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) diff --git a/value-object/src/main/java/com/iluwatar/value/object/App.java b/value-object/src/main/java/com/iluwatar/value/object/App.java index 49375e94c..cc952fd47 100644 --- a/value-object/src/main/java/com/iluwatar/value/object/App.java +++ b/value-object/src/main/java/com/iluwatar/value/object/App.java @@ -43,7 +43,7 @@ import lombok.extern.slf4j.Slf4j; public class App { /** - * This practice creates three HeroStats(Value object) and checks equality between those. + * This example creates three HeroStats (value objects) and checks equality between those. */ public static void main(String[] args) { var statA = HeroStat.valueOf(10, 5, 0); @@ -51,6 +51,8 @@ public class App { var statC = HeroStat.valueOf(5, 1, 8); LOGGER.info(statA.toString()); + LOGGER.info(statB.toString()); + LOGGER.info(statC.toString()); LOGGER.info("Is statA and statB equal : {}", statA.equals(statB)); LOGGER.info("Is statA and statC equal : {}", statA.equals(statC)); diff --git a/value-object/src/main/java/com/iluwatar/value/object/HeroStat.java b/value-object/src/main/java/com/iluwatar/value/object/HeroStat.java index 4d060ee0f..4620b4e4a 100644 --- a/value-object/src/main/java/com/iluwatar/value/object/HeroStat.java +++ b/value-object/src/main/java/com/iluwatar/value/object/HeroStat.java @@ -23,10 +23,7 @@ package com.iluwatar.value.object; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.ToString; +import lombok.Value; /** * HeroStat is a value object. @@ -35,23 +32,10 @@ import lombok.ToString; * http://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html * */ -@Getter -@ToString -@EqualsAndHashCode -@RequiredArgsConstructor -public class HeroStat { - - // Stats for a hero - - private final int strength; - private final int intelligence; - private final int luck; - - // Static factory method to create new instances. - public static HeroStat valueOf(int strength, int intelligence, int luck) { - return new HeroStat(strength, intelligence, luck); - } - - // The clone() method should not be public. Just don't override it. +@Value(staticConstructor = "valueOf") +class HeroStat { + int strength; + int intelligence; + int luck; }