Refactor and add explanation for value object
This commit is contained in:
parent
2679f7aa6f
commit
d2fab302ce
@ -10,19 +10,80 @@ tags:
|
|||||||
---
|
---
|
||||||
|
|
||||||
## Intent
|
## Intent
|
||||||
|
|
||||||
Provide objects which follow value semantics rather than reference semantics.
|
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.
|
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
|
## Class diagram
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
|
|
||||||
Use the Value Object when
|
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.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)
|
* [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
|
## Credits
|
||||||
|
|
||||||
* [Patterns of Enterprise Application Architecture](http://www.martinfowler.com/books/eaa.html)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
||||||
|
@ -43,7 +43,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
public class App {
|
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) {
|
public static void main(String[] args) {
|
||||||
var statA = HeroStat.valueOf(10, 5, 0);
|
var statA = HeroStat.valueOf(10, 5, 0);
|
||||||
@ -51,6 +51,8 @@ public class App {
|
|||||||
var statC = HeroStat.valueOf(5, 1, 8);
|
var statC = HeroStat.valueOf(5, 1, 8);
|
||||||
|
|
||||||
LOGGER.info(statA.toString());
|
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 statB equal : {}", statA.equals(statB));
|
||||||
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));
|
LOGGER.info("Is statA and statC equal : {}", statA.equals(statC));
|
||||||
|
@ -23,10 +23,7 @@
|
|||||||
|
|
||||||
package com.iluwatar.value.object;
|
package com.iluwatar.value.object;
|
||||||
|
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.Value;
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.ToString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HeroStat is a value object.
|
* 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
|
* http://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html
|
||||||
* </a>
|
* </a>
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Value(staticConstructor = "valueOf")
|
||||||
@ToString
|
class HeroStat {
|
||||||
@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.
|
|
||||||
|
|
||||||
|
int strength;
|
||||||
|
int intelligence;
|
||||||
|
int luck;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user