-
-
Notifications
You must be signed in to change notification settings - Fork 27k
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
Changes from 4 commits
64b89ec
cca40a5
083065b
d3eb8a2
3ef4649
0e7fae2
d837891
1e5cbe1
0498412
db2140e
f71e186
8353354
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,14 +3,14 @@ layout: pattern | |
title: Front Controller | ||
folder: front-controller | ||
permalink: /patterns/front-controller/ | ||
categories: Presentation Tier | ||
categories: Creational | ||
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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,6 +93,7 @@ | |
<module>publish-subscribe</module> | ||
<module>delegation</module> | ||
<module>event-driven-architecture</module> | ||
<module>value-object</module> | ||
</modules> | ||
|
||
<dependencyManagement> | ||
|
@@ -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> | ||
|
@@ -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> | ||
|
@@ -327,8 +328,8 @@ | |
<excludeFromFailureFile>exclude-pmd.properties</excludeFromFailureFile> | ||
</configuration> | ||
</execution> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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> | ||
|
||
|
@@ -341,5 +342,5 @@ | |
</plugin> | ||
</plugins> | ||
</reporting> | ||
|
||
</project> |
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> |
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. | ||
|
||
 | ||
|
||
## 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) |
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> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.iluwatar.value.object; | ||
|
||
/** | ||
* App Class. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)); | ||
} | ||
} |
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()))); | ||
|
||
|
||
} | ||
|
||
} |
There was a problem hiding this comment.
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?