1
pom.xml
1
pom.xml
@ -120,6 +120,7 @@
|
||||
<module>delegation</module>
|
||||
<module>event-driven-architecture</module>
|
||||
<module>feature-toggle</module>
|
||||
<module>value-object</module>
|
||||
</modules>
|
||||
|
||||
<dependencyManagement>
|
||||
|
BIN
value-object/etc/value-object.png
Normal file
BIN
value-object/etc/value-object.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.9 KiB |
19
value-object/etc/value-object.ucls
Normal file
19
value-object/etc/value-object.ucls
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<class-diagram version="1.1.9" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
||||
realizations="true" associations="true" dependencies="true" nesting-relationships="true" router="FAN">
|
||||
<class id="1" language="java" name="com.iluwatar.value.object.HeroStat" project="value-object"
|
||||
file="/value-object/src/main/java/com/iluwatar/value/object/HeroStat.java" binary="false" corner="BOTTOM_RIGHT">
|
||||
<position height="-1" width="-1" x="520" y="337"/>
|
||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</display>
|
||||
</class>
|
||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||
sort-features="false" accessors="true" visibility="true">
|
||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||
</classifier-display>
|
||||
<association-display labels="true" multiplicity="true"/>
|
||||
</class-diagram>
|
34
value-object/index.md
Normal file
34
value-object/index.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
layout: pattern
|
||||
title: Value Object
|
||||
folder: value-object
|
||||
permalink: /patterns/value-object/
|
||||
categories: Creational
|
||||
tags:
|
||||
- Java
|
||||
- Difficulty-Beginner
|
||||
---
|
||||
|
||||
## 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
|
||||
equal when they have the same value, not necessarily being the same object.
|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
Use the Value Object when
|
||||
|
||||
* you need to measure the objects' equality based on the objects' value
|
||||
|
||||
## Real world examples
|
||||
|
||||
* [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)
|
||||
* [joda-time, money, beans](http://www.joda.org/)
|
||||
|
||||
## Credits
|
||||
|
||||
* [Patterns of Enterprise Application Architecture](http://www.martinfowler.com/books/eaa.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)
|
30
value-object/pom.xml
Normal file
30
value-object/pom.xml
Normal file
@ -0,0 +1,30 @@
|
||||
<?xml version="1.0"?>
|
||||
<project
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>com.iluwatar</groupId>
|
||||
<artifactId>java-design-patterns</artifactId>
|
||||
<version>1.11.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>value-object</artifactId>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-testlib</artifactId>
|
||||
<version>19.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@ -0,0 +1,32 @@
|
||||
package com.iluwatar.value.object;
|
||||
|
||||
/**
|
||||
* A Value Object are objects which follow value semantics rather than reference semantics. This
|
||||
* means value objects' equality are not based on identity. Two value objects are equal when they
|
||||
* have the same value, not necessarily being the same object..
|
||||
*
|
||||
* Value Objects must override equals(), hashCode() to check the equality with values.
|
||||
* Value Objects should be immutable so declare members final.
|
||||
* Obtain instances by static factory methods.
|
||||
* The elements of the state must be other values, including primitive types.
|
||||
* Provide methods, typically simple getters, to get the elements of the state.
|
||||
* A Value Object must check equality with equals() not ==
|
||||
*
|
||||
* For more specific and strict rules to implement value objects check the rules from Stephen
|
||||
* Colebourne's term VALJO : http://blog.joda.org/2014/03/valjos-value-java-objects.html
|
||||
*/
|
||||
public class App {
|
||||
/**
|
||||
* This practice creates three HeroStats(Value object) and checks equality between those.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
HeroStat statA = HeroStat.valueOf(10, 5, 0);
|
||||
HeroStat statB = HeroStat.valueOf(10, 5, 0);
|
||||
HeroStat statC = HeroStat.valueOf(5, 1, 8);
|
||||
|
||||
System.out.println(statA.toString());
|
||||
|
||||
System.out.println("Is statA and statB equal : " + statA.equals(statB));
|
||||
System.out.println("Is statA and statC equal : " + statA.equals(statC));
|
||||
}
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package com.iluwatar.value.object;
|
||||
|
||||
/**
|
||||
* HeroStat is a value object
|
||||
*
|
||||
* {@link http://docs.oracle.com/javase/8/docs/api/java/lang/doc-files/ValueBased.html}
|
||||
*/
|
||||
public class HeroStat {
|
||||
|
||||
// Stats for a hero
|
||||
|
||||
private final int strength;
|
||||
private final int intelligence;
|
||||
private final int luck;
|
||||
|
||||
// All constructors must be private.
|
||||
private HeroStat(int strength, int intelligence, int luck) {
|
||||
super();
|
||||
this.strength = strength;
|
||||
this.intelligence = intelligence;
|
||||
this.luck = luck;
|
||||
}
|
||||
|
||||
// Static factory method to create new instances.
|
||||
public static HeroStat valueOf(int strength, int intelligence, int luck) {
|
||||
return new HeroStat(strength, intelligence, luck);
|
||||
}
|
||||
|
||||
public int getStrength() {
|
||||
return strength;
|
||||
}
|
||||
|
||||
public int getIntelligence() {
|
||||
return intelligence;
|
||||
}
|
||||
|
||||
public int getLuck() {
|
||||
return luck;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recommended to provide a static factory method capable of creating an instance from the formal
|
||||
* string representation declared like this. public static HeroStat parse(String string) {}
|
||||
*/
|
||||
|
||||
// toString, hashCode, equals
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HeroStat [strength=" + strength + ", intelligence=" + intelligence
|
||||
+ ", luck=" + luck + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + intelligence;
|
||||
result = prime * result + luck;
|
||||
result = prime * result + strength;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
HeroStat other = (HeroStat) obj;
|
||||
if (intelligence != other.intelligence) {
|
||||
return false;
|
||||
}
|
||||
if (luck != other.luck) {
|
||||
return false;
|
||||
}
|
||||
if (strength != other.strength) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// The clone() method should not be public. Just don't override it.
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.iluwatar.value.object;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Application test
|
||||
*/
|
||||
public class AppTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
String[] args = {};
|
||||
App.main(args);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.iluwatar.value.object;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import com.google.common.testing.EqualsTester;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit test for HeroStat.
|
||||
*/
|
||||
public class HeroStatTest {
|
||||
|
||||
/**
|
||||
* Tester for equals() and hashCode() methods of a class. Using guava's EqualsTester.
|
||||
*
|
||||
* @see http://static.javadoc.io/com.google.guava/guava-testlib/19.0/com/google/common/testing/
|
||||
* EqualsTester.html
|
||||
*/
|
||||
@Test
|
||||
public void testEquals() {
|
||||
HeroStat heroStatA = HeroStat.valueOf(3, 9, 2);
|
||||
HeroStat heroStatB = HeroStat.valueOf(3, 9, 2);
|
||||
new EqualsTester().addEqualityGroup(heroStatA, heroStatB).testEquals();
|
||||
}
|
||||
|
||||
/**
|
||||
* The toString() for two equal values must be the same. For two non-equal values it must be
|
||||
* different.
|
||||
*/
|
||||
@Test
|
||||
public void testToString() {
|
||||
HeroStat heroStatA = HeroStat.valueOf(3, 9, 2);
|
||||
HeroStat heroStatB = HeroStat.valueOf(3, 9, 2);
|
||||
HeroStat heroStatC = HeroStat.valueOf(3, 9, 8);
|
||||
|
||||
assertThat(heroStatA.toString(), is(heroStatB.toString()));
|
||||
assertThat(heroStatA.toString(), is(not(heroStatC.toString())));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user