Skip to content

Value object pattern #349 #362

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Feb 5, 2016
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions front-controller/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ layout: pattern
title: Front Controller
folder: front-controller
permalink: /patterns/front-controller/
categories: Presentation Tier
categories: Creational
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to change this file?

tags:
- Java
- Difficulty-Intermediate
---

## Intent
Introduce a common handler for all requests for a web site. This
Introduce how to create objects which follow value semantics rather than reference semantics.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to change this?

way we can encapsulate common functionality such as security,
internationalization, routing and logging in a single place.

Expand Down
17 changes: 9 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
<module>publish-subscribe</module>
<module>delegation</module>
<module>event-driven-architecture</module>
<module>value-object</module>
</modules>

<dependencyManagement>
Expand Down Expand Up @@ -172,8 +173,8 @@
<build>
<pluginManagement>
<plugins>
<!-- This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. TODO: Remove when the
<!-- This plugin's configuration is used to store Eclipse m2e settings
only. It has no influence on the Maven build itself. TODO: Remove when the
m2e plugin can correctly bind to Maven lifecycle -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
Expand Down Expand Up @@ -229,10 +230,10 @@
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.version}</version>
<!-- The following exclude configuration was added because error occurred
<!-- The following exclude configuration was added because error occurred
when executing "mvn clean test jacoco:report coveralls:report" -->
<!-- [ERROR] Failed to execute goal org.eluder.coveralls:coveralls-maven-plugin:3.1.0:report
(default-cli) on project java-design-patterns: I/O operation failed: No source
<!-- [ERROR] Failed to execute goal org.eluder.coveralls:coveralls-maven-plugin:3.1.0:report
(default-cli) on project java-design-patterns: I/O operation failed: No source
found for domainapp/dom/modules/simple/QSimpleObject.java -> [Help 1] -->
<configuration>
<excludes>
Expand Down Expand Up @@ -327,8 +328,8 @@
<excludeFromFailureFile>exclude-pmd.properties</excludeFromFailureFile>
</configuration>
</execution>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why these blanks exist and make differences in this file. I only added one line value-object.

</executions>
</plugin>
</executions>
</plugin>
</plugins>
</build>

Expand All @@ -341,5 +342,5 @@
</plugin>
</plugins>
</reporting>

</project>
Binary file added value-object/etc/value-object.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions value-object/etc/value-object.ucls
Original file line number Diff line number Diff line change
@@ -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 changes: 34 additions & 0 deletions value-object/index.md
Original file line number Diff line number Diff line change
@@ -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.

![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

## 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 changes: 30 additions & 0 deletions value-object/pom.xml
Original file line number Diff line number Diff line change
@@ -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.10.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>
19 changes: 19 additions & 0 deletions value-object/src/main/java/com/iluwatar/value/object/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.iluwatar.value.object;

/**
* App Class.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe the pattern and the example here. For reference, see other pattern examples.

*
*/
public class App {
/**
* main method.
*/
public static void main(String[] args) {
HeroStat statA = HeroStat.valueOf(10, 5, 0);
HeroStat statB = HeroStat.valueOf(5, 1, 8);

System.out.println(statA.toString());
// When using Value Objects do not use ==, only compare using equals().
System.out.println("is statA and statB equal : " + statA.equals(statB));
}
}
99 changes: 99 additions & 0 deletions value-object/src/main/java/com/iluwatar/value/object/HeroStat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.iluwatar.value.object;

/**
* HeroStat is a Value Object. following rules are from Stephen Colebourne's term VALJO(not the
* entire rule set) from : http://blog.joda.org/2014/03/valjos-value-java-objects.html<br>
* Value Objects must override equals(), hashCode() to check the equality with values. <br>
* Value Objects should be immutable so declare members final. Obtain instances by static factory
* methods. <br>
* The elements of the state must be other values, including primitive types.<br>
* Provide methods, typically simple getters, to get the elements of the state.<br>
*
* {@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 Juice 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

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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.
*
* @see http://www.javadoc.io/doc/com.google.guava/guava-testlib/19.0
*/
@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())));


}

}