diff --git a/CONTRIBUTING.MD b/CONTRIBUTING.MD
new file mode 100644
index 000000000..39087fbf1
--- /dev/null
+++ b/CONTRIBUTING.MD
@@ -0,0 +1,4 @@
+This is great you have something to contribute!
+
+Before going any further please read the [wiki](https://github.com/iluwatar/java-design-patterns/wiki)
+with conventions and rules we used for this project.
diff --git a/README.md b/README.md
index ac3aadd67..f1ce0bfc7 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,10 @@
that smart and dearly wants an empty line before a heading to be able to
display it as such, e.g. website) -->
-# Design pattern samples in Java
+# Design patterns implemented in Java
[](https://travis-ci.org/iluwatar/java-design-patterns)
[](https://coveralls.io/r/iluwatar/java-design-patterns?branch=master)
-[](https://scan.coverity.com/projects/5634)
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
# Introduction
@@ -40,7 +39,7 @@ patterns by any of the following approaches
# How to contribute
-If you are willing to contribute to the project you will find the relevant information in our [developer wiki](https://github.com/iluwatar/java-design-patterns/wiki).
+If you are willing to contribute to the project you will find the relevant information in our [developer wiki](https://github.com/iluwatar/java-design-patterns/wiki). We will help you and answer your questions in the [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns).
# Credits
diff --git a/abstract-factory/index.md b/abstract-factory/index.md
index f824f7e0e..485599b98 100644
--- a/abstract-factory/index.md
+++ b/abstract-factory/index.md
@@ -7,26 +7,30 @@ categories: Creational
tags:
- Java
- Gang Of Four
+ - Difficulty-Intermediate
---
-**Also known as:** Kit
+## Also known as
+Kit
-**Intent:** Provide an interface for creating families of related or dependent
+## Intent
+Provide an interface for creating families of related or dependent
objects without specifying their concrete classes.

-**Applicability:** Use the Abstract Factory pattern when
+## Applicability
+Use the Abstract Factory pattern when
* a system should be independent of how its products are created, composed and represented
* a system should be configured with one of multiple families of products
* a family of related product objects is designed to be used together, and you need to enforce this constraint
* you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations
-**Real world examples:**
+## Real world examples
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml
index 1c1e40229..71ea6dc98 100644
--- a/abstract-factory/pom.xml
+++ b/abstract-factory/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTabstract-factory
diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
index 9a32a091a..cdde3bd8f 100644
--- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
+++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java
@@ -1,20 +1,18 @@
package com.iluwatar.abstractfactory;
-
/**
*
- * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that
- * have a common theme without specifying their concrete classes. In normal usage, the client
- * software creates a concrete implementation of the abstract factory and then uses the generic
- * interface of the factory to create the concrete objects that are part of the theme. The client
- * does not know (or care) which concrete objects it gets from each of these internal factories,
- * since it uses only the generic interfaces of their products. This pattern separates the details
- * of implementation of a set of objects from their general usage and relies on object composition,
- * as object creation is implemented in methods exposed in the factory interface.
+ * The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
+ * without specifying their concrete classes. In normal usage, the client software creates a concrete implementation of
+ * the abstract factory and then uses the generic interface of the factory to create the concrete objects that are part
+ * of the theme. The client does not know (or care) which concrete objects it gets from each of these internal
+ * factories, since it uses only the generic interfaces of their products. This pattern separates the details of
+ * implementation of a set of objects from their general usage and relies on object composition, as object creation is
+ * implemented in methods exposed in the factory interface.
*
- * The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and
- * its implementations ({@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both
- * concrete implementations to create a king, a castle and an army.
+ * The essence of the Abstract Factory pattern is a factory interface ({@link KingdomFactory}) and its implementations (
+ * {@link ElfKingdomFactory}, {@link OrcKingdomFactory}). The example uses both concrete implementations to create a
+ * king, a castle and an army.
*
*/
public class App {
@@ -23,11 +21,8 @@ public class App {
private Castle castle;
private Army army;
-
/**
* Creates kingdom
- *
- * @param factory
*/
public void createKingdom(final KingdomFactory factory) {
setKing(factory.createKing());
@@ -47,14 +42,6 @@ public class App {
return factory.createKing();
}
- Castle getCastle(final KingdomFactory factory) {
- return factory.createCastle();
- }
-
- Army getArmy(final KingdomFactory factory) {
- return factory.createArmy();
- }
-
public King getKing() {
return king;
}
@@ -62,6 +49,10 @@ public class App {
private void setKing(final King king) {
this.king = king;
}
+
+ Castle getCastle(final KingdomFactory factory) {
+ return factory.createCastle();
+ }
public Castle getCastle() {
return castle;
@@ -70,6 +61,10 @@ public class App {
private void setCastle(final Castle castle) {
this.castle = castle;
}
+
+ Army getArmy(final KingdomFactory factory) {
+ return factory.createArmy();
+ }
public Army getArmy() {
return army;
@@ -79,32 +74,32 @@ public class App {
this.army = army;
}
-
/**
* Program entry point
*
- * @param args command line args
+ * @param args
+ * command line args
*/
public static void main(String[] args) {
-
- App app = new App();
-
- System.out.println("Elf Kingdom");
- KingdomFactory elfKingdomFactory;
- elfKingdomFactory = app.getElfKingdomFactory();
- app.createKingdom(elfKingdomFactory);
- System.out.println(app.getArmy().getDescription());
- System.out.println(app.getCastle().getDescription());
- System.out.println(app.getKing().getDescription());
-
- System.out.println("\nOrc Kingdom");
- KingdomFactory orcKingdomFactory;
- orcKingdomFactory = app.getOrcKingdomFactory();
- app.createKingdom(orcKingdomFactory);
- System.out.println(app.getArmy().getDescription());
- System.out.println(app.getCastle().getDescription());
- System.out.println(app.getKing().getDescription());
-
+
+ App app = new App();
+
+ System.out.println("Elf Kingdom");
+ KingdomFactory elfKingdomFactory;
+ elfKingdomFactory = app.getElfKingdomFactory();
+ app.createKingdom(elfKingdomFactory);
+ System.out.println(app.getArmy().getDescription());
+ System.out.println(app.getCastle().getDescription());
+ System.out.println(app.getKing().getDescription());
+
+ System.out.println("\nOrc Kingdom");
+ KingdomFactory orcKingdomFactory;
+ orcKingdomFactory = app.getOrcKingdomFactory();
+ app.createKingdom(orcKingdomFactory);
+ System.out.println(app.getArmy().getDescription());
+ System.out.println(app.getCastle().getDescription());
+ System.out.println(app.getKing().getDescription());
+
}
-
+
}
diff --git a/adapter/index.md b/adapter/index.md
index 7c7dc15e5..4263eb322 100644
--- a/adapter/index.md
+++ b/adapter/index.md
@@ -7,26 +7,30 @@ categories: Structural
tags:
- Java
- Gang Of Four
+ - Difficulty-Beginner
---
-**Also known as:** Wrapper
+## Also known as
+Wrapper
-**Intent:** Convert the interface of a class into another interface the clients
+## Intent
+Convert the interface of a class into another interface the clients
expect. Adapter lets classes work together that couldn't otherwise because of
incompatible interfaces.

-**Applicability:** Use the Adapter pattern when
+## Applicability
+Use the Adapter pattern when
* you want to use an existing class, and its interface does not match the one you need
* you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces
* you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.
-**Real world examples:**
+## Real world examples
* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/adapter/pom.xml b/adapter/pom.xml
index 2b67e4d53..736ce16ec 100644
--- a/adapter/pom.xml
+++ b/adapter/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTadapter
diff --git a/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
index 98c7cee2d..9fce02a3c 100644
--- a/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
+++ b/adapter/src/test/java/com/iluwatar/adapter/AdapterPatternTest.java
@@ -1,18 +1,13 @@
package com.iluwatar.adapter;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import java.util.HashMap;
-import java.util.Map;
-
import org.junit.Before;
import org.junit.Test;
-import com.iluwatar.adapter.BattleFishingBoat;
-import com.iluwatar.adapter.BattleShip;
-import com.iluwatar.adapter.Captain;
-import com.iluwatar.adapter.FishingBoat;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
/**
* Test class
diff --git a/async-method-invocation/index.md b/async-method-invocation/index.md
index dfcee0208..93c0249d9 100644
--- a/async-method-invocation/index.md
+++ b/async-method-invocation/index.md
@@ -4,24 +4,29 @@ title: Async Method Invocation
folder: async-method-invocation
permalink: /patterns/async-method-invocation/
categories: Concurrency
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Functional
---
-**Intent:** Asynchronous method invocation is pattern where the calling thread
+## Intent
+Asynchronous method invocation is pattern where the calling thread
is not blocked while waiting results of tasks. The pattern provides parallel
processing of multiple independent tasks and retrieving the results via
callbacks or waiting until everything is done.

-**Applicability:** Use async method invocation pattern when
+## Applicability
+Use async method invocation pattern when
* you have multiple independent tasks that can run in parallel
* you need to improve the performance of a group of sequential tasks
* you have limited amount of processing capacity or long running tasks and the
caller should not wait the tasks to be ready
-**Real world examples:**
+## Real world examples
* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html), [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) and [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) (Java)
* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx) (.NET)
diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml
index de81eb0b7..3f2a62aee 100644
--- a/async-method-invocation/pom.xml
+++ b/async-method-invocation/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTasync-method-invocation
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
index 0b8ee3649..6f2d4a8fc 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/App.java
@@ -4,24 +4,23 @@ import java.util.concurrent.Callable;
/**
* This application demonstrates the async method invocation pattern. Key parts of the pattern are
- * AsyncResult which is an intermediate container for an asynchronously evaluated
- * value, AsyncCallback which can be provided to be executed on task completion and
- * AsyncExecutor that manages the execution of the async tasks.
+ * AsyncResult which is an intermediate container for an asynchronously evaluated value,
+ * AsyncCallback which can be provided to be executed on task completion and AsyncExecutor
+ * that manages the execution of the async tasks.
*
- * The main method shows example flow of async invocations. The main thread starts multiple tasks
- * with variable durations and then continues its own work. When the main thread has done it's job
- * it collects the results of the async tasks. Two of the tasks are handled with callbacks, meaning
- * the callbacks are executed immediately when the tasks complete.
+ * The main method shows example flow of async invocations. The main thread starts multiple tasks with variable
+ * durations and then continues its own work. When the main thread has done it's job it collects the results of the
+ * async tasks. Two of the tasks are handled with callbacks, meaning the callbacks are executed immediately when the
+ * tasks complete.
*
- * Noteworthy difference of thread usage between the async results and callbacks is that the async
- * results are collected in the main thread but the callbacks are executed within the worker
- * threads. This should be noted when working with thread pools.
+ * Noteworthy difference of thread usage between the async results and callbacks is that the async results are collected
+ * in the main thread but the callbacks are executed within the worker threads. This should be noted when working with
+ * thread pools.
*
- * Java provides its own implementations of async method invocation pattern. FutureTask,
- * CompletableFuture and ExecutorService are the real world implementations of this pattern. But due
- * to the nature of parallel programming, the implementations are not trivial. This example does not
- * take all possible scenarios into account but rather provides a simple version that helps to
- * understand the pattern.
+ * Java provides its own implementations of async method invocation pattern. FutureTask, CompletableFuture and
+ * ExecutorService are the real world implementations of this pattern. But due to the nature of parallel programming,
+ * the implementations are not trivial. This example does not take all possible scenarios into account but rather
+ * provides a simple version that helps to understand the pattern.
*
* @see AsyncResult
* @see AsyncCallback
@@ -33,6 +32,9 @@ import java.util.concurrent.Callable;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) throws Exception {
// construct a new executor that will run async tasks
AsyncExecutor executor = new ThreadAsyncExecutor();
@@ -41,10 +43,8 @@ public class App {
AsyncResult asyncResult1 = executor.startProcess(lazyval(10, 500));
AsyncResult asyncResult2 = executor.startProcess(lazyval("test", 300));
AsyncResult asyncResult3 = executor.startProcess(lazyval(50L, 700));
- AsyncResult asyncResult4 =
- executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
- AsyncResult asyncResult5 =
- executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
+ AsyncResult asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
+ AsyncResult asyncResult5 = executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
// emulate processing in the current thread while async tasks are running in their own threads
Thread.sleep(350); // Oh boy I'm working hard here
@@ -66,8 +66,10 @@ public class App {
/**
* Creates a callable that lazily evaluates to given value with artificial delay.
*
- * @param value value to evaluate
- * @param delayMillis artificial delay in milliseconds
+ * @param value
+ * value to evaluate
+ * @param delayMillis
+ * artificial delay in milliseconds
* @return new callable for lazy evaluation
*/
private static Callable lazyval(T value, long delayMillis) {
@@ -81,7 +83,8 @@ public class App {
/**
* Creates a simple callback that logs the complete status of the async result.
*
- * @param name callback name
+ * @param name
+ * callback name
* @return new async callback
*/
private static AsyncCallback callback(String name) {
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
index 6d77df8ec..d64180dad 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/AsyncResult.java
@@ -5,8 +5,6 @@ import java.util.concurrent.ExecutionException;
/**
*
* AsyncResult interface
- *
- * @param
*/
public interface AsyncResult {
diff --git a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
index 300934562..6e86b26e4 100644
--- a/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
+++ b/async-method-invocation/src/main/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutor.java
@@ -29,13 +29,12 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
} catch (Exception ex) {
result.setException(ex);
}
- }, "executor-" + idx.incrementAndGet()).start();
+ } , "executor-" + idx.incrementAndGet()).start();
return result;
}
@Override
- public T endProcess(AsyncResult asyncResult) throws ExecutionException,
- InterruptedException {
+ public T endProcess(AsyncResult asyncResult) throws ExecutionException, InterruptedException {
if (asyncResult.isCompleted()) {
return asyncResult.getValue();
} else {
@@ -45,9 +44,8 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
}
/**
- * Simple implementation of async result that allows completing it successfully with a value or
- * exceptionally with an exception. A really simplified version from its real life cousins
- * FutureTask and CompletableFuture.
+ * Simple implementation of async result that allows completing it successfully with a value or exceptionally with an
+ * exception. A really simplified version from its real life cousins FutureTask and CompletableFuture.
*
* @see java.util.concurrent.FutureTask
* @see java.util.concurrent.CompletableFuture
@@ -71,10 +69,11 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
}
/**
- * Sets the value from successful execution and executes callback if available. Notifies any
- * thread waiting for completion.
+ * Sets the value from successful execution and executes callback if available. Notifies any thread waiting for
+ * completion.
*
- * @param value value of the evaluated task
+ * @param value
+ * value of the evaluated task
*/
void setValue(T value) {
this.value = value;
@@ -86,10 +85,11 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
}
/**
- * Sets the exception from failed execution and executes callback if available. Notifies any
- * thread waiting for completion.
+ * Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for
+ * completion.
*
- * @param exception exception of the failed task
+ * @param exception
+ * exception of the failed task
*/
void setException(Exception exception) {
this.exception = exception;
@@ -102,7 +102,7 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
@Override
public boolean isCompleted() {
- return (state > RUNNING);
+ return state > RUNNING;
}
@Override
diff --git a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
index 440e47552..c9d222e55 100644
--- a/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
+++ b/async-method-invocation/src/test/java/com/iluwatar/async/method/invocation/ThreadAsyncExecutorTest.java
@@ -8,19 +8,9 @@ import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
import static org.mockito.internal.verification.VerificationModeFactory.times;
/**
@@ -55,8 +45,7 @@ public class ThreadAsyncExecutorTest {
}
/**
- * Test used to verify the happy path of
- * {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
*/
@Test(timeout = 3000)
public void testSuccessfulTaskWithCallback() throws Exception {
@@ -77,8 +66,7 @@ public class ThreadAsyncExecutorTest {
verify(task, times(1)).call();
// ... same for the callback, we expect our object
- final ArgumentCaptor> optionalCaptor = ArgumentCaptor
- .forClass((Class) Optional.class);
+ final ArgumentCaptor> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
final Optional optionalException = optionalCaptor.getValue();
@@ -90,8 +78,8 @@ public class ThreadAsyncExecutorTest {
}
/**
- * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a
- * task takes a while to execute
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
+ * to execute
*/
@Test(timeout = 5000)
public void testLongRunningTaskWithoutCallback() throws Exception {
@@ -111,8 +99,7 @@ public class ThreadAsyncExecutorTest {
try {
asyncResult.getValue();
- fail(
- "Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
+ fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
@@ -130,9 +117,8 @@ public class ThreadAsyncExecutorTest {
}
/**
- * Test used to verify the happy path of
- * {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task takes a while to
- * execute
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
+ * takes a while to execute
*/
@Test(timeout = 5000)
public void testLongRunningTaskWithCallback() throws Exception {
@@ -155,8 +141,7 @@ public class ThreadAsyncExecutorTest {
try {
asyncResult.getValue();
- fail(
- "Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
+ fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
@@ -164,8 +149,7 @@ public class ThreadAsyncExecutorTest {
// Our task should only execute once, but it can take a while ...
verify(task, timeout(3000).times(1)).call();
- final ArgumentCaptor> optionalCaptor = ArgumentCaptor
- .forClass((Class) Optional.class);
+ final ArgumentCaptor> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
final Optional optionalException = optionalCaptor.getValue();
@@ -182,9 +166,8 @@ public class ThreadAsyncExecutorTest {
}
/**
- * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a
- * task takes a while to execute, while waiting on the result using
- * {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
+ * Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
+ * to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
*/
@Test(timeout = 5000)
public void testEndProcess() throws Exception {
@@ -204,8 +187,7 @@ public class ThreadAsyncExecutorTest {
try {
asyncResult.getValue();
- fail(
- "Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
+ fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
} catch (IllegalStateException e) {
assertNotNull(e.getMessage());
}
@@ -220,8 +202,7 @@ public class ThreadAsyncExecutorTest {
}
/**
- * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when
- * the callable is 'null'
+ * Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when the callable is 'null'
*/
@Test(timeout = 3000)
public void testNullTask() throws Exception {
@@ -229,8 +210,7 @@ public class ThreadAsyncExecutorTest {
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
final AsyncResult
*
*/
-public class DBManager {
+public class DbManager {
private static MongoClient mongoClient;
private static MongoDatabase db;
@@ -29,21 +29,34 @@ public class DBManager {
private static HashMap virtualDB;
- public static void createVirtualDB() {
+ private DbManager() {
+ }
+
+ /**
+ * Create DB
+ */
+ public static void createVirtualDb() {
useMongoDB = false;
virtualDB = new HashMap();
}
+ /**
+ * Connect to DB
+ */
public static void connect() throws ParseException {
useMongoDB = true;
mongoClient = new MongoClient();
db = mongoClient.getDatabase("test");
}
- public static UserAccount readFromDB(String userID) {
+ /**
+ * Read user account from DB
+ */
+ public static UserAccount readFromDb(String userId) {
if (!useMongoDB) {
- if (virtualDB.containsKey(userID))
- return virtualDB.get(userID);
+ if (virtualDB.containsKey(userId)) {
+ return virtualDB.get(userId);
+ }
return null;
}
if (null == db) {
@@ -54,18 +67,22 @@ public class DBManager {
}
}
FindIterable iterable =
- db.getCollection("user_accounts").find(new Document("userID", userID));
- if (iterable == null)
+ db.getCollection("user_accounts").find(new Document("userID", userId));
+ if (iterable == null) {
return null;
+ }
Document doc = iterable.first();
UserAccount userAccount =
- new UserAccount(userID, doc.getString("userName"), doc.getString("additionalInfo"));
+ new UserAccount(userId, doc.getString("userName"), doc.getString("additionalInfo"));
return userAccount;
}
- public static void writeToDB(UserAccount userAccount) {
+ /**
+ * Write user account to DB
+ */
+ public static void writeToDb(UserAccount userAccount) {
if (!useMongoDB) {
- virtualDB.put(userAccount.getUserID(), userAccount);
+ virtualDB.put(userAccount.getUserId(), userAccount);
return;
}
if (null == db) {
@@ -76,13 +93,16 @@ public class DBManager {
}
}
db.getCollection("user_accounts").insertOne(
- new Document("userID", userAccount.getUserID()).append("userName",
+ new Document("userID", userAccount.getUserId()).append("userName",
userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo()));
}
- public static void updateDB(UserAccount userAccount) {
+ /**
+ * Update DB
+ */
+ public static void updateDb(UserAccount userAccount) {
if (!useMongoDB) {
- virtualDB.put(userAccount.getUserID(), userAccount);
+ virtualDB.put(userAccount.getUserId(), userAccount);
return;
}
if (null == db) {
@@ -93,7 +113,7 @@ public class DBManager {
}
}
db.getCollection("user_accounts").updateOne(
- new Document("userID", userAccount.getUserID()),
+ new Document("userID", userAccount.getUserId()),
new Document("$set", new Document("userName", userAccount.getUserName()).append(
"additionalInfo", userAccount.getAdditionalInfo())));
}
@@ -102,9 +122,9 @@ public class DBManager {
*
* Insert data into DB if it does not exist. Else, update it.
*/
- public static void upsertDB(UserAccount userAccount) {
+ public static void upsertDb(UserAccount userAccount) {
if (!useMongoDB) {
- virtualDB.put(userAccount.getUserID(), userAccount);
+ virtualDB.put(userAccount.getUserId(), userAccount);
return;
}
if (null == db) {
@@ -115,8 +135,8 @@ public class DBManager {
}
}
db.getCollection("user_accounts").updateOne(
- new Document("userID", userAccount.getUserID()),
- new Document("$set", new Document("userID", userAccount.getUserID()).append("userName",
+ new Document("userID", userAccount.getUserId()),
+ new Document("$set", new Document("userID", userAccount.getUserId()).append("userName",
userAccount.getUserName()).append("additionalInfo", userAccount.getAdditionalInfo())),
new UpdateOptions().upsert(true));
}
diff --git a/caching/src/main/java/com/iluwatar/caching/LRUCache.java b/caching/src/main/java/com/iluwatar/caching/LruCache.java
similarity index 70%
rename from caching/src/main/java/com/iluwatar/caching/LRUCache.java
rename to caching/src/main/java/com/iluwatar/caching/LruCache.java
index 872f97256..e20275a40 100644
--- a/caching/src/main/java/com/iluwatar/caching/LRUCache.java
+++ b/caching/src/main/java/com/iluwatar/caching/LruCache.java
@@ -12,16 +12,16 @@ import java.util.HashMap;
* LRU data is always at the end of the list.
*
*/
-public class LRUCache {
+public class LruCache {
class Node {
- String userID;
+ String userId;
UserAccount userAccount;
Node previous;
Node next;
- public Node(String userID, UserAccount userAccount) {
- this.userID = userID;
+ public Node(String userId, UserAccount userAccount) {
+ this.userId = userId;
this.userAccount = userAccount;
}
}
@@ -31,13 +31,16 @@ public class LRUCache {
Node head = null;
Node end = null;
- public LRUCache(int capacity) {
+ public LruCache(int capacity) {
this.capacity = capacity;
}
- public UserAccount get(String userID) {
- if (cache.containsKey(userID)) {
- Node node = cache.get(userID);
+ /**
+ * Get user account
+ */
+ public UserAccount get(String userId) {
+ if (cache.containsKey(userId)) {
+ Node node = cache.get(userId);
remove(node);
setHead(node);
return node.userAccount;
@@ -69,52 +72,63 @@ public class LRUCache {
public void setHead(Node node) {
node.next = head;
node.previous = null;
- if (head != null)
+ if (head != null) {
head.previous = node;
+ }
head = node;
- if (end == null)
+ if (end == null) {
end = head;
+ }
}
- public void set(String userID, UserAccount userAccount) {
- if (cache.containsKey(userID)) {
- Node old = cache.get(userID);
+ /**
+ * Set user account
+ */
+ public void set(String userId, UserAccount userAccount) {
+ if (cache.containsKey(userId)) {
+ Node old = cache.get(userId);
old.userAccount = userAccount;
remove(old);
setHead(old);
} else {
- Node newNode = new Node(userID, userAccount);
+ Node newNode = new Node(userId, userAccount);
if (cache.size() >= capacity) {
- System.out.println("# Cache is FULL! Removing " + end.userID + " from cache...");
- cache.remove(end.userID); // remove LRU data from cache.
+ System.out.println("# Cache is FULL! Removing " + end.userId + " from cache...");
+ cache.remove(end.userId); // remove LRU data from cache.
remove(end);
setHead(newNode);
} else {
setHead(newNode);
}
- cache.put(userID, newNode);
+ cache.put(userId, newNode);
}
}
- public boolean contains(String userID) {
- return cache.containsKey(userID);
+ public boolean contains(String userId) {
+ return cache.containsKey(userId);
}
- public void invalidate(String userID) {
- System.out.println("# " + userID + " has been updated! Removing older version from cache...");
- Node toBeRemoved = cache.get(userID);
+ /**
+ * Invalidate cache for user
+ */
+ public void invalidate(String userId) {
+ System.out.println("# " + userId + " has been updated! Removing older version from cache...");
+ Node toBeRemoved = cache.get(userId);
remove(toBeRemoved);
- cache.remove(userID);
+ cache.remove(userId);
}
public boolean isFull() {
return cache.size() >= capacity;
}
- public UserAccount getLRUData() {
+ public UserAccount getLruData() {
return end.userAccount;
}
+ /**
+ * Clear cache
+ */
public void clear() {
head = null;
end = null;
@@ -135,6 +149,9 @@ public class LRUCache {
return listOfCacheData;
}
+ /**
+ * Set cache capacity
+ */
public void setCapacity(int newCapacity) {
if (capacity > newCapacity) {
clear(); // Behavior can be modified to accommodate for decrease in cache size. For now, we'll
diff --git a/caching/src/main/java/com/iluwatar/caching/UserAccount.java b/caching/src/main/java/com/iluwatar/caching/UserAccount.java
index eff0878ad..0e281c429 100644
--- a/caching/src/main/java/com/iluwatar/caching/UserAccount.java
+++ b/caching/src/main/java/com/iluwatar/caching/UserAccount.java
@@ -6,22 +6,25 @@ package com.iluwatar.caching;
*
*/
public class UserAccount {
- private String userID;
+ private String userId;
private String userName;
private String additionalInfo;
- public UserAccount(String userID, String userName, String additionalInfo) {
- this.userID = userID;
+ /**
+ * Constructor
+ */
+ public UserAccount(String userId, String userName, String additionalInfo) {
+ this.userId = userId;
this.userName = userName;
this.additionalInfo = additionalInfo;
}
- public String getUserID() {
- return userID;
+ public String getUserId() {
+ return userId;
}
- public void setUserID(String userID) {
- this.userID = userID;
+ public void setUserId(String userId) {
+ this.userId = userId;
}
public String getUserName() {
@@ -42,6 +45,6 @@ public class UserAccount {
@Override
public String toString() {
- return userID + ", " + userName + ", " + additionalInfo;
+ return userId + ", " + userName + ", " + additionalInfo;
}
}
diff --git a/caching/src/test/java/com/iluwatar/caching/AppTest.java b/caching/src/test/java/com/iluwatar/caching/AppTest.java
index ce5cddf08..35917da1c 100644
--- a/caching/src/test/java/com/iluwatar/caching/AppTest.java
+++ b/caching/src/test/java/com/iluwatar/caching/AppTest.java
@@ -16,7 +16,7 @@ public class AppTest {
*/
@Before
public void setUp() {
- AppManager.initDB(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
+ AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
// to avoid Maven compilation errors. Set flag to true to run the
// tests with MongoDB (provided that MongoDB is installed and socket
// connection is open).
diff --git a/callback/index.md b/callback/index.md
index b724f1edc..be73dc78f 100644
--- a/callback/index.md
+++ b/callback/index.md
@@ -4,19 +4,25 @@ title: Callback
folder: callback
permalink: /patterns/callback/
categories: Other
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Functional
+ - Idiom
---
-**Intent:** Callback is a piece of executable code that is passed as an
+## Intent
+Callback is a piece of executable code that is passed as an
argument to other code, which is expected to call back (execute) the argument
at some convenient time.

-**Applicability:** Use the Callback pattern when
+## Applicability
+Use the Callback pattern when
* when some arbitrary synchronous or asynchronous action must be performed after execution of some defined activity.
-**Real world examples:**
+## Real world examples
* [CyclicBarrier] (http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html#CyclicBarrier%28int,%20java.lang.Runnable%29) constructor can accept callback that will be triggered every time when barrier is tripped.
diff --git a/callback/pom.xml b/callback/pom.xml
index 91f131f43..b4b2f6ed0 100644
--- a/callback/pom.xml
+++ b/callback/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTcallback
diff --git a/callback/src/main/java/com/iluwatar/callback/App.java b/callback/src/main/java/com/iluwatar/callback/App.java
index 81cb16f73..bc8b08cf0 100644
--- a/callback/src/main/java/com/iluwatar/callback/App.java
+++ b/callback/src/main/java/com/iluwatar/callback/App.java
@@ -9,6 +9,9 @@ package com.iluwatar.callback;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) {
Task task = new SimpleTask();
Callback callback = new Callback() {
diff --git a/callback/src/main/java/com/iluwatar/callback/Callback.java b/callback/src/main/java/com/iluwatar/callback/Callback.java
index 08939298b..712893873 100644
--- a/callback/src/main/java/com/iluwatar/callback/Callback.java
+++ b/callback/src/main/java/com/iluwatar/callback/Callback.java
@@ -7,5 +7,5 @@ package com.iluwatar.callback;
*/
public interface Callback {
- public void call();
+ void call();
}
diff --git a/callback/src/main/java/com/iluwatar/callback/LambdasApp.java b/callback/src/main/java/com/iluwatar/callback/LambdasApp.java
new file mode 100644
index 000000000..19dd17eae
--- /dev/null
+++ b/callback/src/main/java/com/iluwatar/callback/LambdasApp.java
@@ -0,0 +1,19 @@
+package com.iluwatar.callback;
+
+/**
+ *
+ * This example generates the exact same output as {@link App} however the callback has been
+ * defined as a Lambdas expression.
+ *
+ */
+public class LambdasApp {
+
+ /**
+ * Program entry point
+ */
+ public static void main(String[] args) {
+ Task task = new SimpleTask();
+ Callback c = () -> System.out.println("I'm done now.");
+ task.executeWith(c);
+ }
+}
diff --git a/callback/src/main/java/com/iluwatar/callback/Task.java b/callback/src/main/java/com/iluwatar/callback/Task.java
index d3be6c7a0..83e2cd4df 100644
--- a/callback/src/main/java/com/iluwatar/callback/Task.java
+++ b/callback/src/main/java/com/iluwatar/callback/Task.java
@@ -7,6 +7,9 @@ package com.iluwatar.callback;
*/
public abstract class Task {
+ /**
+ * Execute with callback
+ */
public final void executeWith(Callback callback) {
execute();
if (callback != null) {
diff --git a/callback/src/test/java/com/iluwatar/callback/AppTest.java b/callback/src/test/java/com/iluwatar/callback/AppTest.java
index 67046a175..28d6eaa1c 100644
--- a/callback/src/test/java/com/iluwatar/callback/AppTest.java
+++ b/callback/src/test/java/com/iluwatar/callback/AppTest.java
@@ -36,4 +36,22 @@ public class AppTest {
assertEquals("Callback called twice", new Integer(2), callingCount);
}
+
+ @Test
+ public void testWithLambdasExample() {
+ Callback callback = () -> callingCount++;
+
+ Task task = new SimpleTask();
+
+ assertEquals("Initial calling count of 0", new Integer(0), callingCount);
+
+ task.executeWith(callback);
+
+ assertEquals("Callback called once", new Integer(1), callingCount);
+
+ task.executeWith(callback);
+
+ assertEquals("Callback called twice", new Integer(2), callingCount);
+
+ }
}
diff --git a/chain/index.md b/chain/index.md
index 9be376324..ef18f6f64 100644
--- a/chain/index.md
+++ b/chain/index.md
@@ -7,25 +7,28 @@ categories: Behavioral
tags:
- Java
- Gang Of Four
+ - Difficulty-Intermediate
---
-**Intent:** Avoid coupling the sender of a request to its receiver by giving
+## Intent
+Avoid coupling the sender of a request to its receiver by giving
more than one object a chance to handle the request. Chain the receiving
objects and pass the request along the chain until an object handles it.

-**Applicability:** Use Chain of Responsibility when
+## Applicability
+Use Chain of Responsibility when
* more than one object may handle a request, and the handler isn't known a priori. The handler should be ascertained automatically
* you want to issue a request to one of several objects without specifying the receiver explicitly
* the set of objects that can handle a request should be specified dynamically
-**Real world examples:**
+## Real world examples
* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29)
* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/chain/pom.xml b/chain/pom.xml
index d1136420e..ec3ecf1bb 100644
--- a/chain/pom.xml
+++ b/chain/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTchain
diff --git a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
index fd58b9ea8..12db1f51c 100644
--- a/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
+++ b/chain/src/main/java/com/iluwatar/chain/RequestHandler.java
@@ -13,6 +13,9 @@ public abstract class RequestHandler {
this.next = next;
}
+ /**
+ * Request handler
+ */
public void handleRequest(Request req) {
if (next != null) {
next.handleRequest(req);
diff --git a/chain/src/test/java/com/iluwatar/chain/AppTest.java b/chain/src/test/java/com/iluwatar/chain/AppTest.java
index bd28b007a..f1dc78759 100644
--- a/chain/src/test/java/com/iluwatar/chain/AppTest.java
+++ b/chain/src/test/java/com/iluwatar/chain/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.chain;
import org.junit.Test;
-import com.iluwatar.chain.App;
-
/**
*
* Application test
diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml
new file mode 100644
index 000000000..a3a2c23a8
--- /dev/null
+++ b/checkstyle-suppressions.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/checkstyle.xml b/checkstyle.xml
index 0ff943d95..706c188e0 100644
--- a/checkstyle.xml
+++ b/checkstyle.xml
@@ -25,8 +25,10 @@
+
+
-
+
@@ -48,7 +50,7 @@
-
+
@@ -61,7 +63,7 @@
-
+
@@ -86,9 +88,6 @@
-
-
-
@@ -97,42 +96,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
@@ -180,11 +148,6 @@
-
-
-
-
@@ -195,7 +158,7 @@
-
+
@@ -205,4 +168,5 @@
+
diff --git a/command/index.md b/command/index.md
index 3fa774d8f..2b9311537 100644
--- a/command/index.md
+++ b/command/index.md
@@ -7,17 +7,21 @@ categories: Behavioral
tags:
- Java
- Gang Of Four
+ - Difficulty-Intermediate
---
-**Also known as:** Action, Transaction
+## Also known as
+Action, Transaction
-**Intent:** Encapsulate a request as an object, thereby letting you
+## Intent
+Encapsulate a request as an object, thereby letting you
parameterize clients with different requests, queue or log requests, and
support undoable operations.

-**Applicability:** Use the Command pattern when you want to
+## Applicability
+Use the Command pattern when you want to
* parameterize objects by an action to perform. You can express such parameterization in a procedural language with a callback function, that is, a function that's registered somewhere to be called at a later point. Commands are an object-oriented replacement for callbacks.
* specify, queue, and execute requests at different times. A Command object can have a lifetime independent of the original request. If the receiver of a request can be represented in an address space-independent way, then you can transfer a command object for the request to a different process and fulfill the request there
@@ -25,16 +29,16 @@ support undoable operations.
* support logging changes so that they can be reapplied in case of a system crash. By augmenting the Command interface with load and store operations, you can keep a persistent log of changes. Recovering from a crash involves reloading logged commands from disk and re-executing them with the execute operation
* structure a system around high-level operations build on primitive operations. Such a structure is common in information systems that support transactions. A transaction encapsulates a set of changes to data. The Command pattern offers a way to model transactions. Commands have a common interface, letting you invoke all transactions the same way. The pattern also makes it easy to extend the system with new transactions
-**Typical Use Case:**
+## Typical Use Case
* to keep a history of requests
* implement callback functionality
* implement the undo functionality
-**Real world examples:**
+## Real world examples
* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/command/pom.xml b/command/pom.xml
index cc21f7f56..837b149f6 100644
--- a/command/pom.xml
+++ b/command/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTcommand
diff --git a/command/src/main/java/com/iluwatar/command/Target.java b/command/src/main/java/com/iluwatar/command/Target.java
index e12f758ff..731fe4d1f 100644
--- a/command/src/main/java/com/iluwatar/command/Target.java
+++ b/command/src/main/java/com/iluwatar/command/Target.java
@@ -30,6 +30,9 @@ public abstract class Target {
@Override
public abstract String toString();
+ /**
+ * Print status
+ */
public void printStatus() {
System.out.println(String.format("%s, [size=%s] [visibility=%s]", this, getSize(),
getVisibility()));
diff --git a/command/src/main/java/com/iluwatar/command/Wizard.java b/command/src/main/java/com/iluwatar/command/Wizard.java
index edef8d3a9..fb6407c74 100644
--- a/command/src/main/java/com/iluwatar/command/Wizard.java
+++ b/command/src/main/java/com/iluwatar/command/Wizard.java
@@ -15,12 +15,18 @@ public class Wizard {
public Wizard() {}
+ /**
+ * Cast spell
+ */
public void castSpell(Command command, Target target) {
System.out.println(this + " casts " + command + " at " + target);
command.execute(target);
undoStack.offerLast(command);
}
+ /**
+ * Undo last spell
+ */
public void undoLastSpell() {
if (!undoStack.isEmpty()) {
Command previousSpell = undoStack.pollLast();
@@ -30,6 +36,9 @@ public class Wizard {
}
}
+ /**
+ * Redo last spell
+ */
public void redoLastSpell() {
if (!redoStack.isEmpty()) {
Command previousSpell = redoStack.pollLast();
diff --git a/composite/index.md b/composite/index.md
index 4a31a1b33..8b980292d 100644
--- a/composite/index.md
+++ b/composite/index.md
@@ -7,24 +7,27 @@ categories: Structural
tags:
- Java
- Gang Of Four
+ - Difficulty-Intermediate
---
-**Intent:** Compose objects into tree structures to represent part-whole
+## Intent
+Compose objects into tree structures to represent part-whole
hierarchies. Composite lets clients treat individual objects and compositions
of objects uniformly.

-**Applicability:** Use the Composite pattern when
+## Applicability
+Use the Composite pattern when
* you want to represent part-whole hierarchies of objects
* you want clients to be able to ignore the difference between compositions of objects and individual objects. Clients will treat all objects in the composite structure uniformly
-**Real world examples:**
+## Real world examples
* [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) and [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html)
* [Apache Wicket](https://github.com/apache/wicket) component tree, see [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) and [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/composite/pom.xml b/composite/pom.xml
index 32c4d2934..584ba5476 100644
--- a/composite/pom.xml
+++ b/composite/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTcomposite
diff --git a/composite/src/main/java/com/iluwatar/composite/LetterComposite.java b/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
index 1fdf4fdb6..39655fa37 100644
--- a/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
+++ b/composite/src/main/java/com/iluwatar/composite/LetterComposite.java
@@ -24,6 +24,9 @@ public abstract class LetterComposite {
protected abstract void printThisAfter();
+ /**
+ * Print
+ */
public void print() {
printThisBefore();
for (LetterComposite letter : children) {
diff --git a/composite/src/main/java/com/iluwatar/composite/Sentence.java b/composite/src/main/java/com/iluwatar/composite/Sentence.java
index e6c626ea2..03f0c6949 100644
--- a/composite/src/main/java/com/iluwatar/composite/Sentence.java
+++ b/composite/src/main/java/com/iluwatar/composite/Sentence.java
@@ -9,6 +9,9 @@ import java.util.List;
*/
public class Sentence extends LetterComposite {
+ /**
+ * Constructor
+ */
public Sentence(List words) {
for (Word w : words) {
this.add(w);
diff --git a/composite/src/main/java/com/iluwatar/composite/Word.java b/composite/src/main/java/com/iluwatar/composite/Word.java
index 3060b0a1b..98c5f0b0d 100644
--- a/composite/src/main/java/com/iluwatar/composite/Word.java
+++ b/composite/src/main/java/com/iluwatar/composite/Word.java
@@ -9,6 +9,9 @@ import java.util.List;
*/
public class Word extends LetterComposite {
+ /**
+ * Constructor
+ */
public Word(List letters) {
for (Letter l : letters) {
this.add(l);
diff --git a/composite/src/test/java/com/iluwatar/composite/AppTest.java b/composite/src/test/java/com/iluwatar/composite/AppTest.java
index 574e8def4..a5bc613c0 100644
--- a/composite/src/test/java/com/iluwatar/composite/AppTest.java
+++ b/composite/src/test/java/com/iluwatar/composite/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.composite;
import org.junit.Test;
-import com.iluwatar.composite.App;
-
/**
*
* Application test
diff --git a/dao/index.md b/dao/index.md
index cf9f43a68..785a1c362 100644
--- a/dao/index.md
+++ b/dao/index.md
@@ -3,22 +3,24 @@ layout: pattern
title: Data Access Object
folder: dao
permalink: /patterns/dao/
-categories: Architectural
+categories: Persistence Tier
tags:
- Java
- Difficulty-Beginner
---
-**Intent:** Object provides an abstract interface to some type of database or
+## Intent
+Object provides an abstract interface to some type of database or
other persistence mechanism.

-**Applicability:** Use the Data Access Object in any of the following situations
+## Applicability
+Use the Data Access Object in any of the following situations
* when you want to consolidate how the data layer is accessed
* when you want to avoid writing multiple data retrieval/persistence layers
-**Credits:**
+## Credits
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
diff --git a/dao/pom.xml b/dao/pom.xml
index c0cd83be1..8b0c260e5 100644
--- a/dao/pom.xml
+++ b/dao/pom.xml
@@ -6,7 +6,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTdao
diff --git a/dao/src/main/java/com/iluwatar/dao/App.java b/dao/src/main/java/com/iluwatar/dao/App.java
index 2e115d8ce..a9351689d 100644
--- a/dao/src/main/java/com/iluwatar/dao/App.java
+++ b/dao/src/main/java/com/iluwatar/dao/App.java
@@ -21,7 +21,7 @@ import org.apache.log4j.Logger;
*/
public class App {
- private static Logger LOGGER = Logger.getLogger(App.class);
+ private static Logger log = Logger.getLogger(App.class);
/**
* Program entry point.
@@ -30,17 +30,17 @@ public class App {
*/
public static void main(final String[] args) {
final CustomerDaoImpl customerDao = new CustomerDaoImpl(generateSampleCustomers());
- LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
- LOGGER.info("customerDao.getCusterById(2): " + customerDao.getCustomerById(2));
+ log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
+ log.info("customerDao.getCusterById(2): " + customerDao.getCustomerById(2));
final Customer customer = new Customer(4, "Dan", "Danson");
customerDao.addCustomer(customer);
- LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
+ log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
customer.setFirstName("Daniel");
customer.setLastName("Danielson");
customerDao.updateCustomer(customer);
- LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
+ log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
customerDao.deleteCustomer(customer);
- LOGGER.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
+ log.info("customerDao.getAllCustomers(): " + customerDao.getAllCustomers());
}
/**
diff --git a/dao/src/main/java/com/iluwatar/dao/Customer.java b/dao/src/main/java/com/iluwatar/dao/Customer.java
index e6d7f7763..ea13daf11 100644
--- a/dao/src/main/java/com/iluwatar/dao/Customer.java
+++ b/dao/src/main/java/com/iluwatar/dao/Customer.java
@@ -11,6 +11,9 @@ public class Customer {
private String firstName;
private String lastName;
+ /**
+ * Constructor
+ */
public Customer(final int id, final String firstName, final String lastName) {
this.id = id;
this.firstName = firstName;
@@ -52,10 +55,11 @@ public class Customer {
boolean isEqual = false;
if (this == o) {
isEqual = true;
- } else if (o != null && (getClass() == o.getClass())) {
+ } else if (o != null && getClass() == o.getClass()) {
final Customer customer = (Customer) o;
- if (getId() == customer.getId())
+ if (getId() == customer.getId()) {
isEqual = true;
+ }
}
return isEqual;
}
diff --git a/dao/src/main/resources/log4j.xml b/dao/src/main/resources/log4j.xml
index 136817f50..906e37170 100644
--- a/dao/src/main/resources/log4j.xml
+++ b/dao/src/main/resources/log4j.xml
@@ -1,17 +1,17 @@
+ xmlns:log4j='http://jakarta.apache.org/log4j/'>
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/decorator/etc/decorator.png b/decorator/etc/decorator.png
index 1e4bfdac2..47a87b20b 100644
Binary files a/decorator/etc/decorator.png and b/decorator/etc/decorator.png differ
diff --git a/decorator/etc/decorator.ucls b/decorator/etc/decorator.ucls
index 7adb8c3a6..a5353d4ec 100644
--- a/decorator/etc/decorator.ucls
+++ b/decorator/etc/decorator.ucls
@@ -1,18 +1,18 @@
-
+
-
+
-
-
+
+
@@ -21,29 +21,46 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
+
+
+
+
+
+
diff --git a/decorator/etc/decorator_1.png b/decorator/etc/decorator_1.png
deleted file mode 100644
index 5a7afe2d1..000000000
Binary files a/decorator/etc/decorator_1.png and /dev/null differ
diff --git a/decorator/index.md b/decorator/index.md
index 61eeeac60..108e0cc73 100644
--- a/decorator/index.md
+++ b/decorator/index.md
@@ -7,22 +7,26 @@ categories: Structural
tags:
- Java
- Gang Of Four
+ - Difficulty-Beginner
---
-**Also known as:** Wrapper
+## Also known as
+Wrapper
-**Intent:** Attach additional responsibilities to an object dynamically.
+## Intent
+Attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending
functionality.

-**Applicability:** Use Decorator
+## Applicability
+Use Decorator
* to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects
* for responsibilities that can be withdrawn
* when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/decorator/pom.xml b/decorator/pom.xml
index 384c03aa4..ea30f5b38 100644
--- a/decorator/pom.xml
+++ b/decorator/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTdecorator
diff --git a/decorator/src/main/java/com/iluwatar/decorator/App.java b/decorator/src/main/java/com/iluwatar/decorator/App.java
index d58d3b61a..242e72d11 100644
--- a/decorator/src/main/java/com/iluwatar/decorator/App.java
+++ b/decorator/src/main/java/com/iluwatar/decorator/App.java
@@ -8,7 +8,7 @@ package com.iluwatar.decorator;
* runtime.
*
* In this example we show how the simple {@link Troll} first attacks and then flees the battle.
- * Then we decorate the {@link Troll} with a {@link SmartTroll} and perform the attack again. You
+ * Then we decorate the {@link Troll} with a {@link SmartHostile} and perform the attack again. You
* can see how the behavior changes after the decoration.
*
*/
@@ -30,7 +30,7 @@ public class App {
// change the behavior of the simple troll by adding a decorator
System.out.println("\nA smart looking troll surprises you.");
- Hostile smart = new SmartTroll(troll);
+ Hostile smart = new SmartHostile(troll);
smart.attack();
smart.fleeBattle();
System.out.printf("Smart troll power %d.\n", smart.getAttackPower());
diff --git a/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java b/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java
similarity index 56%
rename from decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java
rename to decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java
index 93927237d..93f494688 100644
--- a/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java
+++ b/decorator/src/main/java/com/iluwatar/decorator/SmartHostile.java
@@ -1,34 +1,34 @@
package com.iluwatar.decorator;
/**
- * SmartTroll is a decorator for {@link Hostile} objects. The calls to the {@link Hostile} interface
+ * SmartHostile is a decorator for {@link Hostile} objects. The calls to the {@link Hostile} interface
* are intercepted and decorated. Finally the calls are delegated to the decorated {@link Hostile}
* object.
*
*/
-public class SmartTroll implements Hostile {
+public class SmartHostile implements Hostile {
private Hostile decorated;
- public SmartTroll(Hostile decorated) {
+ public SmartHostile(Hostile decorated) {
this.decorated = decorated;
}
@Override
public void attack() {
- System.out.println("The troll throws a rock at you!");
+ System.out.println("It throws a rock at you!");
decorated.attack();
}
@Override
public int getAttackPower() {
- // decorated troll power + 20 because it is smart
+ // decorated hostile's power + 20 because it is smart
return decorated.getAttackPower() + 20;
}
@Override
public void fleeBattle() {
- System.out.println("The troll calls for help!");
+ System.out.println("It calls for help!");
decorated.fleeBattle();
}
}
diff --git a/decorator/src/test/java/com/iluwatar/decorator/AppTest.java b/decorator/src/test/java/com/iluwatar/decorator/AppTest.java
index f6fa96092..4b2ced962 100644
--- a/decorator/src/test/java/com/iluwatar/decorator/AppTest.java
+++ b/decorator/src/test/java/com/iluwatar/decorator/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.decorator;
import org.junit.Test;
-import com.iluwatar.decorator.App;
-
/**
*
* Application test
diff --git a/decorator/src/test/java/com/iluwatar/decorator/SmartTrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java
similarity index 74%
rename from decorator/src/test/java/com/iluwatar/decorator/SmartTrollTest.java
rename to decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java
index fd73d91cb..e5be32eae 100644
--- a/decorator/src/test/java/com/iluwatar/decorator/SmartTrollTest.java
+++ b/decorator/src/test/java/com/iluwatar/decorator/SmartHostileTest.java
@@ -3,9 +3,7 @@ package com.iluwatar.decorator;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.*;
import static org.mockito.internal.verification.VerificationModeFactory.times;
/**
@@ -13,15 +11,15 @@ import static org.mockito.internal.verification.VerificationModeFactory.times;
*
* @author Jeroen Meulemeester
*/
-public class SmartTrollTest {
+public class SmartHostileTest {
@Test
- public void testSmartTroll() throws Exception {
+ public void testSmartHostile() throws Exception {
// Create a normal troll first, but make sure we can spy on it later on.
final Hostile simpleTroll = spy(new Troll());
// Now we want to decorate the troll to make it smarter ...
- final Hostile smartTroll = new SmartTroll(simpleTroll);
+ final Hostile smartTroll = new SmartHostile(simpleTroll);
assertEquals(30, smartTroll.getAttackPower());
verify(simpleTroll, times(1)).getAttackPower();
diff --git a/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java b/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java
index 021f7ed1a..56f541cfc 100644
--- a/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java
+++ b/decorator/src/test/java/com/iluwatar/decorator/TrollTest.java
@@ -4,15 +4,11 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
import java.io.PrintStream;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.*;
import static org.mockito.internal.verification.VerificationModeFactory.times;
/**
diff --git a/delegation/etc/delegation.png b/delegation/etc/delegation.png
new file mode 100644
index 000000000..375ef4d6b
Binary files /dev/null and b/delegation/etc/delegation.png differ
diff --git a/delegation/etc/delegation.ucls b/delegation/etc/delegation.ucls
new file mode 100644
index 000000000..e3ce08873
--- /dev/null
+++ b/delegation/etc/delegation.ucls
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/delegation/index.md b/delegation/index.md
new file mode 100644
index 000000000..e5c0c6376
--- /dev/null
+++ b/delegation/index.md
@@ -0,0 +1,30 @@
+---
+layout: pattern
+title: Delegation
+folder: delegation
+permalink: /patterns/delegation/
+categories: Behavioral
+tags:
+ - Java
+ - Difficulty-Beginner
+---
+
+## Also known as
+Proxy Pattern
+
+## Intent
+It is a technique where an object expresses certain behavior to the outside but in
+reality delegates responsibility for implementing that behaviour to an associated object.
+
+
+
+## Applicability
+Use the Delegate pattern in order to achieve the following
+
+* Reduce the coupling of methods to their class
+* Components that behave identically, but realize that this situation can change in the future.
+
+## Credits
+
+* [Delegate Pattern: Wikipedia ](https://en.wikipedia.org/wiki/Delegation_pattern)
+* [Proxy Pattern: Wikipedia ](https://en.wikipedia.org/wiki/Proxy_pattern)
diff --git a/delegation/pom.xml b/delegation/pom.xml
new file mode 100644
index 000000000..3d9ca390d
--- /dev/null
+++ b/delegation/pom.xml
@@ -0,0 +1,27 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.10.0-SNAPSHOT
+
+ 4.0.0
+
+ delegation
+
+
+
+ junit
+ junit
+ test
+
+
+ com.github.stefanbirkner
+ system-rules
+ test
+
+
+
\ No newline at end of file
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/App.java b/delegation/src/main/java/com/iluwatar/delegation/simple/App.java
new file mode 100644
index 000000000..050380c18
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/App.java
@@ -0,0 +1,38 @@
+package com.iluwatar.delegation.simple;
+
+import com.iluwatar.delegation.simple.printers.CanonPrinter;
+import com.iluwatar.delegation.simple.printers.EpsonPrinter;
+import com.iluwatar.delegation.simple.printers.HpPrinter;
+
+/**
+ * The delegate pattern provides a mechanism to abstract away the implementation and control of the desired action.
+ * The class being called in this case {@link PrinterController} is not responsible for the actual desired action,
+ * but is actually delegated to a helper class either {@link CanonPrinter}, {@link EpsonPrinter} or {@link HpPrinter}.
+ * The consumer does not have or require knowledge of the actual class carrying out the action, only the
+ * container on which they are calling.
+ *
+ * In this example the delegates are {@link EpsonPrinter}, {@link HpPrinter} and {@link CanonPrinter} they all implement
+ * {@link Printer}. The {@link PrinterController} class also implements {@link Printer}. However neither provide the
+ * functionality of {@link Printer} by printing to the screen, they actually call upon the instance of {@link Printer}
+ * that they were instantiated with. Therefore delegating the behaviour to another class.
+ */
+public class App {
+
+ public static final String MESSAGE_TO_PRINT = "hello world";
+
+ /**
+ * Program entry point
+ *
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ PrinterController hpPrinterController = new PrinterController(new HpPrinter());
+ PrinterController canonPrinterController = new PrinterController(new CanonPrinter());
+ PrinterController epsonPrinterController = new PrinterController(new EpsonPrinter());
+
+ hpPrinterController.print(MESSAGE_TO_PRINT);
+ canonPrinterController.print(MESSAGE_TO_PRINT);
+ epsonPrinterController.print(MESSAGE_TO_PRINT);
+ }
+
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java b/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java
new file mode 100644
index 000000000..91531dfce
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/Printer.java
@@ -0,0 +1,23 @@
+package com.iluwatar.delegation.simple;
+
+import com.iluwatar.delegation.simple.printers.CanonPrinter;
+import com.iluwatar.delegation.simple.printers.EpsonPrinter;
+import com.iluwatar.delegation.simple.printers.HpPrinter;
+
+/**
+ * Interface that both the Controller and the Delegate will implement.
+ *
+ * @see CanonPrinter
+ * @see EpsonPrinter
+ * @see HpPrinter
+ */
+public interface Printer {
+
+ /**
+ * Method that takes a String to print to the screen. This will be implemented on both the
+ * controller and the delegate allowing the controller to call the same method on the delegate class.
+ *
+ * @param message to be printed to the screen
+ */
+ void print(final String message);
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java
new file mode 100644
index 000000000..d237f0871
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/PrinterController.java
@@ -0,0 +1,23 @@
+package com.iluwatar.delegation.simple;
+
+public class PrinterController implements Printer {
+
+ private final Printer printer;
+
+ public PrinterController(Printer printer) {
+ this.printer = printer;
+ }
+
+ /**
+ * This method is implemented from {@link Printer} however instead on providing an
+ * implementation, it instead calls upon the class passed through the constructor. This is the delegate,
+ * hence the pattern. Therefore meaning that the caller does not care of the implementing class only the owning
+ * controller.
+ *
+ * @param message to be printed to the screen
+ */
+ @Override
+ public void print(String message) {
+ printer.print(message);
+ }
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java
new file mode 100644
index 000000000..ef6386429
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/CanonPrinter.java
@@ -0,0 +1,21 @@
+package com.iluwatar.delegation.simple.printers;
+
+import com.iluwatar.delegation.simple.Printer;
+
+/**
+ * Specialised Implementation of {@link Printer} for a Canon Printer, in
+ * this case the message to be printed is appended to "Canon Printer : "
+ *
+ * @see Printer
+ */
+public class CanonPrinter implements Printer {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void print(String message) {
+ System.out.print("Canon Printer : " + message);
+ }
+
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java
new file mode 100644
index 000000000..780d12bcb
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/EpsonPrinter.java
@@ -0,0 +1,21 @@
+package com.iluwatar.delegation.simple.printers;
+
+import com.iluwatar.delegation.simple.Printer;
+
+/**
+ * Specialised Implementation of {@link Printer} for a Epson Printer, in
+ * this case the message to be printed is appended to "Epson Printer : "
+ *
+ * @see Printer
+ */
+public class EpsonPrinter implements Printer {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void print(String message) {
+ System.out.print("Epson Printer : " + message);
+ }
+
+}
diff --git a/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java
new file mode 100644
index 000000000..be8845ece
--- /dev/null
+++ b/delegation/src/main/java/com/iluwatar/delegation/simple/printers/HpPrinter.java
@@ -0,0 +1,21 @@
+package com.iluwatar.delegation.simple.printers;
+
+import com.iluwatar.delegation.simple.Printer;
+
+/**
+ * Specialised Implementation of {@link Printer} for a HP Printer, in
+ * this case the message to be printed is appended to "HP Printer : "
+ *
+ * @see Printer
+ */
+public class HpPrinter implements Printer {
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void print(String message) {
+ System.out.print("HP Printer : " + message);
+ }
+
+}
diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java
new file mode 100644
index 000000000..189baa856
--- /dev/null
+++ b/delegation/src/test/java/com/iluwatar/delegation/simple/AppTest.java
@@ -0,0 +1,13 @@
+package com.iluwatar.delegation.simple;
+
+import org.junit.Test;
+
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+
+}
diff --git a/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
new file mode 100644
index 000000000..9442b3033
--- /dev/null
+++ b/delegation/src/test/java/com/iluwatar/delegation/simple/DelegateTest.java
@@ -0,0 +1,43 @@
+package com.iluwatar.delegation.simple;
+
+import com.iluwatar.delegation.simple.printers.CanonPrinter;
+import com.iluwatar.delegation.simple.printers.EpsonPrinter;
+import com.iluwatar.delegation.simple.printers.HpPrinter;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.contrib.java.lang.system.SystemOutRule;
+
+import static org.junit.Assert.assertEquals;
+
+public class DelegateTest {
+
+ private static final String MESSAGE = "Test Message Printed";
+
+ @Rule
+ public final SystemOutRule systemOutRule = new SystemOutRule().enableLog();
+
+ @Test
+ public void testCanonPrinter() throws Exception {
+ PrinterController printerController = new PrinterController(new CanonPrinter());
+ printerController.print(MESSAGE);
+
+ assertEquals("Canon Printer : Test Message Printed", systemOutRule.getLog());
+ }
+
+ @Test
+ public void testHpPrinter() throws Exception {
+ PrinterController printerController = new PrinterController(new HpPrinter());
+ printerController.print(MESSAGE);
+
+ assertEquals("HP Printer : Test Message Printed", systemOutRule.getLog());
+ }
+
+ @Test
+ public void testEpsonPrinter() throws Exception {
+ PrinterController printerController = new PrinterController(new EpsonPrinter());
+ printerController.print(MESSAGE);
+
+ assertEquals("Epson Printer : Test Message Printed", systemOutRule.getLog());
+ }
+
+}
diff --git a/dependency-injection/index.md b/dependency-injection/index.md
index f6ead97a7..735f589b1 100644
--- a/dependency-injection/index.md
+++ b/dependency-injection/index.md
@@ -4,10 +4,13 @@ title: Dependency Injection
folder: dependency-injection
permalink: /patterns/dependency-injection/
categories: Behavioral
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** Dependency Injection is a software design pattern in which one or
+## Intent
+Dependency Injection is a software design pattern in which one or
more dependencies (or services) are injected, or passed by reference, into a
dependent object (or client) and are made part of the client's state. The
pattern separates the creation of a client's dependencies from its own
@@ -16,7 +19,8 @@ inversion of control and single responsibility principles.

-**Applicability:** Use the Dependency Injection pattern when
+## Applicability
+Use the Dependency Injection pattern when
* when you need to remove knowledge of concrete implementation from object
* to enable unit testing of classes in isolation using mock objects or stubs
diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml
index 4746d5835..e0aee6a6a 100644
--- a/dependency-injection/pom.xml
+++ b/dependency-injection/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTdependency-injection
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java
index 8d6411028..36f016e47 100644
--- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.dependency.injection;
import org.junit.Test;
-import com.iluwatar.dependency.injection.App;
-
/**
*
* Application test
diff --git a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java
index 69895a493..9b3f4ea3a 100644
--- a/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java
+++ b/dependency-injection/src/test/java/com/iluwatar/dependency/injection/SimpleWizardTest.java
@@ -1,15 +1,8 @@
package com.iluwatar.dependency.injection;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
-import java.io.PrintStream;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.*;
/**
* Date: 12/10/15 - 8:26 PM
diff --git a/double-checked-locking/index.md b/double-checked-locking/index.md
index b1b0108ec..da1fdd1a2 100644
--- a/double-checked-locking/index.md
+++ b/double-checked-locking/index.md
@@ -4,17 +4,22 @@ title: Double Checked Locking
folder: double-checked-locking
permalink: /patterns/double-checked-locking/
categories: Concurrency
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Idiom
---
-**Intent:** Reduce the overhead of acquiring a lock by first testing the
+## Intent
+Reduce the overhead of acquiring a lock by first testing the
locking criterion (the "lock hint") without actually acquiring the lock. Only
if the locking criterion check indicates that locking is required does the
actual locking logic proceed.

-**Applicability:** Use the Double Checked Locking pattern when
+## Applicability
+Use the Double Checked Locking pattern when
* there is a concurrent access in object creation, e.g. singleton, where you want to create single instance of the same class and checking if it's null or not maybe not be enough when there are two or more threads that checks if instance is null or not.
* there is a concurrent access on a method where method's behaviour changes according to the some constraints and these constraint change within this method.
diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml
index 9b87d6859..465184e4c 100644
--- a/double-checked-locking/pom.xml
+++ b/double-checked-locking/pom.xml
@@ -3,7 +3,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTdouble-checked-locking
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java
index 0cc62c995..79bf6aefd 100644
--- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java
+++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java
@@ -28,7 +28,7 @@ public class App {
ExecutorService executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
executorService.execute(() -> {
- while (inventory.addItem(new Item()));
+ while (inventory.addItem(new Item())) {};
});
}
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java
index 0a17ac13d..1011b78b4 100644
--- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java
+++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Inventory.java
@@ -17,12 +17,18 @@ public class Inventory {
private final List items;
private final Lock lock;
+ /**
+ * Constructor
+ */
public Inventory(int inventorySize) {
this.inventorySize = inventorySize;
this.items = new ArrayList<>(inventorySize);
this.lock = new ReentrantLock();
}
+ /**
+ * Add item
+ */
public boolean addItem(Item item) {
if (items.size() < inventorySize) {
lock.lock();
diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Item.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Item.java
index 5efe06215..bba4970a3 100644
--- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Item.java
+++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/Item.java
@@ -6,7 +6,4 @@ package com.iluwatar.doublechecked.locking;
*
*/
public class Item {
-
- private String name;
- private int level;
}
diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java
index bd88f223c..012d00648 100644
--- a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java
+++ b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.doublechecked.locking;
import org.junit.Test;
-import com.iluwatar.doublechecked.locking.App;
-
/**
*
* Application test
diff --git a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
index 1bc43263f..a09f19e57 100644
--- a/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
+++ b/double-checked-locking/src/test/java/com/iluwatar/doublechecked/locking/InventoryTest.java
@@ -77,7 +77,7 @@ public class InventoryTest {
final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
for (int i = 0; i < THREAD_COUNT; i++) {
executorService.execute(() -> {
- while (inventory.addItem(new Item())) ;
+ while (inventory.addItem(new Item())) {};
});
}
diff --git a/double-dispatch/index.md b/double-dispatch/index.md
index 6847b7a41..ae87208a2 100644
--- a/double-dispatch/index.md
+++ b/double-dispatch/index.md
@@ -4,18 +4,23 @@ title: Double Dispatch
folder: double-dispatch
permalink: /patterns/double-dispatch/
categories: Other
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Idiom
---
-**Intent:** Double Dispatch pattern is a way to create maintainable dynamic
+## Intent
+Double Dispatch pattern is a way to create maintainable dynamic
behavior based on receiver and parameter types.

-**Applicability:** Use the Double Dispatch pattern when
+## Applicability
+Use the Double Dispatch pattern when
* the dynamic behavior is not defined only based on receiving object's type but also on the receiving method's parameter type.
-**Real world examples:**
+## Real world examples
* [ObjectOutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html)
diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml
index 8c5db3b6b..719827cf0 100644
--- a/double-dispatch/pom.xml
+++ b/double-dispatch/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTdouble-dispatch
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java
index 6514feb7f..98e19b770 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/App.java
@@ -5,22 +5,20 @@ import java.util.List;
/**
*
- * When a message with a parameter is sent to an object, the resultant behaviour is defined by the
- * implementation of that method in the receiver. Sometimes the behaviour must also be determined by
- * the type of the parameter.
+ * When a message with a parameter is sent to an object, the resultant behaviour is defined by the implementation of
+ * that method in the receiver. Sometimes the behaviour must also be determined by the type of the parameter.
*
- * One way to implement this would be to create multiple instanceof-checks for the methods
- * parameter. However, this creates a maintenance issue. When new types are added we would also need
- * to change the method's implementation and add a new instanceof-check. This violates the single
- * responsibility principle - a class should have only one reason to change.
+ * One way to implement this would be to create multiple instanceof-checks for the methods parameter. However, this
+ * creates a maintenance issue. When new types are added we would also need to change the method's implementation and
+ * add a new instanceof-check. This violates the single responsibility principle - a class should have only one reason
+ * to change.
*
- * Instead of the instanceof-checks a better way is to make another virtual call on the parameter
- * object. This way new functionality can be easily added without the need to modify existing
- * implementation (open-closed principle).
+ * Instead of the instanceof-checks a better way is to make another virtual call on the parameter object. This way new
+ * functionality can be easily added without the need to modify existing implementation (open-closed principle).
*
- * In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other.
- * Each object has its own coordinates which are checked against the other objects' coordinates. If
- * there is an overlap, then the objects collide utilizing the Double Dispatch pattern.
+ * In this example we have hierarchy of objects ({@link GameObject}) that can collide to each other. Each object has its
+ * own coordinates which are checked against the other objects' coordinates. If there is an overlap, then the objects
+ * collide utilizing the Double Dispatch pattern.
*
*/
public class App {
@@ -28,7 +26,8 @@ public class App {
/**
* Program entry point
*
- * @param args command line args
+ * @param args
+ * command line args
*/
public static void main(String[] args) {
// initialize game objects and print their status
@@ -42,8 +41,9 @@ public class App {
// collision check
objects.stream().forEach(o1 -> objects.stream().forEach(o2 -> {
- if (o1 != o2 && o1.intersectsWith(o2))
+ if (o1 != o2 && o1.intersectsWith(o2)) {
o1.collision(o2);
+ }
}));
System.out.println("");
diff --git a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
index db26265cc..e1e3eab7b 100644
--- a/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
+++ b/double-dispatch/src/main/java/com/iluwatar/doubledispatch/Rectangle.java
@@ -12,6 +12,9 @@ public class Rectangle {
private int right;
private int bottom;
+ /**
+ * Constructor
+ */
public Rectangle(int left, int top, int right, int bottom) {
this.left = left;
this.top = top;
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java
index c5cd213b5..83caca613 100644
--- a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.doubledispatch;
import org.junit.Test;
-import com.iluwatar.doubledispatch.App;
-
/**
*
* Application test
diff --git a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java
index 5a3366e4e..6792a5d37 100644
--- a/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java
+++ b/double-dispatch/src/test/java/com/iluwatar/doubledispatch/CollisionTest.java
@@ -107,9 +107,9 @@ public abstract class CollisionTest {
final String targetName = target.getClass().getSimpleName();
final String otherName = other.getClass().getSimpleName();
- final String errorMessage = expectTargetOnFire ?
- "Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!" :
- "Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!";
+ final String errorMessage = expectTargetOnFire
+ ? "Expected [" + targetName + "] to be on fire after colliding with [" + otherName + "] but it was not!"
+ : "Expected [" + targetName + "] not to be on fire after colliding with [" + otherName + "] but it was!";
assertEquals(errorMessage, expectTargetOnFire, target.isOnFire());
}
@@ -126,9 +126,9 @@ public abstract class CollisionTest {
final String targetName = target.getClass().getSimpleName();
final String otherName = other.getClass().getSimpleName();
- final String errorMessage = expectedDamage ?
- "Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!" :
- "Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!";
+ final String errorMessage = expectedDamage
+ ? "Expected [" + targetName + "] to be damaged after colliding with [" + otherName + "] but it was not!"
+ : "Expected [" + targetName + "] not to be damaged after colliding with [" + otherName + "] but it was!";
assertEquals(errorMessage, expectedDamage, target.isDamaged());
}
diff --git a/event-aggregator/index.md b/event-aggregator/index.md
index 1c89c7188..5462a2a5d 100644
--- a/event-aggregator/index.md
+++ b/event-aggregator/index.md
@@ -4,10 +4,13 @@ title: Event Aggregator
folder: event-aggregator
permalink: /patterns/event-aggregator/
categories: Structural
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** A system with lots of objects can lead to complexities when a
+## Intent
+A system with lots of objects can lead to complexities when a
client wants to subscribe to events. The client has to find and register for
each object individually, if each object has multiple events then each event
requires a separate subscription. An Event Aggregator acts as a single source
@@ -16,7 +19,8 @@ allowing clients to register with just the aggregator.

-**Applicability:** Use the Event Aggregator pattern when
+## Applicability
+Use the Event Aggregator pattern when
* Event Aggregator is a good choice when you have lots of objects that are
potential event sources. Rather than have the observer deal with registering
@@ -24,6 +28,6 @@ allowing clients to register with just the aggregator.
Aggregator. As well as simplifying registration, a Event Aggregator also
simplifies the memory management issues in using observers.
-**Credits:**
+## Credits
* [Martin Fowler - Event Aggregator](http://martinfowler.com/eaaDev/EventAggregator.html)
diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml
index 94873472f..70d585cbb 100644
--- a/event-aggregator/pom.xml
+++ b/event-aggregator/pom.xml
@@ -4,7 +4,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTevent-aggregator
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java
index 0cb76c215..d0c37c3a8 100644
--- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.event.aggregator;
import org.junit.Test;
-import com.iluwatar.event.aggregator.App;
-
/**
*
* Application test
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java
index 09acf7442..37bd36da4 100644
--- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/EventEmitterTest.java
@@ -10,8 +10,8 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Date: 12/12/15 - 10:58 PM
@@ -63,6 +63,37 @@ public abstract class EventEmitterTest {
testAllDaysWithDefaultObserver(specialDay, event);
}
+ /**
+ * Pass each week of the day, day by day to the event emitter and verify of the given observers
+ * received the correct event on the special day.
+ *
+ * @param specialDay The special day on which an event is emitted
+ * @param event The expected event emitted by the test object
+ * @param emitter The event emitter
+ * @param observers The registered observer mocks
+ */
+ private void testAllDays(final Weekday specialDay, final Event event, final E emitter,
+ final EventObserver... observers) {
+
+ for (final Weekday weekday : Weekday.values()) {
+ // Pass each week of the day, day by day to the event emitter
+ emitter.timePasses(weekday);
+
+ if (weekday == specialDay) {
+ // On a special day, every observer should have received the event
+ for (final EventObserver observer : observers) {
+ verify(observer, times(1)).onEvent(eq(event));
+ }
+ } else {
+ // On any other normal day, the observers should have received nothing at all
+ verifyZeroInteractions(observers);
+ }
+ }
+
+ // The observers should not have received any additional events after the week
+ verifyNoMoreInteractions(observers);
+ }
+
/**
* Go over every day of the month, and check if the event is emitted on the given day. Use an
* event emitter without a default observer
@@ -99,35 +130,4 @@ public abstract class EventEmitterTest {
testAllDays(specialDay, event, emitter, defaultObserver, observer1, observer2);
}
- /**
- * Pass each week of the day, day by day to the event emitter and verify of the given observers
- * received the correct event on the special day.
- *
- * @param specialDay The special day on which an event is emitted
- * @param event The expected event emitted by the test object
- * @param emitter The event emitter
- * @param observers The registered observer mocks
- */
- private void testAllDays(final Weekday specialDay, final Event event, final E emitter,
- final EventObserver... observers) {
-
- for (final Weekday weekday : Weekday.values()) {
- // Pass each week of the day, day by day to the event emitter
- emitter.timePasses(weekday);
-
- if (weekday == specialDay) {
- // On a special day, every observer should have received the event
- for (final EventObserver observer : observers) {
- verify(observer, times(1)).onEvent(eq(event));
- }
- } else {
- // On any other normal day, the observers should have received nothing at all
- verifyZeroInteractions(observers);
- }
- }
-
- // The observers should not have received any additional events after the week
- verifyNoMoreInteractions(observers);
- }
-
}
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
index 1dd4e5c63..c1d054936 100644
--- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingJoffreyTest.java
@@ -9,8 +9,8 @@ import java.io.PrintStream;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Date: 12/12/15 - 3:04 PM
diff --git a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingsHandTest.java b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingsHandTest.java
index 992ee4cf5..e62bb3f52 100644
--- a/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingsHandTest.java
+++ b/event-aggregator/src/test/java/com/iluwatar/event/aggregator/KingsHandTest.java
@@ -6,8 +6,8 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Date: 12/12/15 - 10:57 AM
@@ -24,7 +24,7 @@ public class KingsHandTest extends EventEmitterTest {
}
/**
- * The {@link KingsHand} is both an {@EventEmitter} as an {@link EventObserver} so verify if every
+ * The {@link KingsHand} is both an {@link EventEmitter} as an {@link EventObserver} so verify if every
* event received is passed up to it's superior, in most cases {@link KingJoffrey} but now just a
* mocked observer.
*/
diff --git a/event-driven-architecture/etc/eda.png b/event-driven-architecture/etc/eda.png
new file mode 100644
index 000000000..38c433a40
Binary files /dev/null and b/event-driven-architecture/etc/eda.png differ
diff --git a/event-driven-architecture/etc/eda.ucls b/event-driven-architecture/etc/eda.ucls
new file mode 100644
index 000000000..4ddb8b20c
--- /dev/null
+++ b/event-driven-architecture/etc/eda.ucls
@@ -0,0 +1,196 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/event-driven-architecture/index.md b/event-driven-architecture/index.md
new file mode 100644
index 000000000..7c786b76c
--- /dev/null
+++ b/event-driven-architecture/index.md
@@ -0,0 +1,30 @@
+layout: pattern
+title: Event Driven Architecture
+folder: event-driven-architecture
+permalink: /patterns/event-driven-architecture
+
+## Intent
+Send and notify state changes of your objects to other applications using an Event-driven Architecture.
+
+
+
+## Applicability
+Use an Event-driven architecture when
+
+* you want to create a loosely coupled system
+* you want to build a more responsive system
+* you want a system that is easier to extend
+
+## Real world examples
+
+* SendGrid, an email API, sends events whenever an email is processed, delivered, opened etc... (https://sendgrid.com/docs/API_Reference/Webhooks/event.html)
+* Chargify, a billing API, exposes payment activity through various events (https://docs.chargify.com/api-events)
+* Amazon's AWS Lambda, lets you execute code in response to events such as changes to Amazon S3 buckets, updates to an Amazon DynamoDB table, or custom events generated by your applications or devices. (https://aws.amazon.com/lambda)
+* MySQL runs triggers based on events such as inserts and update events happening on database tables.
+
+## Credits
+
+* [Event-driven architecture - Wikipedia](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained)
+* [Fundamental Components of an Event-Driven Architecture](http://giocc.com/fundamental-components-of-an-event-driven-architecture.html)
+* [Real World Applications/Event Driven Applications](https://wiki.haskell.org/Real_World_Applications/Event_Driven_Applications)
+* [Event-driven architecture definition](http://searchsoa.techtarget.com/definition/event-driven-architecture)
diff --git a/event-driven-architecture/pom.xml b/event-driven-architecture/pom.xml
new file mode 100644
index 000000000..32b0bfb3e
--- /dev/null
+++ b/event-driven-architecture/pom.xml
@@ -0,0 +1,28 @@
+
+
+
+ 4.0.0
+
+ com.iluwatar
+ java-design-patterns
+ 1.10.0-SNAPSHOT
+
+
+ event-driven-architecture
+
+
+
+ junit
+ junit
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/App.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/App.java
new file mode 100644
index 000000000..a1e4c6652
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/App.java
@@ -0,0 +1,42 @@
+package com.iluwatar.eda;
+
+import com.iluwatar.eda.event.Event;
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.event.UserUpdatedEvent;
+import com.iluwatar.eda.framework.EventDispatcher;
+import com.iluwatar.eda.handler.UserCreatedEventHandler;
+import com.iluwatar.eda.handler.UserUpdatedEventHandler;
+import com.iluwatar.eda.model.User;
+
+/**
+ * An event-driven architecture (EDA) is a framework that orchestrates behavior around the
+ * production, detection and consumption of events as well as the responses they evoke. An event is
+ * any identifiable occurrence that has significance for system hardware or software. The
+ * example below uses an {@link EventDispatcher} to link/register {@link Event} objects to their
+ * respective handlers once an {@link Event} is dispatched, it's respective handler is invoked and
+ * the {@link Event} is handled accordingly.
+ *
+ */
+public class App {
+
+ /**
+ * Once the {@link EventDispatcher} is initialised, handlers related to specific events have to be
+ * made known to the dispatcher by registering them. In this case the {@link UserCreatedEvent} is
+ * bound to the UserCreatedEventHandler, whilst the {@link UserUpdatedEvent} is bound to the
+ * {@link UserUpdatedEventHandler}. The dispatcher can now be called to dispatch specific events.
+ * When a user is saved, the {@link UserCreatedEvent} can be dispatched.
+ * On the other hand, when a user is updated, {@link UserUpdatedEvent} can be dispatched.
+ *
+ */
+ public static void main(String[] args) {
+
+ EventDispatcher dispatcher = new EventDispatcher();
+ dispatcher.registerChannel(UserCreatedEvent.class, new UserCreatedEventHandler());
+ dispatcher.registerChannel(UserUpdatedEvent.class, new UserUpdatedEventHandler());
+
+ User user = new User("iluwatar");
+ dispatcher.onEvent(new UserCreatedEvent(user));
+ dispatcher.onEvent(new UserUpdatedEvent(user));
+ }
+
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/Event.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/Event.java
new file mode 100644
index 000000000..bcf78f275
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/Event.java
@@ -0,0 +1,27 @@
+package com.iluwatar.eda.event;
+
+import com.iluwatar.eda.framework.EventDispatcher;
+import com.iluwatar.eda.framework.Message;
+
+/**
+ * The {@link Event} class serves as a base class for defining custom events happening with your
+ * system. In this example we have two types of events defined.
+ *
+ *
{@link UserCreatedEvent} - used when a user is created
+ *
{@link UserUpdatedEvent} - used when a user is updated
+ *
+ * Events can be distinguished using the {@link #getType() getType} method.
+ */
+public class Event implements Message {
+
+ /**
+ * Returns the event type as a {@link Class} object
+ * In this example, this method is used by the {@link EventDispatcher} to
+ * dispatch events depending on their type.
+ *
+ * @return the Event type as a {@link Class}.
+ */
+ public Class extends Message> getType() {
+ return getClass();
+ }
+}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
new file mode 100644
index 000000000..f7beaf82c
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserCreatedEvent.java
@@ -0,0 +1,21 @@
+package com.iluwatar.eda.event;
+
+import com.iluwatar.eda.model.User;
+
+/**
+ * The {@link UserCreatedEvent} should should be dispatched whenever a user has been created.
+ * This class can be extended to contain details about the user has been created. In this example,
+ * the entire {@link User} object is passed on as data with the event.
+ */
+public class UserCreatedEvent extends Event {
+
+ private User user;
+
+ public UserCreatedEvent(User user) {
+ this.user = user;
+ }
+
+ public User getUser() {
+ return user;
+ }
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
new file mode 100644
index 000000000..c07e83e7c
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/event/UserUpdatedEvent.java
@@ -0,0 +1,21 @@
+package com.iluwatar.eda.event;
+
+import com.iluwatar.eda.model.User;
+
+/**
+ * The {@link UserUpdatedEvent} should should be dispatched whenever a user has been updated.
+ * This class can be extended to contain details about the user has been updated. In this example,
+ * the entire {@link User} object is passed on as data with the event.
+ */
+public class UserUpdatedEvent extends Event {
+
+ private User user;
+
+ public UserUpdatedEvent(User user) {
+ this.user = user;
+ }
+
+ public User getUser() {
+ return user;
+ }
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
new file mode 100644
index 000000000..d5436acbf
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/EventDispatcher.java
@@ -0,0 +1,41 @@
+package com.iluwatar.eda.framework;
+
+import com.iluwatar.eda.event.Event;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Handles the routing of {@link Event} messages to associated handlers.
+ * A {@link HashMap} is used to store the association between events and their respective handlers.
+ *
+ */
+public class EventDispatcher {
+
+ private Map, Handler>> handlers;
+
+ public EventDispatcher() {
+ handlers = new HashMap<>();
+ }
+
+ /**
+ * Links an {@link Event} to a specific {@link Handler}.
+ *
+ * @param eventType The {@link Event} to be registered
+ * @param handler The {@link Handler} that will be handling the {@link Event}
+ */
+ public void registerChannel(Class extends Event> eventType,
+ Handler> handler) {
+ handlers.put(eventType, handler);
+ }
+
+ /**
+ * Dispatches an {@link Event} depending on it's type.
+ *
+ * @param event The {@link Event} to be dispatched
+ */
+ public void onEvent(Event event) {
+ handlers.get(event.getClass()).onEvent(event);
+ }
+
+}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java
new file mode 100644
index 000000000..cba2f08b2
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Handler.java
@@ -0,0 +1,18 @@
+package com.iluwatar.eda.framework;
+
+import com.iluwatar.eda.event.Event;
+
+/**
+ * This interface can be implemented to handle different types of messages.
+ * Every handler is responsible for a single of type message
+ */
+public interface Handler {
+
+ /**
+ * The onEvent method should implement and handle behavior related to the event.
+ * This can be as simple as calling another service to handle the event on publishing the event on
+ * a queue to be consumed by other sub systems.
+ * @param event the {@link Event} object to be handled.
+ */
+ void onEvent(Event event);
+}
\ No newline at end of file
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Message.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Message.java
new file mode 100644
index 000000000..f8f8c7dfc
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/framework/Message.java
@@ -0,0 +1,15 @@
+package com.iluwatar.eda.framework;
+
+/**
+ * A {@link Message} is an object with a specific type that is associated
+ * to a specific {@link Handler}.
+ */
+public interface Message {
+
+ /**
+ * Returns the message type as a {@link Class} object. In this example the message type is
+ * used to handle events by their type.
+ * @return the message type as a {@link Class}.
+ */
+ Class extends Message> getType();
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java
new file mode 100644
index 000000000..7db4a2d81
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserCreatedEventHandler.java
@@ -0,0 +1,18 @@
+package com.iluwatar.eda.handler;
+
+import com.iluwatar.eda.event.Event;
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.framework.Handler;
+
+/**
+ * Handles the {@link UserCreatedEvent} message.
+ */
+public class UserCreatedEventHandler implements Handler {
+
+ @Override
+ public void onEvent(Event message) {
+
+ UserCreatedEvent userCreatedEvent = (UserCreatedEvent) message;
+ System.out.printf("User with %s has been Created!", userCreatedEvent.getUser().getUsername());
+ }
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java
new file mode 100644
index 000000000..754a75c45
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/handler/UserUpdatedEventHandler.java
@@ -0,0 +1,18 @@
+package com.iluwatar.eda.handler;
+
+import com.iluwatar.eda.event.Event;
+import com.iluwatar.eda.event.UserUpdatedEvent;
+import com.iluwatar.eda.framework.Handler;
+
+/**
+ * Handles the {@link UserUpdatedEvent} message.
+ */
+public class UserUpdatedEventHandler implements Handler {
+
+ @Override
+ public void onEvent(Event message) {
+
+ UserUpdatedEvent userUpdatedEvent = (UserUpdatedEvent) message;
+ System.out.printf("User with %s has been Updated!", userUpdatedEvent.getUser().getUsername());
+ }
+}
diff --git a/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
new file mode 100644
index 000000000..02a7a4641
--- /dev/null
+++ b/event-driven-architecture/src/main/java/com/iluwatar/eda/model/User.java
@@ -0,0 +1,21 @@
+package com.iluwatar.eda.model;
+
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.event.UserUpdatedEvent;
+
+/**
+ * This {@link User} class is a basic pojo used to demonstrate user data sent along with
+ * the {@link UserCreatedEvent} and {@link UserUpdatedEvent} events.
+ */
+public class User {
+
+ private String username;
+
+ public User(String username) {
+ this.username = username;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+}
diff --git a/event-driven-architecture/src/test/java/com/iluwatar/eda/event/UserCreatedEventTest.java b/event-driven-architecture/src/test/java/com/iluwatar/eda/event/UserCreatedEventTest.java
new file mode 100644
index 000000000..108280bf1
--- /dev/null
+++ b/event-driven-architecture/src/test/java/com/iluwatar/eda/event/UserCreatedEventTest.java
@@ -0,0 +1,24 @@
+package com.iluwatar.eda.event;
+
+import com.iluwatar.eda.model.User;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * {@link UserCreatedEventTest} tests and verifies {@link Event} behaviour.
+ */
+public class UserCreatedEventTest {
+
+ /**
+ * This unit test should correctly return the {@link Event} class type when calling the
+ * {@link Event#getType() getType} method.
+ */
+ @Test
+ public void testGetEventType() {
+ User user = new User("iluwatar");
+ UserCreatedEvent userCreatedEvent = new UserCreatedEvent(user);
+ assertEquals(UserCreatedEvent.class, userCreatedEvent.getType());
+ }
+}
diff --git a/event-driven-architecture/src/test/java/com/iluwatar/eda/framework/EventDispatcherTest.java b/event-driven-architecture/src/test/java/com/iluwatar/eda/framework/EventDispatcherTest.java
new file mode 100644
index 000000000..163ffed6e
--- /dev/null
+++ b/event-driven-architecture/src/test/java/com/iluwatar/eda/framework/EventDispatcherTest.java
@@ -0,0 +1,50 @@
+package com.iluwatar.eda.framework;
+
+import com.iluwatar.eda.framework.EventDispatcher;
+import com.iluwatar.eda.event.UserCreatedEvent;
+import com.iluwatar.eda.event.UserUpdatedEvent;
+import com.iluwatar.eda.handler.UserCreatedEventHandler;
+import com.iluwatar.eda.handler.UserUpdatedEventHandler;
+import com.iluwatar.eda.model.User;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Event Dispatcher unit tests to assert and verify correct event dispatcher behaviour
+ */
+public class EventDispatcherTest {
+
+ /**
+ * This unit test should register events and event handlers correctly with the event dispatcher
+ * and events should be dispatched accordingly.
+ */
+ @Test
+ public void testEventDriverPattern() {
+
+ EventDispatcher dispatcher = spy(new EventDispatcher());
+ UserCreatedEventHandler userCreatedEventHandler = spy(new UserCreatedEventHandler());
+ UserUpdatedEventHandler userUpdatedEventHandler = spy(new UserUpdatedEventHandler());
+ dispatcher.registerChannel(UserCreatedEvent.class, userCreatedEventHandler);
+ dispatcher.registerChannel(UserUpdatedEvent.class, userUpdatedEventHandler);
+
+ User user = new User("iluwatar");
+
+ UserCreatedEvent userCreatedEvent = new UserCreatedEvent(user);
+ UserUpdatedEvent userUpdatedEvent = new UserUpdatedEvent(user);
+
+ //fire a userCreatedEvent and verify that userCreatedEventHandler has been invoked.
+ dispatcher.onEvent(userCreatedEvent);
+ verify(userCreatedEventHandler).onEvent(userCreatedEvent);
+ verify(dispatcher).onEvent(userCreatedEvent);
+
+ //fire a userCreatedEvent and verify that userUpdatedEventHandler has been invoked.
+ dispatcher.onEvent(userUpdatedEvent);
+ verify(userUpdatedEventHandler).onEvent(userUpdatedEvent);
+ verify(dispatcher).onEvent(userUpdatedEvent);
+ }
+
+
+}
diff --git a/exclude-pmd.properties b/exclude-pmd.properties
new file mode 100644
index 000000000..d97b3b827
--- /dev/null
+++ b/exclude-pmd.properties
@@ -0,0 +1,3 @@
+com.iluwatar.servicelayer.common.BaseEntity=UnusedPrivateField
+com.iluwatar.doublechecked.locking.App=EmptyStatementNotInLoop,EmptyWhileStmt
+com.iluwatar.doublechecked.locking.InventoryTest=EmptyStatementNotInLoop,EmptyWhileStmt
diff --git a/execute-around/index.md b/execute-around/index.md
index 56ece4ac4..ec543bdc7 100644
--- a/execute-around/index.md
+++ b/execute-around/index.md
@@ -4,16 +4,21 @@ title: Execute Around
folder: execute-around
permalink: /patterns/execute-around/
categories: Other
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Idiom
---
-**Intent:** Execute Around idiom frees the user from certain actions that
+## Intent
+Execute Around idiom frees the user from certain actions that
should always be executed before and after the business method. A good example
of this is resource allocation and deallocation leaving the user to specify
only what to do with the resource.

-**Applicability:** Use the Execute Around idiom when
+## Applicability
+Use the Execute Around idiom when
* you use an API that requires methods to be called in pairs such as open/close or allocate/deallocate.
diff --git a/execute-around/pom.xml b/execute-around/pom.xml
index dd46f59cd..d644d6a0f 100644
--- a/execute-around/pom.xml
+++ b/execute-around/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTexecute-around
diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/App.java b/execute-around/src/main/java/com/iluwatar/execute/around/App.java
index 4a0648dbe..4695b8df5 100644
--- a/execute-around/src/main/java/com/iluwatar/execute/around/App.java
+++ b/execute-around/src/main/java/com/iluwatar/execute/around/App.java
@@ -17,9 +17,6 @@ public class App {
/**
* Program entry point
- *
- * @param args command line args
- * @throws IOException
*/
public static void main(String[] args) throws IOException {
diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/SimpleFileWriter.java b/execute-around/src/main/java/com/iluwatar/execute/around/SimpleFileWriter.java
index be89ff9ce..e1a9073ef 100644
--- a/execute-around/src/main/java/com/iluwatar/execute/around/SimpleFileWriter.java
+++ b/execute-around/src/main/java/com/iluwatar/execute/around/SimpleFileWriter.java
@@ -11,6 +11,9 @@ import java.io.IOException;
*/
public class SimpleFileWriter {
+ /**
+ * Constructor
+ */
public SimpleFileWriter(String filename, FileWriterAction action) throws IOException {
FileWriter writer = new FileWriter(filename);
try {
diff --git a/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java
index 9eb3dbf5f..80dff657b 100644
--- a/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java
+++ b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java
@@ -1,13 +1,11 @@
package com.iluwatar.execute.around;
-import java.io.File;
-import java.io.IOException;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import com.iluwatar.execute.around.App;
+import java.io.File;
+import java.io.IOException;
/**
*
diff --git a/execute-around/src/test/java/com/iluwatar/execute/around/SimpleFileWriterTest.java b/execute-around/src/test/java/com/iluwatar/execute/around/SimpleFileWriterTest.java
index 168026b65..1f4380fe4 100644
--- a/execute-around/src/test/java/com/iluwatar/execute/around/SimpleFileWriterTest.java
+++ b/execute-around/src/test/java/com/iluwatar/execute/around/SimpleFileWriterTest.java
@@ -10,7 +10,6 @@ import java.io.IOException;
import java.nio.file.Files;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
/**
@@ -65,7 +64,7 @@ public class SimpleFileWriterTest {
* Verify if an {@link IOException} during the write ripples through
*/
@Test(expected = IOException.class)
- public void testIOException() throws Exception {
+ public void testIoException() throws Exception {
final File temporaryFile = this.testFolder.newFile();
new SimpleFileWriter(temporaryFile.getPath(), writer -> {
throw new IOException("");
diff --git a/facade/index.md b/facade/index.md
index 59ff888b2..c416552c7 100644
--- a/facade/index.md
+++ b/facade/index.md
@@ -7,19 +7,22 @@ categories: Structural
tags:
- Java
- Gang Of Four
+ - Difficulty-Beginner
---
-**Intent:** Provide a unified interface to a set of interfaces in a subsystem.
+## Intent
+Provide a unified interface to a set of interfaces in a subsystem.
Facade defines a higher-level interface that makes the subsystem easier to use.

-**Applicability:** Use the Facade pattern when
+## Applicability
+Use the Facade pattern when
* you want to provide a simple interface to a complex subsystem. Subsystems often get more complex as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the subsystem more reusable and easier to customize, but it also becomes harder to use for clients that don't need to customize it. A facade can provide a simple default view of the subsystem that is good enough for most clients. Only clients needing more customizability will need to look beyond the facade.
* there are many dependencies between clients and the implementation classes of an abstraction. Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting subsystem independence and portability.
* you want to layer your subsystems. Use a facade to define an entry point to each subsystem level. If subsystems are dependent, the you can simplify the dependencies between them by making them communicate with each other solely through their facades
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/facade/pom.xml b/facade/pom.xml
index 5fec5216e..56f308ae4 100644
--- a/facade/pom.xml
+++ b/facade/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTfacade
diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java
index d6b653eaa..fd37e40c5 100644
--- a/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java
+++ b/facade/src/main/java/com/iluwatar/facade/DwarvenGoldmineFacade.java
@@ -16,6 +16,9 @@ public class DwarvenGoldmineFacade {
private final List workers;
+ /**
+ * Constructor
+ */
public DwarvenGoldmineFacade() {
workers = new ArrayList<>();
workers.add(new DwarvenGoldDigger());
diff --git a/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java b/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java
index d329fe84b..3190c9365 100644
--- a/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java
+++ b/facade/src/main/java/com/iluwatar/facade/DwarvenMineWorker.java
@@ -46,6 +46,9 @@ public abstract class DwarvenMineWorker {
}
}
+ /**
+ * Perform actions
+ */
public void action(Action... actions) {
for (Action action : actions) {
action(action);
diff --git a/facade/src/test/java/com/iluwatar/facade/AppTest.java b/facade/src/test/java/com/iluwatar/facade/AppTest.java
index 49b7c01c4..3de38f26e 100644
--- a/facade/src/test/java/com/iluwatar/facade/AppTest.java
+++ b/facade/src/test/java/com/iluwatar/facade/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.facade;
import org.junit.Test;
-import com.iluwatar.facade.App;
-
/**
*
* Application test
diff --git a/factory-method/index.md b/factory-method/index.md
index 3568a1109..42237883d 100644
--- a/factory-method/index.md
+++ b/factory-method/index.md
@@ -10,20 +10,23 @@ tags:
- Gang Of Four
---
-**Also known as:** Virtual Constructor
+## Also known as
+Virtual Constructor
-**Intent:** Define an interface for creating an object, but let subclasses
+## Intent
+Define an interface for creating an object, but let subclasses
decide which class to instantiate. Factory Method lets a class defer
instantiation to subclasses.

-**Applicability:** Use the Factory Method pattern when
+## Applicability
+Use the Factory Method pattern when
* a class can't anticipate the class of objects it must create
* a class wants its subclasses to specify the objects it creates
* classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/factory-method/pom.xml b/factory-method/pom.xml
index 23ef0e774..f3dc2646a 100644
--- a/factory-method/pom.xml
+++ b/factory-method/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTfactory-method
diff --git a/fluentinterface/index.md b/fluentinterface/index.md
index 27a4d1a26..767792da7 100644
--- a/fluentinterface/index.md
+++ b/fluentinterface/index.md
@@ -7,11 +7,13 @@ categories: Other
tags:
- Java
- Difficulty-Intermediate
+ - Functional
---
-**Intent:** A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
+## Intent
+A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific language. Using this pattern results in code that can be read nearly as human language.
-**Implementation:**
+## Implementation
A fluent interface can be implemented using any of
@@ -21,13 +23,13 @@ A fluent interface can be implemented using any of

-
-**Applicability:** Use the Fluent Interface pattern when
+## Applicability
+Use the Fluent Interface pattern when
* you provide an API that would benefit from a DSL-like usage
* you have objects that are difficult to configure or use
-**Real world examples:**
+## Real world examples
* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html)
* [Google Guava FluentInterable](https://github.com/google/guava/wiki/FunctionalExplained)
@@ -35,7 +37,7 @@ A fluent interface can be implemented using any of
* [Mockito](http://mockito.org/)
* [Java Hamcrest](http://code.google.com/p/hamcrest/wiki/Tutorial)
-**Credits**
+## Credits
* [Fluent Interface - Martin Fowler](http://www.martinfowler.com/bliki/FluentInterface.html)
* [Evolutionary architecture and emergent design: Fluent interfaces - Neal Ford](http://www.ibm.com/developerworks/library/j-eaed14/)
diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml
index ff10a3814..1260bad3d 100644
--- a/fluentinterface/pom.xml
+++ b/fluentinterface/pom.xml
@@ -5,7 +5,7 @@
java-design-patternscom.iluwatar
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOT4.0.0
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
index bdff83e17..4e5ab3767 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java
@@ -1,15 +1,19 @@
package com.iluwatar.fluentinterface.app;
+import static java.lang.String.valueOf;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringJoiner;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable;
import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable;
-import java.util.*;
-import java.util.function.Function;
-import java.util.function.Predicate;
-
-import static java.lang.String.valueOf;
-
/**
* The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API.
* Those interfaces tend to mimic domain specific languages, so they can nearly be read as human
@@ -24,6 +28,9 @@ import static java.lang.String.valueOf;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) {
List integerList = new ArrayList<>();
@@ -58,7 +65,7 @@ public class App {
List lastTwoOfFirstFourStringMapped =
LazyFluentIterable.from(integerList).filter(positives()).first(4).last(2)
- .map(number -> "String[" + String.valueOf(number) + "]").asList();
+ .map(number -> "String[" + valueOf(number) + "]").asList();
prettyPrint(
"The lazy list contains the last two of the first four positive numbers mapped to Strings: ",
lastTwoOfFirstFourStringMapped);
@@ -78,19 +85,19 @@ public class App {
}
private static Predicate super Integer> negatives() {
- return integer -> (integer < 0);
+ return integer -> integer < 0;
}
private static Predicate super Integer> positives() {
- return integer -> (integer > 0);
+ return integer -> integer > 0;
}
private static void prettyPrint(String prefix, Iterable iterable) {
- prettyPrint(", ", prefix, ".", iterable);
+ prettyPrint(", ", prefix, iterable);
}
- private static void prettyPrint(String delimiter, String prefix, String suffix,
- Iterable iterable) {
+ private static void prettyPrint(String delimiter, String prefix,
+ Iterable iterable) {
StringJoiner joiner = new StringJoiner(delimiter, prefix, ".");
Iterator iterator = iterable.iterator();
while (iterator.hasNext()) {
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java
index e80356d8e..dae300c4e 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java
@@ -5,8 +5,6 @@ import java.util.Iterator;
/**
* This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not
* support consecutive hasNext() calls.
- *
- * @param
*/
public abstract class DecoratingIterator implements Iterator {
@@ -16,8 +14,6 @@ public abstract class DecoratingIterator implements Iterator {
/**
* Creates an iterator that decorates the given iterator.
- *
- * @param fromIterator
*/
public DecoratingIterator(Iterator fromIterator) {
this.fromIterator = fromIterator;
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
index 44f095289..e887ad556 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java
@@ -53,10 +53,9 @@ public class LazyFluentIterable implements FluentIterable {
public TYPE computeNext() {
while (fromIterator.hasNext()) {
TYPE candidate = fromIterator.next();
- if (!predicate.test(candidate)) {
- continue;
+ if (predicate.test(candidate)) {
+ return candidate;
}
- return candidate;
}
return null;
@@ -94,12 +93,10 @@ public class LazyFluentIterable implements FluentIterable {
@Override
public TYPE computeNext() {
- if (currentIndex < count) {
- if (fromIterator.hasNext()) {
- TYPE candidate = fromIterator.next();
- currentIndex++;
- return candidate;
- }
+ if (currentIndex < count && fromIterator.hasNext()) {
+ TYPE candidate = fromIterator.next();
+ currentIndex++;
+ return candidate;
}
return null;
}
@@ -188,11 +185,12 @@ public class LazyFluentIterable implements FluentIterable {
@Override
public NEW_TYPE computeNext() {
- while (oldTypeIterator.hasNext()) {
+ if (oldTypeIterator.hasNext()) {
TYPE candidate = oldTypeIterator.next();
return function.apply(candidate);
+ } else {
+ return null;
}
- return null;
}
};
}
diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java
index 19283152e..ef1859529 100644
--- a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java
+++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java
@@ -1,12 +1,16 @@
package com.iluwatar.fluentinterface.fluentiterable.simple;
-import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
-
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Optional;
+import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
+
/**
* This is a simple implementation of the FluentIterable interface. It evaluates all chained
* operations eagerly. This implementation would be costly to be utilized in real applications.
diff --git a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java
index 29ad885c0..2268b0428 100644
--- a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java
+++ b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.fluentinterface.app;
import org.junit.Test;
-import com.iluwatar.fluentinterface.app.App;
-
public class AppTest {
@Test
diff --git a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterableTest.java b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterableTest.java
index 7d4cb0530..baabbe096 100644
--- a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterableTest.java
+++ b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterableTest.java
@@ -2,21 +2,11 @@ package com.iluwatar.fluentinterface.fluentiterable;
import org.junit.Test;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Optional;
-import java.util.Spliterator;
+import java.util.*;
import java.util.function.Consumer;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
/**
* Date: 12/12/15 - 7:00 PM
@@ -26,7 +16,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
public abstract class FluentIterableTest {
/**
- * Create a new {@link FluentIterable} from the given integers
+ * Create a new {@link FluentIterable} from the given integers
*
* @param integers The integers
* @return The new iterable, use for testing
diff --git a/flux/index.md b/flux/index.md
index 227237168..7ac312c44 100644
--- a/flux/index.md
+++ b/flux/index.md
@@ -4,20 +4,24 @@ title: Flux
folder: flux
permalink: /patterns/flux/
categories: Presentation Tier
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** Flux eschews MVC in favor of a unidirectional data flow. When a
+## Intent
+Flux eschews MVC in favor of a unidirectional data flow. When a
user interacts with a view, the view propagates an action through a central
dispatcher, to the various stores that hold the application's data and business
logic, which updates all of the views that are affected.

-**Applicability:** Use the Flux pattern when
+## Applicability
+Use the Flux pattern when
* you want to focus on creating explicit and understandable update paths for your application's data, which makes tracing changes during development simpler and makes bugs easier to track down and fix.
-**Credits:**
+## Credits
* [Flux - Application architecture for building user interfaces](http://facebook.github.io/flux/)
diff --git a/flux/pom.xml b/flux/pom.xml
index 7b0afd626..aff383800 100644
--- a/flux/pom.xml
+++ b/flux/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTflux
diff --git a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
index 26c836b0e..1ff624e11 100644
--- a/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
+++ b/flux/src/main/java/com/iluwatar/flux/dispatcher/Dispatcher.java
@@ -31,6 +31,9 @@ public class Dispatcher {
stores.add(store);
}
+ /**
+ * Menu item selected handler
+ */
public void menuItemSelected(MenuItem menuItem) {
dispatchAction(new MenuAction(menuItem));
switch (menuItem) {
diff --git a/flux/src/main/java/com/iluwatar/flux/view/View.java b/flux/src/main/java/com/iluwatar/flux/view/View.java
index a642b5b2c..892527fdc 100644
--- a/flux/src/main/java/com/iluwatar/flux/view/View.java
+++ b/flux/src/main/java/com/iluwatar/flux/view/View.java
@@ -9,7 +9,7 @@ import com.iluwatar.flux.store.Store;
*/
public interface View {
- public void storeChanged(Store store);
+ void storeChanged(Store store);
- public void render();
+ void render();
}
diff --git a/flux/src/test/java/com/iluwatar/flux/app/AppTest.java b/flux/src/test/java/com/iluwatar/flux/app/AppTest.java
index 918c76acd..d833c321c 100644
--- a/flux/src/test/java/com/iluwatar/flux/app/AppTest.java
+++ b/flux/src/test/java/com/iluwatar/flux/app/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.flux.app;
import org.junit.Test;
-import com.iluwatar.flux.app.App;
-
/**
*
* Application test
diff --git a/flux/src/test/java/com/iluwatar/flux/dispatcher/DispatcherTest.java b/flux/src/test/java/com/iluwatar/flux/dispatcher/DispatcherTest.java
index 8e1977dd8..7c66e7a81 100644
--- a/flux/src/test/java/com/iluwatar/flux/dispatcher/DispatcherTest.java
+++ b/flux/src/test/java/com/iluwatar/flux/dispatcher/DispatcherTest.java
@@ -7,7 +7,6 @@ import com.iluwatar.flux.action.ContentAction;
import com.iluwatar.flux.action.MenuAction;
import com.iluwatar.flux.action.MenuItem;
import com.iluwatar.flux.store.Store;
-
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
diff --git a/flux/src/test/java/com/iluwatar/flux/store/ContentStoreTest.java b/flux/src/test/java/com/iluwatar/flux/store/ContentStoreTest.java
index 7c9ce0a69..00a7a924d 100644
--- a/flux/src/test/java/com/iluwatar/flux/store/ContentStoreTest.java
+++ b/flux/src/test/java/com/iluwatar/flux/store/ContentStoreTest.java
@@ -5,7 +5,6 @@ import com.iluwatar.flux.action.ContentAction;
import com.iluwatar.flux.action.MenuAction;
import com.iluwatar.flux.action.MenuItem;
import com.iluwatar.flux.view.View;
-
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -13,8 +12,8 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Date: 12/12/15 - 10:18 PM
diff --git a/flux/src/test/java/com/iluwatar/flux/store/MenuStoreTest.java b/flux/src/test/java/com/iluwatar/flux/store/MenuStoreTest.java
index 2e7f80590..6fdc4e5d3 100644
--- a/flux/src/test/java/com/iluwatar/flux/store/MenuStoreTest.java
+++ b/flux/src/test/java/com/iluwatar/flux/store/MenuStoreTest.java
@@ -5,7 +5,6 @@ import com.iluwatar.flux.action.ContentAction;
import com.iluwatar.flux.action.MenuAction;
import com.iluwatar.flux.action.MenuItem;
import com.iluwatar.flux.view.View;
-
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -13,8 +12,8 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Date: 12/12/15 - 10:18 PM
diff --git a/flux/src/test/java/com/iluwatar/flux/view/ContentViewTest.java b/flux/src/test/java/com/iluwatar/flux/view/ContentViewTest.java
index 49cecd24a..cf452233b 100644
--- a/flux/src/test/java/com/iluwatar/flux/view/ContentViewTest.java
+++ b/flux/src/test/java/com/iluwatar/flux/view/ContentViewTest.java
@@ -2,14 +2,13 @@ package com.iluwatar.flux.view;
import com.iluwatar.flux.action.Content;
import com.iluwatar.flux.store.ContentStore;
-
import org.junit.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
/**
* Date: 12/12/15 - 10:31 PM
diff --git a/flux/src/test/java/com/iluwatar/flux/view/MenuViewTest.java b/flux/src/test/java/com/iluwatar/flux/view/MenuViewTest.java
index 2534515b0..08a601c71 100644
--- a/flux/src/test/java/com/iluwatar/flux/view/MenuViewTest.java
+++ b/flux/src/test/java/com/iluwatar/flux/view/MenuViewTest.java
@@ -5,7 +5,6 @@ import com.iluwatar.flux.action.MenuItem;
import com.iluwatar.flux.dispatcher.Dispatcher;
import com.iluwatar.flux.store.MenuStore;
import com.iluwatar.flux.store.Store;
-
import org.junit.Test;
import static org.mockito.Matchers.any;
diff --git a/flyweight/index.md b/flyweight/index.md
index e2273c197..a98dced8e 100644
--- a/flyweight/index.md
+++ b/flyweight/index.md
@@ -7,14 +7,18 @@ categories: Structural
tags:
- Java
- Gang Of Four
+ - Difficulty-Intermediate
+ - Performance
---
-**Intent:** Use sharing to support large numbers of fine-grained objects
+## Intent
+Use sharing to support large numbers of fine-grained objects
efficiently.

-**Applicability:** The Flyweight pattern's effectiveness depends heavily on how
+## Applicability
+The Flyweight pattern's effectiveness depends heavily on how
and where it's used. Apply the Flyweight pattern when all of the following are
true
@@ -24,10 +28,10 @@ true
* many groups of objects may be replaced by relatively few shared objects once extrinsic state is removed
* the application doesn't depend on object identity. Since flyweight objects may be shared, identity tests will return true for conceptually distinct objects.
-**Real world examples:**
+## Real world examples
* [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/flyweight/pom.xml b/flyweight/pom.xml
index e00f55e52..fe282ea2e 100644
--- a/flyweight/pom.xml
+++ b/flyweight/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTflyweight
diff --git a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
index a48abbcb0..8418e01e6 100644
--- a/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
+++ b/flyweight/src/main/java/com/iluwatar/flyweight/AlchemistShop.java
@@ -14,6 +14,9 @@ public class AlchemistShop {
private List topShelf;
private List bottomShelf;
+ /**
+ * Constructor
+ */
public AlchemistShop() {
topShelf = new ArrayList<>();
bottomShelf = new ArrayList<>();
@@ -58,6 +61,9 @@ public class AlchemistShop {
return Collections.unmodifiableList(this.bottomShelf);
}
+ /**
+ * Enumerate potions
+ */
public void enumerate() {
System.out.println("Enumerating top shelf potions\n");
diff --git a/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java b/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java
index 16fdb005e..5e0bd98b8 100644
--- a/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java
+++ b/flyweight/src/test/java/com/iluwatar/flyweight/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.flyweight;
import org.junit.Test;
-import com.iluwatar.flyweight.App;
-
/**
*
* Application test
diff --git a/front-controller/index.md b/front-controller/index.md
index ba593a157..a462a08e0 100644
--- a/front-controller/index.md
+++ b/front-controller/index.md
@@ -4,26 +4,30 @@ title: Front Controller
folder: front-controller
permalink: /patterns/front-controller/
categories: Presentation Tier
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** Introduce a common handler for all requests for a web site. This
+## Intent
+Introduce a common handler for all requests for a web site. This
way we can encapsulate common functionality such as security,
internationalization, routing and logging in a single place.

-**Applicability:** Use the Front Controller pattern when
+## Applicability
+Use the Front Controller pattern when
* you want to encapsulate common request handling functionality in single place
* you want to implements dynamic request handling i.e. change routing without modifying code
* make web server configuration portable, you only need to register the handler web server specific way
-**Real world examples:**
+## Real world examples
* [Apache Struts](https://struts.apache.org/)
-**Credits:**
+## Credits
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
* [Presentation Tier Patterns](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns)
diff --git a/front-controller/pom.xml b/front-controller/pom.xml
index 91ad6c1ab..3f56aaa8c 100644
--- a/front-controller/pom.xml
+++ b/front-controller/pom.xml
@@ -6,7 +6,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTfront-controller
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/App.java b/front-controller/src/main/java/com/iluwatar/front/controller/App.java
index 18a92d37d..1beac119c 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/App.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/App.java
@@ -2,32 +2,34 @@ package com.iluwatar.front.controller;
/**
*
- * The Front Controller is a presentation tier pattern. Essentially it defines a
- * controller that handles all requests for a web site.
+ * The Front Controller is a presentation tier pattern. Essentially it defines a controller that
+ * handles all requests for a web site.
*
- * The Front Controller pattern consolidates request handling through a single handler
- * object ({@link FrontController}). This object can carry out the common the behavior such as
+ * The Front Controller pattern consolidates request handling through a single handler object (
+ * {@link FrontController}). This object can carry out the common the behavior such as
* authorization, request logging and routing requests to corresponding views.
*
- * Typically the requests are mapped to command objects ({@link Command}) which then display
- * the correct view ({@link View}).
+ * Typically the requests are mapped to command objects ({@link Command}) which then display the
+ * correct view ({@link View}).
*
* In this example we have implemented two views: {@link ArcherView} and {@link CatapultView}. These
- * are displayed by sending correct request to the {@link FrontController} object. For example,
- * the {@link ArcherView} gets displayed when {@link FrontController} receives request "Archer". When
+ * are displayed by sending correct request to the {@link FrontController} object. For example, the
+ * {@link ArcherView} gets displayed when {@link FrontController} receives request "Archer". When
* the request is unknown, we display the error view ({@link ErrorView}).
*
*/
public class App {
-
- /**
- * Program entry point
- * @param args command line args
- */
- public static void main(String[] args) {
- FrontController controller = new FrontController();
- controller.handleRequest("Archer");
- controller.handleRequest("Catapult");
- controller.handleRequest("foobar");
- }
+
+ /**
+ * Program entry point
+ *
+ * @param args
+ * command line args
+ */
+ public static void main(String[] args) {
+ FrontController controller = new FrontController();
+ controller.handleRequest("Archer");
+ controller.handleRequest("Catapult");
+ controller.handleRequest("foobar");
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/ApplicationException.java b/front-controller/src/main/java/com/iluwatar/front/controller/ApplicationException.java
index b3963d8e9..bb44d34f0 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/ApplicationException.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/ApplicationException.java
@@ -7,9 +7,9 @@ package com.iluwatar.front.controller;
*/
public class ApplicationException extends RuntimeException {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1L;
- public ApplicationException(Throwable cause) {
- super(cause);
- }
+ public ApplicationException(Throwable cause) {
+ super(cause);
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/ArcherCommand.java b/front-controller/src/main/java/com/iluwatar/front/controller/ArcherCommand.java
index 117aa0c8c..8396d5cfc 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/ArcherCommand.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/ArcherCommand.java
@@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/
public class ArcherCommand implements Command {
- @Override
- public void process() {
- new ArcherView().display();
- }
+ @Override
+ public void process() {
+ new ArcherView().display();
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java b/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java
index d8cae33c1..d16fe8b71 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/ArcherView.java
@@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/
public class ArcherView implements View {
- @Override
- public void display() {
- System.out.println("Displaying archers");
- }
+ @Override
+ public void display() {
+ System.out.println("Displaying archers");
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/CatapultCommand.java b/front-controller/src/main/java/com/iluwatar/front/controller/CatapultCommand.java
index fae5d1753..b5ad9e37c 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/CatapultCommand.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/CatapultCommand.java
@@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/
public class CatapultCommand implements Command {
- @Override
- public void process() {
- new CatapultView().display();
- }
+ @Override
+ public void process() {
+ new CatapultView().display();
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java b/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java
index 9ad94d522..161b4ed4e 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/CatapultView.java
@@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/
public class CatapultView implements View {
- @Override
- public void display() {
- System.out.println("Displaying catapults");
- }
+ @Override
+ public void display() {
+ System.out.println("Displaying catapults");
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/Command.java b/front-controller/src/main/java/com/iluwatar/front/controller/Command.java
index 95bd00129..2ad41a629 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/Command.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/Command.java
@@ -6,6 +6,6 @@ package com.iluwatar.front.controller;
*
*/
public interface Command {
-
- void process();
+
+ void process();
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java b/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java
index 04c31dd34..c1045c821 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/ErrorView.java
@@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/
public class ErrorView implements View {
- @Override
- public void display() {
- System.out.println("Error 500");
- }
+ @Override
+ public void display() {
+ System.out.println("Error 500");
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java b/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java
index 0c6c132f2..6b84d7f78 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java
@@ -2,33 +2,33 @@ package com.iluwatar.front.controller;
/**
*
- * FrontController is the handler class that takes in all the requests and
- * renders the correct response.
+ * FrontController is the handler class that takes in all the requests and renders the correct
+ * response.
*
*/
public class FrontController {
-
- public void handleRequest(String request) {
- Command command = getCommand(request);
- command.process();
- }
-
- private Command getCommand(String request) {
- Class commandClass = getCommandClass(request);
- try {
- return (Command) commandClass.newInstance();
- } catch (Exception e) {
- throw new ApplicationException(e);
- }
- }
-
- private Class getCommandClass(String request) {
- Class result;
- try {
- result = Class.forName("com.iluwatar.front.controller." + request + "Command");
- } catch (ClassNotFoundException e) {
- result = UnknownCommand.class;
- }
- return result;
- }
+
+ public void handleRequest(String request) {
+ Command command = getCommand(request);
+ command.process();
+ }
+
+ private Command getCommand(String request) {
+ Class commandClass = getCommandClass(request);
+ try {
+ return (Command) commandClass.newInstance();
+ } catch (Exception e) {
+ throw new ApplicationException(e);
+ }
+ }
+
+ private Class getCommandClass(String request) {
+ Class result;
+ try {
+ result = Class.forName("com.iluwatar.front.controller." + request + "Command");
+ } catch (ClassNotFoundException e) {
+ result = UnknownCommand.class;
+ }
+ return result;
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/UnknownCommand.java b/front-controller/src/main/java/com/iluwatar/front/controller/UnknownCommand.java
index f8f93e7e0..d800d4db0 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/UnknownCommand.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/UnknownCommand.java
@@ -7,8 +7,8 @@ package com.iluwatar.front.controller;
*/
public class UnknownCommand implements Command {
- @Override
- public void process() {
- new ErrorView().display();
- }
+ @Override
+ public void process() {
+ new ErrorView().display();
+ }
}
diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/View.java b/front-controller/src/main/java/com/iluwatar/front/controller/View.java
index 29c5f0fcb..55bb187ce 100644
--- a/front-controller/src/main/java/com/iluwatar/front/controller/View.java
+++ b/front-controller/src/main/java/com/iluwatar/front/controller/View.java
@@ -7,5 +7,5 @@ package com.iluwatar.front.controller;
*/
public interface View {
- void display();
+ void display();
}
diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java b/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java
index 2c28aa8ce..cc09de662 100644
--- a/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java
+++ b/front-controller/src/test/java/com/iluwatar/front/controller/AppTest.java
@@ -2,18 +2,16 @@ package com.iluwatar.front.controller;
import org.junit.Test;
-import com.iluwatar.front.controller.App;
-
/**
*
* Application test
*
*/
public class AppTest {
-
- @Test
- public void test() {
- String[] args = {};
- App.main(args);
- }
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
}
diff --git a/front-controller/src/test/java/com/iluwatar/front/controller/ApplicationExceptionTest.java b/front-controller/src/test/java/com/iluwatar/front/controller/ApplicationExceptionTest.java
index 18bdf0d13..4b038cfda 100644
--- a/front-controller/src/test/java/com/iluwatar/front/controller/ApplicationExceptionTest.java
+++ b/front-controller/src/test/java/com/iluwatar/front/controller/ApplicationExceptionTest.java
@@ -1,8 +1,8 @@
package com.iluwatar.front.controller;
-import org.junit.Test;
+import static org.junit.Assert.assertSame;
-import static org.junit.Assert.*;
+import org.junit.Test;
/**
* Date: 12/13/15 - 1:35 PM
diff --git a/half-sync-half-async/index.md b/half-sync-half-async/index.md
index dc1930e3b..8a091f813 100644
--- a/half-sync-half-async/index.md
+++ b/half-sync-half-async/index.md
@@ -4,16 +4,20 @@ title: Half-Sync/Half-Async
folder: half-sync-half-async
permalink: /patterns/half-sync-half-async/
categories: Concurrency
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** The Half-Sync/Half-Async pattern decouples synchronous I/O from
+## Intent
+The Half-Sync/Half-Async pattern decouples synchronous I/O from
asynchronous I/O in a system to simplify concurrent programming effort without
degrading execution efficiency.

-**Applicability:** Use Half-Sync/Half-Async pattern when
+## Applicability
+Use Half-Sync/Half-Async pattern when
* a system possesses following characteristics:
* the system must perform tasks in response to external events that occur asynchronously, like hardware interrupts in OS
@@ -21,13 +25,13 @@ degrading execution efficiency.
* the higher level tasks in the system can be simplified significantly if I/O is performed synchronously.
* one or more tasks in a system must run in a single thread of control, while other tasks may benefit from multi-threading.
-**Real world examples:**
+## Real world examples
* [BSD Unix networking subsystem](http://www.cs.wustl.edu/~schmidt/PDF/PLoP-95.pdf)
* [Real Time CORBA](http://www.omg.org/news/meetings/workshops/presentations/realtime2001/4-3_Pyarali_thread-pool.pdf)
* [Android AsyncTask framework](http://developer.android.com/reference/android/os/AsyncTask.html)
-**Credits:**
+## Credits
* [Douglas C. Schmidt and Charles D. Cranor - Half Sync/Half Async](http://www.cs.wustl.edu/~schmidt/PDF/PLoP-95.pdf)
* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697)
diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml
index ce8689cee..7ea1a203b 100644
--- a/half-sync-half-async/pom.xml
+++ b/half-sync-half-async/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOThalf-sync-half-async
diff --git a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java
index 80f2eefb2..b67b602ca 100644
--- a/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java
+++ b/half-sync-half-async/src/main/java/com/iluwatar/halfsynchalfasync/App.java
@@ -21,17 +21,15 @@ import java.util.concurrent.LinkedBlockingQueue;
*
*
* APPLICABILITY
- *
- *
UNIX network subsystems - In operating systems network operations are carried out
- * asynchronously with help of hardware level interrupts.
- *
CORBA - At the asynchronous layer one thread is associated with each socket that is connected
+ * UNIX network subsystems - In operating systems network operations are carried out
+ * asynchronously with help of hardware level interrupts.
+ * CORBA - At the asynchronous layer one thread is associated with each socket that is connected
* to the client. Thread blocks waiting for CORBA requests from the client. On receiving request it
* is inserted in the queuing layer which is then picked up by synchronous layer which processes the
- * request and sends response back to the client.
- *
Android AsyncTask framework - Framework provides a way to execute long running blocking
+ * request and sends response back to the client.
+ * Android AsyncTask framework - Framework provides a way to execute long running blocking
* calls, such as downloading a file, in background threads so that the UI thread remains free to
- * respond to user inputs.
- *
+ * respond to user inputs.
*
*
* IMPLEMENTATION
@@ -121,6 +119,7 @@ public class App {
try {
Thread.sleep(i);
} catch (InterruptedException e) {
+ System.out.println(e);
}
return (i) * (i + 1) / 2;
}
diff --git a/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AsynchronousServiceTest.java b/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AsynchronousServiceTest.java
index 01c905039..16b51d0b5 100644
--- a/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AsynchronousServiceTest.java
+++ b/half-sync-half-async/src/test/java/com/iluwatar/halfsynchalfasync/AsynchronousServiceTest.java
@@ -7,14 +7,7 @@ import java.io.IOException;
import java.util.concurrent.LinkedBlockingQueue;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.timeout;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
/**
* Date: 12/12/15 - 11:15 PM
diff --git a/intercepting-filter/index.md b/intercepting-filter/index.md
index 41825745b..327f091b1 100644
--- a/intercepting-filter/index.md
+++ b/intercepting-filter/index.md
@@ -4,25 +4,29 @@ title: Intercepting Filter
folder: intercepting-filter
permalink: /patterns/intercepting-filter/
categories: Behavioral
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** Provide pluggable filters to conduct necessary pre-processing and
+## Intent
+Provide pluggable filters to conduct necessary pre-processing and
post-processing to requests from a client to a target

-**Applicability:** Use the Intercepting Filter pattern when
+## Applicability
+Use the Intercepting Filter pattern when
* a system uses pre-processing or post-processing requests
* a system should do the authentication/ authorization/ logging or tracking of request and then pass the requests to corresponding handlers
* you want a modular approach to configuring pre-processing and post-processing schemes
-**Real world examples:**
+## Real world examples
* [Struts 2 - Interceptors](https://struts.apache.org/docs/interceptors.html)
-**Credits:**
+## Credits
* [TutorialsPoint - Intercepting Filter](http://www.tutorialspoint.com/design_pattern/intercepting_filter_pattern.htm)
* [Presentation Tier Patterns](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns)
diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml
index 2c10af5d0..d18126ba9 100644
--- a/intercepting-filter/pom.xml
+++ b/intercepting-filter/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTintercepting-filter
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/AddressFilter.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/AddressFilter.java
index c1aa0780b..38a762483 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/AddressFilter.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/AddressFilter.java
@@ -14,7 +14,8 @@ public class AddressFilter extends AbstractFilter {
String result = super.execute(order);
if (order.getAddress() == null || order.getAddress().isEmpty()) {
return result + "Invalid address! ";
- } else
+ } else {
return result;
+ }
}
}
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java
index 817ae7587..f0a2267d2 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java
@@ -34,7 +34,7 @@ public class App {
* @param args command line args
*/
public static void main(String[] args) {
- FilterManager filterManager = new FilterManager(new Target());
+ FilterManager filterManager = new FilterManager();
filterManager.addFilter(new NameFilter());
filterManager.addFilter(new ContactFilter());
filterManager.addFilter(new AddressFilter());
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java
index 02499ed0a..5934da75c 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Client.java
@@ -32,8 +32,12 @@ public class Client extends JFrame {
private JLabel jl;
private JTextField[] jtFields;
private JTextArea[] jtAreas;
- private JButton clearButton, processButton;
+ private JButton clearButton;
+ private JButton processButton;
+ /**
+ * Constructor
+ */
public Client() {
super("Client System");
setDefaultCloseOperation(EXIT_ON_CLOSE);
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Filter.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Filter.java
index 9496bde36..a1ea5b4ee 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Filter.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Filter.java
@@ -11,30 +11,21 @@ public interface Filter {
/**
* Execute order processing filter.
- *
- * @param order
- * @return empty string on success, otherwise error message.
*/
String execute(Order order);
/**
* Set next filter in chain after this.
- *
- * @param filter
*/
void setNext(Filter filter);
/**
* Get next filter in chain after this.
- *
- * @return
*/
Filter getNext();
/**
* Get last filter in the chain.
- *
- * @return
*/
Filter getLast();
}
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java
index 987678cc7..e8f3ca70f 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterChain.java
@@ -10,12 +10,15 @@ public class FilterChain {
private Filter chain;
- private final Target target;
-
- public FilterChain(Target target) {
- this.target = target;
+ /**
+ * Constructor
+ */
+ public FilterChain() {
}
+ /**
+ * Adds filter
+ */
public void addFilter(Filter filter) {
if (chain == null) {
chain = filter;
@@ -24,6 +27,9 @@ public class FilterChain {
}
}
+ /**
+ * Execute filter chain
+ */
public String execute(Order order) {
if (chain != null) {
return chain.execute(order);
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
index 7cdaab103..d6e01598e 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/FilterManager.java
@@ -10,8 +10,8 @@ public class FilterManager {
private FilterChain filterChain;
- public FilterManager(Target target) {
- filterChain = new FilterChain(target);
+ public FilterManager() {
+ filterChain = new FilterChain();
}
public void addFilter(Filter filter) {
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java
index 5b30fee35..53d1a3dd9 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Order.java
@@ -14,6 +14,9 @@ public class Order {
public Order() {}
+ /**
+ * Constructor
+ */
public Order(String name, String contactNumber, String address, String depositNumber, String order) {
this.name = name;
this.contactNumber = contactNumber;
diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java
index cb96cd6e0..ffb13c160 100644
--- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java
+++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/Target.java
@@ -29,6 +29,9 @@ public class Target extends JFrame {
private DefaultTableModel dtm;
private JButton del;
+ /**
+ * Constructor
+ */
public Target() {
super("Order System");
setDefaultCloseOperation(EXIT_ON_CLOSE);
@@ -67,8 +70,9 @@ public class Target extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
int temp = jt.getSelectedRow();
- if (temp == -1)
+ if (temp == -1) {
return;
+ }
int temp2 = jt.getSelectedRowCount();
for (int i = 0; i < temp2; i++) {
dtm.removeRow(temp);
diff --git a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java
index bcdf7c09b..9abdcc181 100644
--- a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java
+++ b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.intercepting.filter;
import org.junit.Test;
-import com.iluwatar.intercepting.filter.App;
-
/**
*
* Application test.
diff --git a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterManagerTest.java b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterManagerTest.java
index 6806cd70a..022bd7586 100644
--- a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterManagerTest.java
+++ b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterManagerTest.java
@@ -20,7 +20,7 @@ public class FilterManagerTest {
@Test
public void testFilterRequest() throws Exception {
final Target target = mock(Target.class);
- final FilterManager filterManager = new FilterManager(target);
+ final FilterManager filterManager = new FilterManager();
assertEquals("RUNNING...", filterManager.filterRequest(mock(Order.class)));
verifyZeroInteractions(target);
}
@@ -28,7 +28,7 @@ public class FilterManagerTest {
@Test
public void testAddFilter() throws Exception {
final Target target = mock(Target.class);
- final FilterManager filterManager = new FilterManager(target);
+ final FilterManager filterManager = new FilterManager();
verifyZeroInteractions(target);
diff --git a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterTest.java b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterTest.java
index f15760f08..71d9bf250 100644
--- a/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterTest.java
+++ b/intercepting-filter/src/test/java/com/iluwatar/intercepting/filter/FilterTest.java
@@ -73,6 +73,9 @@ public class FilterTest {
private final Order order;
private final String result;
+ /**
+ * Constructor
+ */
public FilterTest(Filter filter, Order order, String result) {
this.filter = filter;
this.order = order;
diff --git a/interpreter/index.md b/interpreter/index.md
index 57b117e06..87c1c47f7 100644
--- a/interpreter/index.md
+++ b/interpreter/index.md
@@ -7,21 +7,24 @@ categories: Behavioral
tags:
- Java
- Gang Of Four
+ - Difficulty-Intermediate
---
-**Intent:** Given a language, define a representation for its grammar along
+## Intent
+Given a language, define a representation for its grammar along
with an interpreter that uses the representation to interpret sentences in the
language.

-**Applicability:** Use the Interpreter pattern when there is a language to
+## Applicability
+Use the Interpreter pattern when there is a language to
interpret, and you can represent statements in the language as abstract syntax
trees. The Interpreter pattern works best when
* the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time
* efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/interpreter/pom.xml b/interpreter/pom.xml
index 8e51c2ecb..72fd0d51b 100644
--- a/interpreter/pom.xml
+++ b/interpreter/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTinterpreter
diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/App.java b/interpreter/src/main/java/com/iluwatar/interpreter/App.java
index 2f88951f1..e4e238c15 100644
--- a/interpreter/src/main/java/com/iluwatar/interpreter/App.java
+++ b/interpreter/src/main/java/com/iluwatar/interpreter/App.java
@@ -55,6 +55,9 @@ public class App {
return s.equals("+") || s.equals("-") || s.equals("*");
}
+ /**
+ * Get expression for string
+ */
public static Expression getOperatorInstance(String s, Expression left, Expression right) {
switch (s) {
case "+":
@@ -63,7 +66,8 @@ public class App {
return new MinusExpression(left, right);
case "*":
return new MultiplyExpression(left, right);
+ default:
+ return new MultiplyExpression(left, right);
}
- return null;
}
}
diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java
index cb7e957c9..be696f072 100644
--- a/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java
+++ b/interpreter/src/test/java/com/iluwatar/interpreter/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.interpreter;
import org.junit.Test;
-import com.iluwatar.interpreter.App;
-
/**
*
* Application test
diff --git a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java
index 2cdee9966..150596cd8 100644
--- a/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java
+++ b/interpreter/src/test/java/com/iluwatar/interpreter/ExpressionTest.java
@@ -27,9 +27,9 @@ public abstract class ExpressionTest {
for (int i = -10; i < 10; i++) {
for (int j = -10; j < 10; j++) {
testData.add(new Object[]{
- new NumberExpression(i),
- new NumberExpression(j),
- resultCalc.apply(i, j)
+ new NumberExpression(i),
+ new NumberExpression(j),
+ resultCalc.apply(i, j)
});
}
}
diff --git a/iterator/index.md b/iterator/index.md
index fe6c1fe35..d6be7758d 100644
--- a/iterator/index.md
+++ b/iterator/index.md
@@ -10,23 +10,26 @@ tags:
- Gang Of Four
---
-**Also known as:** Cursor
+## Also known as
+Cursor
-**Intent:** Provide a way to access the elements of an aggregate object
+## Intent
+Provide a way to access the elements of an aggregate object
sequentially without exposing its underlying representation.

-**Applicability:** Use the Iterator pattern
+## Applicability
+Use the Iterator pattern
* to access an aggregate object's contents without exposing its internal representation
* to support multiple traversals of aggregate objects
* to provide a uniform interface for traversing different aggregate structures
-**Real world examples:**
+## Real world examples
* [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/iterator/pom.xml b/iterator/pom.xml
index 6f8cd993a..9f57dedb6 100644
--- a/iterator/pom.xml
+++ b/iterator/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTiterator
diff --git a/iterator/src/main/java/com/iluwatar/iterator/App.java b/iterator/src/main/java/com/iluwatar/iterator/App.java
index c9c5fa521..467040ca6 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/App.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/App.java
@@ -20,28 +20,28 @@ public class App {
public static void main(String[] args) {
TreasureChest chest = new TreasureChest();
- ItemIterator ringIterator = chest.Iterator(ItemType.RING);
+ ItemIterator ringIterator = chest.iterator(ItemType.RING);
while (ringIterator.hasNext()) {
System.out.println(ringIterator.next());
}
System.out.println("----------");
- ItemIterator potionIterator = chest.Iterator(ItemType.POTION);
+ ItemIterator potionIterator = chest.iterator(ItemType.POTION);
while (potionIterator.hasNext()) {
System.out.println(potionIterator.next());
}
System.out.println("----------");
- ItemIterator weaponIterator = chest.Iterator(ItemType.WEAPON);
+ ItemIterator weaponIterator = chest.iterator(ItemType.WEAPON);
while (weaponIterator.hasNext()) {
System.out.println(weaponIterator.next());
}
System.out.println("----------");
- ItemIterator it = chest.Iterator(ItemType.ANY);
+ ItemIterator it = chest.iterator(ItemType.ANY);
while (it.hasNext()) {
System.out.println(it.next());
}
diff --git a/iterator/src/main/java/com/iluwatar/iterator/TreasureChest.java b/iterator/src/main/java/com/iluwatar/iterator/TreasureChest.java
index 02496e33c..6b5c54a5a 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/TreasureChest.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/TreasureChest.java
@@ -12,6 +12,9 @@ public class TreasureChest {
private List items;
+ /**
+ * Constructor
+ */
public TreasureChest() {
items = new ArrayList<>();
items.add(new Item(ItemType.POTION, "Potion of courage"));
@@ -26,10 +29,13 @@ public class TreasureChest {
items.add(new Item(ItemType.WEAPON, "Dagger of poison"));
}
- ItemIterator Iterator(ItemType type) {
- return new TreasureChestItemIterator(this, type);
+ ItemIterator iterator(ItemType itemType) {
+ return new TreasureChestItemIterator(this, itemType);
}
+ /**
+ * Get all items
+ */
public List getItems() {
ArrayList list = new ArrayList<>();
list.addAll(items);
diff --git a/iterator/src/main/java/com/iluwatar/iterator/TreasureChestItemIterator.java b/iterator/src/main/java/com/iluwatar/iterator/TreasureChestItemIterator.java
index 39c12ab44..a8303f308 100644
--- a/iterator/src/main/java/com/iluwatar/iterator/TreasureChestItemIterator.java
+++ b/iterator/src/main/java/com/iluwatar/iterator/TreasureChestItemIterator.java
@@ -13,6 +13,9 @@ public class TreasureChestItemIterator implements ItemIterator {
private int idx;
private ItemType type;
+ /**
+ * Constructor
+ */
public TreasureChestItemIterator(TreasureChest chest, ItemType type) {
this.chest = chest;
this.type = type;
diff --git a/iterator/src/test/java/com/iluwatar/iterator/AppTest.java b/iterator/src/test/java/com/iluwatar/iterator/AppTest.java
index b6198f5c5..5ec59ec74 100644
--- a/iterator/src/test/java/com/iluwatar/iterator/AppTest.java
+++ b/iterator/src/test/java/com/iluwatar/iterator/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.iterator;
import org.junit.Test;
-import com.iluwatar.iterator.App;
-
/**
*
* Application test
diff --git a/iterator/src/test/java/com/iluwatar/iterator/TreasureChestTest.java b/iterator/src/test/java/com/iluwatar/iterator/TreasureChestTest.java
index a32066ea8..a2102a2e2 100644
--- a/iterator/src/test/java/com/iluwatar/iterator/TreasureChestTest.java
+++ b/iterator/src/test/java/com/iluwatar/iterator/TreasureChestTest.java
@@ -60,7 +60,7 @@ public class TreasureChestTest {
@Test
public void testIterator() {
final TreasureChest chest = new TreasureChest();
- final ItemIterator iterator = chest.Iterator(expectedItem.getType());
+ final ItemIterator iterator = chest.iterator(expectedItem.getType());
assertNotNull(iterator);
while (iterator.hasNext()) {
diff --git a/layers/index.md b/layers/index.md
index 37089a19c..8e8eda366 100644
--- a/layers/index.md
+++ b/layers/index.md
@@ -4,21 +4,25 @@ title: Layers
folder: layers
permalink: /patterns/layers/
categories: Architectural
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Spring
---
-**Intent:** Layers is an architectural style where software responsibilities are
+## Intent
+Layers is an architectural style where software responsibilities are
divided among the different layers of the application.

-**Applicability:** Use the Layers architecture when
+## Applicability
+Use the Layers architecture when
* you want clearly divide software responsibilities into differents parts of the program
* you want to prevent a change from propagating throughout the application
* you want to make your application more maintainable and testable
-**Credits:**
+## Credits
* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697)
-
diff --git a/layers/pom.xml b/layers/pom.xml
index 23b1db192..685f8b65c 100644
--- a/layers/pom.xml
+++ b/layers/pom.xml
@@ -6,7 +6,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTcom.iluwatar.layerslayers
@@ -32,5 +32,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/layers/src/main/java/com/iluwatar/layers/App.java b/layers/src/main/java/com/iluwatar/layers/App.java
index d175553f7..ecb532510 100644
--- a/layers/src/main/java/com/iluwatar/layers/App.java
+++ b/layers/src/main/java/com/iluwatar/layers/App.java
@@ -4,31 +4,31 @@ import java.util.Arrays;
/**
*
- * Layers is an architectural style where software responsibilities are divided among the different
- * layers of the application.
+ * Layers is an architectural style where software responsibilities are divided among the different layers of the
+ * application.
*
- * This example demonstrates a traditional 3-layer architecture consisting of data access layer,
- * business layer and presentation layer.
+ * This example demonstrates a traditional 3-layer architecture consisting of data access layer, business layer and
+ * presentation layer.
*
- * The data access layer is formed of Spring Data repositories CakeDao,
- * CakeToppingDao and CakeLayerDao. The repositories can be used for CRUD
- * operations on cakes, cake toppings and cake layers respectively.
+ * The data access layer is formed of Spring Data repositories CakeDao, CakeToppingDao and
+ * CakeLayerDao. The repositories can be used for CRUD operations on cakes, cake toppings and cake layers
+ * respectively.
*
- * The business layer is built on top of the data access layer. CakeBakingService
- * offers methods to retrieve available cake toppings and cake layers and baked cakes. Also the
- * service is used to create new cakes out of cake toppings and cake layers.
+ * The business layer is built on top of the data access layer. CakeBakingService offers methods to
+ * retrieve available cake toppings and cake layers and baked cakes. Also the service is used to create new cakes out of
+ * cake toppings and cake layers.
*
- * The presentation layer is built on the business layer and in this example it simply lists the
- * cakes that have been baked.
+ * The presentation layer is built on the business layer and in this example it simply lists the cakes that have been
+ * baked.
*
- * We have applied so called strict layering which means that the layers can only access the classes
- * directly beneath them. This leads the solution to create an additional set of DTOs (
- * CakeInfo, CakeToppingInfo, CakeLayerInfo) to translate
- * data between layers. In other words, CakeBakingService cannot return entities (
- * Cake, CakeTopping, CakeLayer) directly since these reside
- * on data access layer but instead translates these into business layer DTOs (CakeInfo, CakeToppingInfo, CakeLayerInfo) and returns them instead. This way
- * the presentation layer does not have any knowledge of other layers than the business layer and
- * thus is not affected by changes to them.
+ * We have applied so called strict layering which means that the layers can only access the classes directly beneath
+ * them. This leads the solution to create an additional set of DTOs ( CakeInfo,
+ * CakeToppingInfo, CakeLayerInfo) to translate data between layers. In other words,
+ * CakeBakingService cannot return entities ( Cake, CakeTopping,
+ * CakeLayer) directly since these reside on data access layer but instead translates these into business
+ * layer DTOs (CakeInfo, CakeToppingInfo, CakeLayerInfo) and returns them
+ * instead. This way the presentation layer does not have any knowledge of other layers than the business layer and thus
+ * is not affected by changes to them.
*
* @see Cake
* @see CakeTopping
@@ -63,8 +63,6 @@ public class App {
/**
* Initializes the example data
- *
- * @param cakeBakingService
*/
private static void initializeData(CakeBakingService cakeBakingService) {
cakeBakingService.saveNewLayer(new CakeLayerInfo("chocolate", 1200));
diff --git a/layers/src/main/java/com/iluwatar/layers/CakeBakingService.java b/layers/src/main/java/com/iluwatar/layers/CakeBakingService.java
index 80bd3438b..adfa585d6 100644
--- a/layers/src/main/java/com/iluwatar/layers/CakeBakingService.java
+++ b/layers/src/main/java/com/iluwatar/layers/CakeBakingService.java
@@ -11,44 +11,31 @@ public interface CakeBakingService {
/**
* Bakes new cake according to parameters
- *
- * @param cakeInfo
- * @throws CakeBakingException
*/
void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException;
/**
* Get all cakes
- *
- * @return
*/
List getAllCakes();
/**
* Store new cake topping
- *
- * @param toppingInfo
*/
void saveNewTopping(CakeToppingInfo toppingInfo);
/**
* Get available cake toppings
- *
- * @return
*/
List getAvailableToppings();
/**
* Add new cake layer
- *
- * @param layerInfo
*/
void saveNewLayer(CakeLayerInfo layerInfo);
/**
* Get available cake layers
- *
- * @return
*/
List getAvailableLayers();
}
diff --git a/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java b/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java
index a519ec2ce..79917842d 100644
--- a/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java
+++ b/layers/src/main/java/com/iluwatar/layers/CakeBakingServiceImpl.java
@@ -30,9 +30,9 @@ public class CakeBakingServiceImpl implements CakeBakingService {
@Override
public void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException {
- List allToppings = getAvailableToppings();
- List matchingToppings =
- allToppings.stream().filter((t) -> t.name.equals(cakeInfo.cakeToppingInfo.name))
+ List allToppings = getAvailableToppingEntities();
+ List matchingToppings =
+ allToppings.stream().filter((t) -> t.getName().equals(cakeInfo.cakeToppingInfo.name))
.collect(Collectors.toList());
if (matchingToppings.isEmpty()) {
throw new CakeBakingException(String.format("Topping %s is not available",
@@ -50,7 +50,7 @@ public class CakeBakingServiceImpl implements CakeBakingService {
}
}
CakeToppingDao toppingBean = context.getBean(CakeToppingDao.class);
- CakeTopping topping = toppingBean.findOne(matchingToppings.iterator().next().id.get());
+ CakeTopping topping = toppingBean.findOne(matchingToppings.iterator().next().getId());
CakeDao cakeBean = context.getBean(CakeDao.class);
Cake cake = new Cake();
cake.setTopping(topping);
diff --git a/layers/src/main/java/com/iluwatar/layers/CakeInfo.java b/layers/src/main/java/com/iluwatar/layers/CakeInfo.java
index f60ee9a14..dc374bf60 100644
--- a/layers/src/main/java/com/iluwatar/layers/CakeInfo.java
+++ b/layers/src/main/java/com/iluwatar/layers/CakeInfo.java
@@ -14,18 +14,27 @@ public class CakeInfo {
public final CakeToppingInfo cakeToppingInfo;
public final List cakeLayerInfos;
+ /**
+ * Constructor
+ */
public CakeInfo(Long id, CakeToppingInfo cakeToppingInfo, List cakeLayerInfos) {
this.id = Optional.of(id);
this.cakeToppingInfo = cakeToppingInfo;
this.cakeLayerInfos = cakeLayerInfos;
}
+ /**
+ * Constructor
+ */
public CakeInfo(CakeToppingInfo cakeToppingInfo, List cakeLayerInfos) {
this.id = Optional.empty();
this.cakeToppingInfo = cakeToppingInfo;
this.cakeLayerInfos = cakeLayerInfos;
}
+ /**
+ * Calculate calories
+ */
public int calculateTotalCalories() {
int total = cakeToppingInfo != null ? cakeToppingInfo.calories : 0;
total += cakeLayerInfos.stream().mapToInt(c -> c.calories).sum();
@@ -34,7 +43,7 @@ public class CakeInfo {
@Override
public String toString() {
- return String.format("CakeInfo id=%d topping=%s layers=%s totalCalories=%d", id.get(),
+ return String.format("CakeInfo id=%d topping=%s layers=%s totalCalories=%d", id.orElse(-1L),
cakeToppingInfo, cakeLayerInfos, calculateTotalCalories());
}
}
diff --git a/layers/src/main/java/com/iluwatar/layers/CakeLayerInfo.java b/layers/src/main/java/com/iluwatar/layers/CakeLayerInfo.java
index 3dff379da..5bc38b109 100644
--- a/layers/src/main/java/com/iluwatar/layers/CakeLayerInfo.java
+++ b/layers/src/main/java/com/iluwatar/layers/CakeLayerInfo.java
@@ -13,12 +13,18 @@ public class CakeLayerInfo {
public final String name;
public final int calories;
+ /**
+ * Constructor
+ */
public CakeLayerInfo(Long id, String name, int calories) {
this.id = Optional.of(id);
this.name = name;
this.calories = calories;
}
+ /**
+ * Constructor
+ */
public CakeLayerInfo(String name, int calories) {
this.id = Optional.empty();
this.name = name;
@@ -27,6 +33,6 @@ public class CakeLayerInfo {
@Override
public String toString() {
- return String.format("CakeLayerInfo id=%d name=%s calories=%d", id.get(), name, calories);
+ return String.format("CakeLayerInfo id=%d name=%s calories=%d", id.orElse(-1L), name, calories);
}
}
diff --git a/layers/src/main/java/com/iluwatar/layers/CakeTopping.java b/layers/src/main/java/com/iluwatar/layers/CakeTopping.java
index 6dc9c45fc..9f2107f1e 100644
--- a/layers/src/main/java/com/iluwatar/layers/CakeTopping.java
+++ b/layers/src/main/java/com/iluwatar/layers/CakeTopping.java
@@ -58,7 +58,7 @@ public class CakeTopping {
@Override
public String toString() {
- return String.format("id=%s name=%s calories=%d", name, calories);
+ return String.format("id=%s name=%s calories=%d", id, name, calories);
}
public Cake getCake() {
diff --git a/layers/src/main/java/com/iluwatar/layers/CakeToppingInfo.java b/layers/src/main/java/com/iluwatar/layers/CakeToppingInfo.java
index 4e432ec44..4c9be6a3e 100644
--- a/layers/src/main/java/com/iluwatar/layers/CakeToppingInfo.java
+++ b/layers/src/main/java/com/iluwatar/layers/CakeToppingInfo.java
@@ -13,12 +13,18 @@ public class CakeToppingInfo {
public final String name;
public final int calories;
+ /**
+ * Constructor
+ */
public CakeToppingInfo(Long id, String name, int calories) {
this.id = Optional.of(id);
this.name = name;
this.calories = calories;
}
+ /**
+ * Constructor
+ */
public CakeToppingInfo(String name, int calories) {
this.id = Optional.empty();
this.name = name;
@@ -27,6 +33,6 @@ public class CakeToppingInfo {
@Override
public String toString() {
- return String.format("CakeToppingInfo id=%d name=%s calories=%d", id.get(), name, calories);
+ return String.format("CakeToppingInfo id=%d name=%s calories=%d", id.orElse(-1L), name, calories);
}
}
diff --git a/layers/src/main/resources/META-INF/persistence.xml b/layers/src/main/resources/META-INF/persistence.xml
index d94d8582b..96856e1b9 100644
--- a/layers/src/main/resources/META-INF/persistence.xml
+++ b/layers/src/main/resources/META-INF/persistence.xml
@@ -1,8 +1,8 @@
+ xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
-
+
\ No newline at end of file
diff --git a/layers/src/main/resources/applicationContext.xml b/layers/src/main/resources/applicationContext.xml
index 0c908ad2e..6b3bc466d 100644
--- a/layers/src/main/resources/applicationContext.xml
+++ b/layers/src/main/resources/applicationContext.xml
@@ -1,42 +1,39 @@
-
+
-
+
-
+
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/layers/src/test/java/com/iluwatar/layers/AppTest.java b/layers/src/test/java/com/iluwatar/layers/AppTest.java
index 7db3f6ecd..cd03ae815 100644
--- a/layers/src/test/java/com/iluwatar/layers/AppTest.java
+++ b/layers/src/test/java/com/iluwatar/layers/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.layers;
import org.junit.Test;
-import com.iluwatar.layers.App;
-
/**
*
* Application test
diff --git a/layers/src/test/java/com/iluwatar/layers/CakeBakingExceptionTest.java b/layers/src/test/java/com/iluwatar/layers/CakeBakingExceptionTest.java
new file mode 100644
index 000000000..87381a309
--- /dev/null
+++ b/layers/src/test/java/com/iluwatar/layers/CakeBakingExceptionTest.java
@@ -0,0 +1,30 @@
+package com.iluwatar.layers;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Date: 12/15/15 - 7:57 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CakeBakingExceptionTest {
+
+ @Test
+ public void testConstructor() throws Exception {
+ final CakeBakingException exception = new CakeBakingException();
+ assertNull(exception.getMessage());
+ assertNull(exception.getCause());
+ }
+
+ @Test
+ public void testConstructorWithMessage() throws Exception {
+ final String expectedMessage = "message";
+ final CakeBakingException exception = new CakeBakingException(expectedMessage);
+ assertEquals(expectedMessage, exception.getMessage());
+ assertNull(exception.getCause());
+ }
+
+}
diff --git a/layers/src/test/java/com/iluwatar/layers/CakeBakingServiceImplTest.java b/layers/src/test/java/com/iluwatar/layers/CakeBakingServiceImplTest.java
new file mode 100644
index 000000000..11caab9ea
--- /dev/null
+++ b/layers/src/test/java/com/iluwatar/layers/CakeBakingServiceImplTest.java
@@ -0,0 +1,159 @@
+package com.iluwatar.layers;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/15/15 - 9:55 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CakeBakingServiceImplTest {
+
+ @Test
+ public void testLayers() throws CakeBakingException {
+ final CakeBakingServiceImpl service = new CakeBakingServiceImpl();
+
+ final List initialLayers = service.getAvailableLayers();
+ assertNotNull(initialLayers);
+ assertTrue(initialLayers.isEmpty());
+
+ service.saveNewLayer(new CakeLayerInfo("Layer1", 1000));
+ service.saveNewLayer(new CakeLayerInfo("Layer2", 2000));
+
+ final List availableLayers = service.getAvailableLayers();
+ assertNotNull(availableLayers);
+ assertEquals(2, availableLayers.size());
+ for (final CakeLayerInfo layer : availableLayers) {
+ assertNotNull(layer.id);
+ assertNotNull(layer.name);
+ assertNotNull(layer.toString());
+ assertTrue(layer.calories > 0);
+ }
+
+ }
+
+ @Test
+ public void testToppings() throws CakeBakingException {
+ final CakeBakingServiceImpl service = new CakeBakingServiceImpl();
+
+ final List initialToppings = service.getAvailableToppings();
+ assertNotNull(initialToppings);
+ assertTrue(initialToppings.isEmpty());
+
+ service.saveNewTopping(new CakeToppingInfo("Topping1", 1000));
+ service.saveNewTopping(new CakeToppingInfo("Topping2", 2000));
+
+ final List availableToppings = service.getAvailableToppings();
+ assertNotNull(availableToppings);
+ assertEquals(2, availableToppings.size());
+ for (final CakeToppingInfo topping : availableToppings) {
+ assertNotNull(topping.id);
+ assertNotNull(topping.name);
+ assertNotNull(topping.toString());
+ assertTrue(topping.calories > 0);
+ }
+
+ }
+
+ @Test
+ public void testBakeCakes() throws CakeBakingException {
+ final CakeBakingServiceImpl service = new CakeBakingServiceImpl();
+
+ final List initialCakes = service.getAllCakes();
+ assertNotNull(initialCakes);
+ assertTrue(initialCakes.isEmpty());
+
+ final CakeToppingInfo topping1 = new CakeToppingInfo("Topping1", 1000);
+ final CakeToppingInfo topping2 = new CakeToppingInfo("Topping2", 2000);
+ service.saveNewTopping(topping1);
+ service.saveNewTopping(topping2);
+
+ final CakeLayerInfo layer1 = new CakeLayerInfo("Layer1", 1000);
+ final CakeLayerInfo layer2 = new CakeLayerInfo("Layer2", 2000);
+ final CakeLayerInfo layer3 = new CakeLayerInfo("Layer3", 2000);
+ service.saveNewLayer(layer1);
+ service.saveNewLayer(layer2);
+ service.saveNewLayer(layer3);
+
+ service.bakeNewCake(new CakeInfo(topping1, Arrays.asList(layer1, layer2)));
+ service.bakeNewCake(new CakeInfo(topping2, Collections.singletonList(layer3)));
+
+ final List allCakes = service.getAllCakes();
+ assertNotNull(allCakes);
+ assertEquals(2, allCakes.size());
+ for (final CakeInfo cakeInfo : allCakes) {
+ assertNotNull(cakeInfo.id);
+ assertNotNull(cakeInfo.cakeToppingInfo);
+ assertNotNull(cakeInfo.cakeLayerInfos);
+ assertNotNull(cakeInfo.toString());
+ assertFalse(cakeInfo.cakeLayerInfos.isEmpty());
+ assertTrue(cakeInfo.calculateTotalCalories() > 0);
+ }
+
+ }
+
+ @Test(expected = CakeBakingException.class)
+ public void testBakeCakeMissingTopping() throws CakeBakingException {
+ final CakeBakingServiceImpl service = new CakeBakingServiceImpl();
+
+ final CakeLayerInfo layer1 = new CakeLayerInfo("Layer1", 1000);
+ final CakeLayerInfo layer2 = new CakeLayerInfo("Layer2", 2000);
+ service.saveNewLayer(layer1);
+ service.saveNewLayer(layer2);
+
+ final CakeToppingInfo missingTopping = new CakeToppingInfo("Topping1", 1000);
+ service.bakeNewCake(new CakeInfo(missingTopping, Arrays.asList(layer1, layer2)));
+ }
+
+ @Test(expected = CakeBakingException.class)
+ public void testBakeCakeMissingLayer() throws CakeBakingException {
+ final CakeBakingServiceImpl service = new CakeBakingServiceImpl();
+
+ final List initialCakes = service.getAllCakes();
+ assertNotNull(initialCakes);
+ assertTrue(initialCakes.isEmpty());
+
+ final CakeToppingInfo topping1 = new CakeToppingInfo("Topping1", 1000);
+ service.saveNewTopping(topping1);
+
+ final CakeLayerInfo layer1 = new CakeLayerInfo("Layer1", 1000);
+ service.saveNewLayer(layer1);
+
+ final CakeLayerInfo missingLayer = new CakeLayerInfo("Layer2", 2000);
+ service.bakeNewCake(new CakeInfo(topping1, Arrays.asList(layer1, missingLayer)));
+
+ }
+
+ @Test(expected = CakeBakingException.class)
+ public void testBakeCakesUsedLayer() throws CakeBakingException {
+ final CakeBakingServiceImpl service = new CakeBakingServiceImpl();
+
+ final List initialCakes = service.getAllCakes();
+ assertNotNull(initialCakes);
+ assertTrue(initialCakes.isEmpty());
+
+ final CakeToppingInfo topping1 = new CakeToppingInfo("Topping1", 1000);
+ final CakeToppingInfo topping2 = new CakeToppingInfo("Topping2", 2000);
+ service.saveNewTopping(topping1);
+ service.saveNewTopping(topping2);
+
+ final CakeLayerInfo layer1 = new CakeLayerInfo("Layer1", 1000);
+ final CakeLayerInfo layer2 = new CakeLayerInfo("Layer2", 2000);
+ service.saveNewLayer(layer1);
+ service.saveNewLayer(layer2);
+
+ service.bakeNewCake(new CakeInfo(topping1, Arrays.asList(layer1, layer2)));
+ service.bakeNewCake(new CakeInfo(topping2, Collections.singletonList(layer2)));
+
+ }
+
+}
diff --git a/layers/src/test/java/com/iluwatar/layers/CakeTest.java b/layers/src/test/java/com/iluwatar/layers/CakeTest.java
new file mode 100644
index 000000000..8c2bd4c15
--- /dev/null
+++ b/layers/src/test/java/com/iluwatar/layers/CakeTest.java
@@ -0,0 +1,97 @@
+package com.iluwatar.layers;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/15/15 - 8:02 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CakeTest {
+
+ @Test
+ public void testSetId() {
+ final Cake cake = new Cake();
+ assertNull(cake.getId());
+
+ final Long expectedId = Long.valueOf(1234L);
+ cake.setId(expectedId);
+ assertEquals(expectedId, cake.getId());
+ }
+
+ @Test
+ public void testSetTopping() {
+ final Cake cake = new Cake();
+ assertNull(cake.getTopping());
+
+ final CakeTopping expectedTopping = new CakeTopping("DummyTopping", 1000);
+ cake.setTopping(expectedTopping);
+ assertEquals(expectedTopping, cake.getTopping());
+ }
+
+ @Test
+ public void testSetLayers() {
+ final Cake cake = new Cake();
+ assertNotNull(cake.getLayers());
+ assertTrue(cake.getLayers().isEmpty());
+
+ final Set expectedLayers = new HashSet<>();
+ expectedLayers.add(new CakeLayer("layer1", 1000));
+ expectedLayers.add(new CakeLayer("layer2", 2000));
+ expectedLayers.add(new CakeLayer("layer3", 3000));
+
+ cake.setLayers(expectedLayers);
+ assertEquals(expectedLayers, cake.getLayers());
+ }
+
+ @Test
+ public void testAddLayer() {
+ final Cake cake = new Cake();
+ assertNotNull(cake.getLayers());
+ assertTrue(cake.getLayers().isEmpty());
+
+ final Set initialLayers = new HashSet<>();
+ initialLayers.add(new CakeLayer("layer1", 1000));
+ initialLayers.add(new CakeLayer("layer2", 2000));
+
+ cake.setLayers(initialLayers);
+ assertEquals(initialLayers, cake.getLayers());
+
+ final CakeLayer newLayer = new CakeLayer("layer3", 3000);
+ cake.addLayer(newLayer);
+
+ final Set expectedLayers = new HashSet<>();
+ expectedLayers.addAll(initialLayers);
+ expectedLayers.addAll(initialLayers);
+ expectedLayers.add(newLayer);
+ assertEquals(expectedLayers, cake.getLayers());
+ }
+
+ @Test
+ public void testToString() {
+ final CakeTopping topping = new CakeTopping("topping", 20);
+ topping.setId(2345L);
+
+ final CakeLayer layer = new CakeLayer("layer", 100);
+ layer.setId(3456L);
+
+ final Cake cake = new Cake();
+ cake.setId(1234L);
+ cake.setTopping(topping);
+ cake.addLayer(layer);
+
+ final String expected = "id=1234 topping=id=2345 name=topping calories=20 "
+ + "layers=[id=3456 name=layer calories=100]";
+ assertEquals(expected, cake.toString());
+
+ }
+
+}
diff --git a/layers/src/test/java/com/iluwatar/layers/CakeViewImplTest.java b/layers/src/test/java/com/iluwatar/layers/CakeViewImplTest.java
new file mode 100644
index 000000000..ce8299170
--- /dev/null
+++ b/layers/src/test/java/com/iluwatar/layers/CakeViewImplTest.java
@@ -0,0 +1,44 @@
+package com.iluwatar.layers;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Date: 12/15/15 - 10:04 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CakeViewImplTest extends StdOutTest {
+
+ /**
+ * Verify if the cake view renders the expected result
+ */
+ @Test
+ public void testRender() {
+
+ final List layers = new ArrayList<>();
+ layers.add(new CakeLayerInfo("layer1", 1000));
+ layers.add(new CakeLayerInfo("layer2", 2000));
+ layers.add(new CakeLayerInfo("layer3", 3000));
+
+ final List cakes = new ArrayList<>();
+ final CakeInfo cake = new CakeInfo(new CakeToppingInfo("topping", 1000), layers);
+ cakes.add(cake);
+
+ final CakeBakingService bakingService = mock(CakeBakingService.class);
+ when(bakingService.getAllCakes()).thenReturn(cakes);
+
+ final CakeViewImpl cakeView = new CakeViewImpl(bakingService);
+
+ verifyZeroInteractions(getStdOutMock());
+
+ cakeView.render();
+ verify(getStdOutMock(), times(1)).println(cake);
+
+ }
+
+}
diff --git a/layers/src/test/java/com/iluwatar/layers/StdOutTest.java b/layers/src/test/java/com/iluwatar/layers/StdOutTest.java
new file mode 100644
index 000000000..fe72bbb8a
--- /dev/null
+++ b/layers/src/test/java/com/iluwatar/layers/StdOutTest.java
@@ -0,0 +1,54 @@
+package com.iluwatar.layers;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since the actions of the views don't have
+ * any influence on any other accessible objects, except for writing to std-out using {@link
+ * System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/lazy-loading/index.md b/lazy-loading/index.md
index 700892af0..8a06700d3 100644
--- a/lazy-loading/index.md
+++ b/lazy-loading/index.md
@@ -4,20 +4,26 @@ title: Lazy Loading
folder: lazy-loading
permalink: /patterns/lazy-loading/
categories: Other
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Idiom
+ - Performance
---
-**Intent:** Lazy loading is a design pattern commonly used to defer
+## Intent
+Lazy loading is a design pattern commonly used to defer
initialization of an object until the point at which it is needed. It can
contribute to efficiency in the program's operation if properly and
appropriately used.

-**Applicability:** Use the Lazy Loading idiom when
+## Applicability
+Use the Lazy Loading idiom when
* eager loading is expensive or the object to be loaded might not be needed at all
-**Real world examples:**
+## Real world examples
* JPA annotations @OneToOne, @OneToMany, @ManyToOne, @ManyToMany and fetch = FetchType.LAZY
diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml
index 044211ab6..44c950f4a 100644
--- a/lazy-loading/pom.xml
+++ b/lazy-loading/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTlazy-loading
diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java
index 25e46d8b9..dabd8c313 100644
--- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java
+++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Heavy.java
@@ -7,6 +7,9 @@ package com.iluwatar.lazy.loading;
*/
public class Heavy {
+ /**
+ * Constructor
+ */
public Heavy() {
System.out.println("Creating Heavy ...");
try {
diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java
index 132ebaa5f..f78005c73 100644
--- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java
+++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderNaive.java
@@ -9,10 +9,16 @@ public class HolderNaive {
private Heavy heavy;
+ /**
+ * Constructor
+ */
public HolderNaive() {
System.out.println("HolderNaive created");
}
+ /**
+ * Get heavy object
+ */
public Heavy getHeavy() {
if (heavy == null) {
heavy = new Heavy();
diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java
index d2b15a3af..56074846e 100644
--- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java
+++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/HolderThreadSafe.java
@@ -10,10 +10,16 @@ public class HolderThreadSafe {
private Heavy heavy;
+ /**
+ * Constructor
+ */
public HolderThreadSafe() {
System.out.println("HolderThreadSafe created");
}
+ /**
+ * Get heavy object
+ */
public synchronized Heavy getHeavy() {
if (heavy == null) {
heavy = new Heavy();
diff --git a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java
index da021e014..aa86e3b34 100644
--- a/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java
+++ b/lazy-loading/src/main/java/com/iluwatar/lazy/loading/Java8Holder.java
@@ -5,7 +5,7 @@ import java.util.function.Supplier;
/**
*
* This lazy loader is thread safe and more efficient than {@link HolderThreadSafe}. It utilizes
- * Java 8 functional interface {@link Supplier} as {@link Heavy} factory.
+ * Java 8 functional interface {@link Supplier} as {@link Heavy} factory.
*
*/
public class Java8Holder {
diff --git a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AbstractHolderTest.java b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AbstractHolderTest.java
new file mode 100644
index 000000000..99523cd0a
--- /dev/null
+++ b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AbstractHolderTest.java
@@ -0,0 +1,41 @@
+package com.iluwatar.lazy.loading;
+
+import org.junit.Test;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertSame;
+import static junit.framework.TestCase.assertNull;
+
+/**
+ * Date: 12/19/15 - 11:58 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class AbstractHolderTest {
+
+ /**
+ * Get the internal state of the holder value
+ *
+ * @return The internal value
+ */
+ abstract Heavy getInternalHeavyValue() throws Exception;
+
+ /**
+ * Request a lazy loaded {@link Heavy} object from the holder.
+ *
+ * @return The lazy loaded {@link Heavy} object
+ */
+ abstract Heavy getHeavy() throws Exception;
+
+ /**
+ * This test shows that the heavy field is not instantiated until the method getHeavy is called
+ */
+ @Test(timeout = 3000)
+ public void testGetHeavy() throws Exception {
+ assertNull(getInternalHeavyValue());
+ assertNotNull(getHeavy());
+ assertNotNull(getInternalHeavyValue());
+ assertSame(getHeavy(), getInternalHeavyValue());
+ }
+
+}
diff --git a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java
index 591b1282d..29176a6b5 100644
--- a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java
+++ b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.lazy.loading;
import org.junit.Test;
-import com.iluwatar.lazy.loading.App;
-
/**
*
* Application test
diff --git a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/HolderNaiveTest.java b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/HolderNaiveTest.java
new file mode 100644
index 000000000..2c539e8ca
--- /dev/null
+++ b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/HolderNaiveTest.java
@@ -0,0 +1,26 @@
+package com.iluwatar.lazy.loading;
+
+import java.lang.reflect.Field;
+
+/**
+ * Date: 12/19/15 - 12:05 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class HolderNaiveTest extends AbstractHolderTest {
+
+ private final HolderNaive holder = new HolderNaive();
+
+ @Override
+ Heavy getInternalHeavyValue() throws Exception {
+ final Field holderField = HolderNaive.class.getDeclaredField("heavy");
+ holderField.setAccessible(true);
+ return (Heavy) holderField.get(this.holder);
+ }
+
+ @Override
+ Heavy getHeavy() {
+ return holder.getHeavy();
+ }
+
+}
\ No newline at end of file
diff --git a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/HolderThreadSafeTest.java b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/HolderThreadSafeTest.java
index d827f186b..f6aed73b7 100644
--- a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/HolderThreadSafeTest.java
+++ b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/HolderThreadSafeTest.java
@@ -1,45 +1,26 @@
package com.iluwatar.lazy.loading;
-import org.junit.Test;
-
import java.lang.reflect.Field;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
/**
- * Using reflection this test shows that the heavy field is not instantiated until the method
- * getHeavy is called
+ * Date: 12/19/15 - 12:19 PM
*
- * Created by jones on 11/10/2015.
+ * @author Jeroen Meulemeester
*/
-public class HolderThreadSafeTest {
+public class HolderThreadSafeTest extends AbstractHolderTest {
- @Test
- public void test() throws IllegalAccessException {
- HolderThreadSafe hts = new HolderThreadSafe();
+ private final HolderThreadSafe holder = new HolderThreadSafe();
- {
- // first call is null
- Field[] ff = HolderThreadSafe.class.getDeclaredFields();
- for (Field f : ff) {
- f.setAccessible(true);
- }
-
- assertNull(ff[0].get(hts));
- }
-
- // now it is lazily loaded
- hts.getHeavy();
-
- {
- // now it is not null - call via reflection so that the test is the same before and after
- Field[] ff = HolderThreadSafe.class.getDeclaredFields();
- for (Field f : ff) {
- f.setAccessible(true);
- }
-
- assertNotNull(ff[0].get(hts));
- }
+ @Override
+ Heavy getInternalHeavyValue() throws Exception {
+ final Field holderField = HolderThreadSafe.class.getDeclaredField("heavy");
+ holderField.setAccessible(true);
+ return (Heavy) holderField.get(this.holder);
}
-}
+
+ @Override
+ Heavy getHeavy() throws Exception {
+ return this.holder.getHeavy();
+ }
+
+}
\ No newline at end of file
diff --git a/lazy-loading/src/test/java/com/iluwatar/lazy/loading/Java8HolderTest.java b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/Java8HolderTest.java
new file mode 100644
index 000000000..aed9a054e
--- /dev/null
+++ b/lazy-loading/src/test/java/com/iluwatar/lazy/loading/Java8HolderTest.java
@@ -0,0 +1,40 @@
+package com.iluwatar.lazy.loading;
+
+import java.lang.reflect.Field;
+import java.util.function.Supplier;
+
+/**
+ * Date: 12/19/15 - 12:27 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class Java8HolderTest extends AbstractHolderTest {
+
+ private final Java8Holder holder = new Java8Holder();
+
+
+ @Override
+ Heavy getInternalHeavyValue() throws Exception {
+ final Field holderField = Java8Holder.class.getDeclaredField("heavy");
+ holderField.setAccessible(true);
+
+ final Supplier supplier = (Supplier) holderField.get(this.holder);
+ final Class extends Supplier> supplierClass = supplier.getClass();
+
+ // This is a little fishy, but I don't know another way to test this:
+ // The lazy holder is at first a lambda, but gets replaced with a new supplier after loading ...
+ if (supplierClass.isLocalClass()) {
+ final Field instanceField = supplierClass.getDeclaredField("heavyInstance");
+ instanceField.setAccessible(true);
+ return (Heavy) instanceField.get(supplier);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ Heavy getHeavy() throws Exception {
+ return holder.getHeavy();
+ }
+
+}
\ No newline at end of file
diff --git a/mediator/index.md b/mediator/index.md
index cb4ce7fb1..c7a0478c8 100644
--- a/mediator/index.md
+++ b/mediator/index.md
@@ -10,18 +10,20 @@ tags:
- Difficulty-Intermediate
---
-**Intent:** Define an object that encapsulates how a set of objects interact.
+## Intent
+Define an object that encapsulates how a set of objects interact.
Mediator promotes loose coupling by keeping objects from referring to each
other explicitly, and it lets you vary their interaction independently.

-**Applicability:** Use the Mediator pattern when
+## Applicability
+Use the Mediator pattern when
* a set of objects communicate in well-defined but complex ways. The resulting interdependencies are unstructured and difficult to understand
* reusing an object is difficult because it refers to and communicates with many other objects
* a behavior that's distributed between several classes should be customizable without a lot of subclassing
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/mediator/pom.xml b/mediator/pom.xml
index 0e9bff5d1..449ce6e35 100644
--- a/mediator/pom.xml
+++ b/mediator/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTmediator
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java b/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
index acc70a0e6..ab15c26da 100644
--- a/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
+++ b/mediator/src/main/java/com/iluwatar/mediator/PartyImpl.java
@@ -19,7 +19,7 @@ public class PartyImpl implements Party {
@Override
public void act(PartyMember actor, Action action) {
for (PartyMember member : members) {
- if (member != actor) {
+ if (!member.equals(actor)) {
member.partyAction(action);
}
}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
index 4b3269244..3e10dd846 100644
--- a/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
+++ b/mediator/src/test/java/com/iluwatar/mediator/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.mediator;
import org.junit.Test;
-import com.iluwatar.mediator.App;
-
/**
*
* Application test
diff --git a/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java b/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
new file mode 100644
index 000000000..992662fb2
--- /dev/null
+++ b/mediator/src/test/java/com/iluwatar/mediator/PartyImplTest.java
@@ -0,0 +1,41 @@
+package com.iluwatar.mediator;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+/**
+ * Date: 12/19/15 - 10:00 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class PartyImplTest {
+
+ /**
+ * Verify if a member is notified when it's joining a party. Generate an action and see if the
+ * other member gets it. Also check members don't get their own actions.
+ */
+ @Test
+ public void testPartyAction() {
+ final PartyMember partyMember1 = mock(PartyMember.class);
+ final PartyMember partyMember2 = mock(PartyMember.class);
+
+ final PartyImpl party = new PartyImpl();
+ party.addMember(partyMember1);
+ party.addMember(partyMember2);
+
+ verify(partyMember1).joinedParty(party);
+ verify(partyMember2).joinedParty(party);
+
+ party.act(partyMember1, Action.GOLD);
+ verifyZeroInteractions(partyMember1);
+ verify(partyMember2).partyAction(Action.GOLD);
+
+ verifyNoMoreInteractions(partyMember1, partyMember2);
+
+ }
+
+}
diff --git a/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
new file mode 100644
index 000000000..31b7222e9
--- /dev/null
+++ b/mediator/src/test/java/com/iluwatar/mediator/PartyMemberTest.java
@@ -0,0 +1,128 @@
+package com.iluwatar.mediator;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+/**
+ * Date: 12/19/15 - 10:13 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+@RunWith(Parameterized.class)
+public class PartyMemberTest {
+
+ @Parameterized.Parameters
+ public static Collection[]> data() {
+ return Arrays.asList(
+ new Supplier[]{Hobbit::new},
+ new Supplier[]{Hunter::new},
+ new Supplier[]{Rogue::new},
+ new Supplier[]{Wizard::new}
+ );
+ }
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions on a {@link
+ * PartyMember} have any influence on any other accessible objects, except for writing to std-out
+ * using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * The factory, used to create a new instance of the tested party member
+ */
+ private final Supplier memberSupplier;
+
+ /**
+ * Create a new test instance, using the given {@link PartyMember} factory
+ *
+ * @param memberSupplier The party member factory
+ */
+ public PartyMemberTest(final Supplier memberSupplier) {
+ this.memberSupplier = memberSupplier;
+ }
+
+ /**
+ * Verify if a party action triggers the correct output to the std-Out
+ */
+ @Test
+ public void testPartyAction() {
+ final PartyMember member = this.memberSupplier.get();
+
+ for (final Action action : Action.values()) {
+ member.partyAction(action);
+ verify(this.stdOutMock).println(member.toString() + " " + action.getDescription());
+ }
+
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+ /**
+ * Verify if a member action triggers the expected interactions with the party class
+ */
+ @Test
+ public void testAct() {
+ final PartyMember member = this.memberSupplier.get();
+
+ member.act(Action.GOLD);
+ verifyZeroInteractions(this.stdOutMock);
+
+ final Party party = mock(Party.class);
+ member.joinedParty(party);
+ verify(this.stdOutMock).println(member.toString() + " joins the party");
+
+ for (final Action action : Action.values()) {
+ member.act(action);
+ verify(this.stdOutMock).println(member.toString() + " " + action.toString());
+ verify(party).act(member, action);
+ }
+
+ verifyNoMoreInteractions(party, this.stdOutMock);
+ }
+
+ /**
+ * Verify if {@link PartyMember#toString()} generate the expected output
+ */
+ @Test
+ public void testToString() throws Exception {
+ final PartyMember member = this.memberSupplier.get();
+ final Class extends PartyMember> memberClass = member.getClass();
+ assertEquals(memberClass.getSimpleName(), member.toString());
+ }
+
+}
diff --git a/memento/index.md b/memento/index.md
index f299506e0..463b5fec0 100644
--- a/memento/index.md
+++ b/memento/index.md
@@ -7,24 +7,28 @@ categories: Behavioral
tags:
- Java
- Gang Of Four
+ - Difficulty-Intermediate
---
-**Also known as:** Token
+## Also known as
+Token
-**Intent:** Without violating encapsulation, capture and externalize an
+## Intent
+Without violating encapsulation, capture and externalize an
object's internal state so that the object can be restored to this state later.

-**Applicability:** Use the Memento pattern when
+## Applicability
+Use the Memento pattern when
* a snapshot of an object's state must be saved so that it can be restored to that state later, and
* a direct interface to obtaining the state would expose implementation details and break the object's encapsulation
-**Real world examples:**
+## Real world examples
* [java.util.Date](http://docs.oracle.com/javase/8/docs/api/java/util/Date.html)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/memento/pom.xml b/memento/pom.xml
index 0765300c9..258cd270a 100644
--- a/memento/pom.xml
+++ b/memento/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTmemento
diff --git a/memento/src/main/java/com/iluwatar/memento/App.java b/memento/src/main/java/com/iluwatar/memento/App.java
index c99894680..e08e9a106 100644
--- a/memento/src/main/java/com/iluwatar/memento/App.java
+++ b/memento/src/main/java/com/iluwatar/memento/App.java
@@ -23,6 +23,9 @@ import java.util.Stack;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) {
Stack states = new Stack<>();
diff --git a/memento/src/main/java/com/iluwatar/memento/Star.java b/memento/src/main/java/com/iluwatar/memento/Star.java
index b4ec1c669..f67edfd15 100644
--- a/memento/src/main/java/com/iluwatar/memento/Star.java
+++ b/memento/src/main/java/com/iluwatar/memento/Star.java
@@ -11,12 +11,18 @@ public class Star {
private int ageYears;
private int massTons;
+ /**
+ * Constructor
+ */
public Star(StarType startType, int startAge, int startMass) {
this.type = startType;
this.ageYears = startAge;
this.massTons = startMass;
}
+ /**
+ * Makes time pass for the star
+ */
public void timePasses() {
ageYears *= 2;
massTons *= 8;
diff --git a/memento/src/test/java/com/iluwatar/memento/AppTest.java b/memento/src/test/java/com/iluwatar/memento/AppTest.java
index 4eda4a6f9..79ffea00f 100644
--- a/memento/src/test/java/com/iluwatar/memento/AppTest.java
+++ b/memento/src/test/java/com/iluwatar/memento/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.memento;
import org.junit.Test;
-import com.iluwatar.memento.App;
-
/**
*
* Application test
diff --git a/memento/src/test/java/com/iluwatar/memento/StarTest.java b/memento/src/test/java/com/iluwatar/memento/StarTest.java
new file mode 100644
index 000000000..b5c7d9be0
--- /dev/null
+++ b/memento/src/test/java/com/iluwatar/memento/StarTest.java
@@ -0,0 +1,75 @@
+package com.iluwatar.memento;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Date: 12/20/15 - 10:08 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class StarTest {
+
+ /**
+ * Verify the stages of a dying sun, without going back in time
+ */
+ @Test
+ public void testTimePasses() {
+ final Star star = new Star(StarType.SUN, 1, 2);
+ assertEquals("sun age: 1 years mass: 2 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("red giant age: 2 years mass: 16 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("white dwarf age: 4 years mass: 128 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("supernova age: 8 years mass: 1024 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("dead star age: 16 years mass: 8192 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("dead star age: 64 years mass: 0 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("dead star age: 256 years mass: 0 tons", star.toString());
+ }
+
+ /**
+ * Verify some stage of a dying sun, but go back in time to test the memento
+ */
+ @Test
+ public void testSetMemento() {
+ final Star star = new Star(StarType.SUN, 1, 2);
+ final StarMemento firstMemento = star.getMemento();
+ assertEquals("sun age: 1 years mass: 2 tons", star.toString());
+
+ star.timePasses();
+ final StarMemento secondMemento = star.getMemento();
+ assertEquals("red giant age: 2 years mass: 16 tons", star.toString());
+
+ star.timePasses();
+ final StarMemento thirdMemento = star.getMemento();
+ assertEquals("white dwarf age: 4 years mass: 128 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("supernova age: 8 years mass: 1024 tons", star.toString());
+
+ star.setMemento(thirdMemento);
+ assertEquals("white dwarf age: 4 years mass: 128 tons", star.toString());
+
+ star.timePasses();
+ assertEquals("supernova age: 8 years mass: 1024 tons", star.toString());
+
+ star.setMemento(secondMemento);
+ assertEquals("red giant age: 2 years mass: 16 tons", star.toString());
+
+ star.setMemento(firstMemento);
+ assertEquals("sun age: 1 years mass: 2 tons", star.toString());
+
+ }
+
+}
diff --git a/message-channel/index.md b/message-channel/index.md
index 06cf93488..7015c726c 100644
--- a/message-channel/index.md
+++ b/message-channel/index.md
@@ -7,17 +7,20 @@ categories: Integration
tags:
- Java
- EIP
+ - Camel
---
-**Intent:** When two applications communicate using a messaging system they do it by using logical addresses
+## Intent
+When two applications communicate using a messaging system they do it by using logical addresses
of the system, so called Message Channels.

-**Applicability:** Use the Message Channel pattern when
+## Applicability
+Use the Message Channel pattern when
* two or more applications need to communicate using a messaging system
-**Real world examples:**
+## Real world examples
* [akka-camel](http://doc.akka.io/docs/akka/snapshot/scala/camel.html)
diff --git a/message-channel/pom.xml b/message-channel/pom.xml
index a558f40a3..4f5f90339 100644
--- a/message-channel/pom.xml
+++ b/message-channel/pom.xml
@@ -6,7 +6,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTmessage-channel
diff --git a/message-channel/src/main/java/com/iluwatar/message/channel/App.java b/message-channel/src/main/java/com/iluwatar/message/channel/App.java
index a41dd74dc..b0aeb690f 100644
--- a/message-channel/src/main/java/com/iluwatar/message/channel/App.java
+++ b/message-channel/src/main/java/com/iluwatar/message/channel/App.java
@@ -30,9 +30,6 @@ public class App {
/**
* Program entry point
- *
- * @param args command line args
- * @throws Exception
*/
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
diff --git a/model-view-controller/index.md b/model-view-controller/index.md
index 1ba1089c0..bc96f7ab1 100644
--- a/model-view-controller/index.md
+++ b/model-view-controller/index.md
@@ -4,21 +4,25 @@ title: Model-View-Controller
folder: model-view-controller
permalink: /patterns/model-view-controller/
categories: Presentation Tier
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** Separate the user interface into three interconnected components:
+## Intent
+Separate the user interface into three interconnected components:
the model, the view and the controller. Let the model manage the data, the view
display the data and the controller mediate updating the data and redrawing the
display.

-**Applicability:** Use the Model-View-Controller pattern when
+## Applicability
+Use the Model-View-Controller pattern when
* you want to clearly separate the domain data from its user interface representation
-**Credits:**
+## Credits
* [Trygve Reenskaug - Model-view-controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller)
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml
index 8e5d3d9e2..6db4d556f 100644
--- a/model-view-controller/pom.xml
+++ b/model-view-controller/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTmodel-view-controller
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
index 7142c2979..286ab9119 100644
--- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.model.view.controller;
import org.junit.Test;
-import com.iluwatar.model.view.controller.App;
-
/**
*
* Application test
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
new file mode 100644
index 000000000..0090f2d1d
--- /dev/null
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantControllerTest.java
@@ -0,0 +1,100 @@
+package com.iluwatar.model.view.controller;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+/**
+ * Date: 12/20/15 - 2:19 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class GiantControllerTest {
+
+ /**
+ * Verify if the controller passes the health level through to the model and vice versa
+ */
+ @Test
+ public void testSetHealth() {
+ final GiantModel model = mock(GiantModel.class);
+ final GiantView view = mock(GiantView.class);
+ final GiantController controller = new GiantController(model, view);
+
+ verifyZeroInteractions(model, view);
+
+ for (final Health health : Health.values()) {
+ controller.setHealth(health);
+ verify(model).setHealth(health);
+ verifyZeroInteractions(view);
+ }
+
+ controller.getHealth();
+ verify(model).getHealth();
+
+ verifyNoMoreInteractions(model, view);
+ }
+
+ /**
+ * Verify if the controller passes the fatigue level through to the model and vice versa
+ */
+ @Test
+ public void testSetFatigue() {
+ final GiantModel model = mock(GiantModel.class);
+ final GiantView view = mock(GiantView.class);
+ final GiantController controller = new GiantController(model, view);
+
+ verifyZeroInteractions(model, view);
+
+ for (final Fatigue fatigue : Fatigue.values()) {
+ controller.setFatigue(fatigue);
+ verify(model).setFatigue(fatigue);
+ verifyZeroInteractions(view);
+ }
+
+ controller.getFatigue();
+ verify(model).getFatigue();
+
+ verifyNoMoreInteractions(model, view);
+ }
+
+ /**
+ * Verify if the controller passes the nourishment level through to the model and vice versa
+ */
+ @Test
+ public void testSetNourishment() {
+ final GiantModel model = mock(GiantModel.class);
+ final GiantView view = mock(GiantView.class);
+ final GiantController controller = new GiantController(model, view);
+
+ verifyZeroInteractions(model, view);
+
+ for (final Nourishment nourishment : Nourishment.values()) {
+ controller.setNourishment(nourishment);
+ verify(model).setNourishment(nourishment);
+ verifyZeroInteractions(view);
+ }
+
+ controller.getNourishment();
+ verify(model).getNourishment();
+
+ verifyNoMoreInteractions(model, view);
+ }
+
+ @Test
+ public void testUpdateView() {
+ final GiantModel model = mock(GiantModel.class);
+ final GiantView view = mock(GiantView.class);
+ final GiantController controller = new GiantController(model, view);
+
+ verifyZeroInteractions(model, view);
+
+ controller.updateView();
+ verify(view).displayGiant(model);
+
+ verifyNoMoreInteractions(model, view);
+ }
+
+}
\ No newline at end of file
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
new file mode 100644
index 000000000..9513a62ec
--- /dev/null
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantModelTest.java
@@ -0,0 +1,56 @@
+package com.iluwatar.model.view.controller;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Date: 12/20/15 - 2:10 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class GiantModelTest {
+
+ /**
+ * Verify if the health value is set properly though the constructor and setter
+ */
+ @Test
+ public void testSetHealth() {
+ final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ assertEquals(Health.HEALTHY, model.getHealth());
+ for (final Health health : Health.values()) {
+ model.setHealth(health);
+ assertEquals(health, model.getHealth());
+ assertEquals("The giant looks " + health.toString() + ", alert and saturated.", model.toString());
+ }
+ }
+
+ /**
+ * Verify if the fatigue level is set properly though the constructor and setter
+ */
+ @Test
+ public void testSetFatigue() {
+ final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ assertEquals(Fatigue.ALERT, model.getFatigue());
+ for (final Fatigue fatigue : Fatigue.values()) {
+ model.setFatigue(fatigue);
+ assertEquals(fatigue, model.getFatigue());
+ assertEquals("The giant looks healthy, " + fatigue.toString() + " and saturated.", model.toString());
+ }
+ }
+
+ /**
+ * Verify if the nourishment level is set properly though the constructor and setter
+ */
+ @Test
+ public void testSetNourishment() {
+ final GiantModel model = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED);
+ assertEquals(Nourishment.SATURATED, model.getNourishment());
+ for (final Nourishment nourishment : Nourishment.values()) {
+ model.setNourishment(nourishment);
+ assertEquals(nourishment, model.getNourishment());
+ assertEquals("The giant looks healthy, alert and " + nourishment.toString() + ".", model.toString());
+ }
+ }
+
+}
diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java
new file mode 100644
index 000000000..8d7a7dfbf
--- /dev/null
+++ b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/GiantViewTest.java
@@ -0,0 +1,64 @@
+package com.iluwatar.model.view.controller;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/20/15 - 2:04 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class GiantViewTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since the actions of the views don't have
+ * any influence on any other accessible objects, except for writing to std-out using {@link
+ * System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Verify if the {@link GiantView} does what it has to do: Print the {@link GiantModel} to the
+ * standard out stream, nothing more, nothing less.
+ */
+ @Test
+ public void testDisplayGiant() {
+ final GiantView view = new GiantView();
+
+ final GiantModel model = mock(GiantModel.class);
+ view.displayGiant(model);
+
+ verify(this.stdOutMock).println(model);
+ verifyNoMoreInteractions(model, this.stdOutMock);
+
+ }
+
+}
\ No newline at end of file
diff --git a/model-view-presenter/index.md b/model-view-presenter/index.md
index b51268013..a3b921ce4 100644
--- a/model-view-presenter/index.md
+++ b/model-view-presenter/index.md
@@ -4,20 +4,24 @@ title: Model-View-Presenter
folder: model-view-presenter
permalink: /patterns/model-view-presenter/
categories: Presentation Tier
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** Apply a "Separation of Concerns" principle in a way that allows
+## Intent
+Apply a "Separation of Concerns" principle in a way that allows
developers to build and test user interfaces.

-**Applicability:** Use the Model-View-Presenter in any of the following
+## Applicability
+Use the Model-View-Presenter in any of the following
situations
* when you want to improve the "Separation of Concerns" principle in presentation logic
* when a user interface development and testing is necessary.
-**Real world examples:**
+## Real world examples
* [MVP4J](https://github.com/amineoualialami/mvp4j)
diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml
index 556f45cf5..cea55b47f 100644
--- a/model-view-presenter/pom.xml
+++ b/model-view-presenter/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTmodel-view-presentermodel-view-presenter
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
index d04f284ac..0cf4f8c34 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileLoader.java
@@ -39,9 +39,7 @@ public class FileLoader {
br.close();
return sb.toString();
- }
-
- catch (Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
index 02cb2703a..db08d525b 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorJFrame.java
@@ -26,7 +26,7 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/**
* The "OK" button for loading the file.
*/
- private JButton OK;
+ private JButton ok;
/**
* The cancel button.
@@ -121,10 +121,10 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
/*
* Add the OK button.
*/
- this.OK = new JButton("OK");
- this.panel.add(OK);
- this.OK.setBounds(250, 50, 100, 25);
- this.OK.addActionListener(this);
+ this.ok = new JButton("OK");
+ this.panel.add(ok);
+ this.ok.setBounds(250, 50, 100, 25);
+ this.ok.addActionListener(this);
/*
* Add the cancel button.
@@ -140,13 +140,11 @@ public class FileSelectorJFrame extends JFrame implements FileSelectorView, Acti
@Override
public void actionPerformed(ActionEvent e) {
- if (e.getSource() == this.OK) {
+ if (this.ok.equals(e.getSource())) {
this.fileName = this.input.getText();
presenter.fileNameChanged();
presenter.confirmed();
- }
-
- else if (e.getSource() == this.cancel) {
+ } else if (this.cancel.equals(e.getSource())) {
presenter.cancelled();
}
}
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
index 133d8555d..f38dc2655 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorPresenter.java
@@ -51,6 +51,9 @@ public class FileSelectorPresenter {
loader.setFileName(view.getFileName());
}
+ /**
+ * Ok button handler
+ */
public void confirmed() {
if (loader.getFileName() == null || loader.getFileName().equals("")) {
view.showMessage("Please give the name of the file first!");
@@ -60,9 +63,7 @@ public class FileSelectorPresenter {
if (loader.fileExists()) {
String data = loader.loadData();
view.displayData(data);
- }
-
- else {
+ } else {
view.showMessage("The file specified does not exist.");
}
}
diff --git a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java
index 80cfadd28..f124c0054 100644
--- a/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java
+++ b/model-view-presenter/src/main/java/com/iluwatar/model/view/presenter/FileSelectorView.java
@@ -9,53 +9,53 @@ public interface FileSelectorView {
/**
* Opens the view.
*/
- public void open();
+ void open();
/**
* Closes the view.
*/
- public void close();
+ void close();
/**
* @return True, if the view is opened, false otherwise.
*/
- public boolean isOpened();
+ boolean isOpened();
/**
* Sets the presenter component, to the one given as parameter.
*
* @param presenter The new presenter component.
*/
- public void setPresenter(FileSelectorPresenter presenter);
+ void setPresenter(FileSelectorPresenter presenter);
/**
* @return The presenter Component.
*/
- public FileSelectorPresenter getPresenter();
+ FileSelectorPresenter getPresenter();
/**
* Sets the file's name, to the value given as parameter.
*
* @param name The new name of the file.
*/
- public void setFileName(String name);
+ void setFileName(String name);
/**
* @return The name of the file.
*/
- public String getFileName();
+ String getFileName();
/**
* Displays a message to the users.
*
* @param message The message to be displayed.
*/
- public void showMessage(String message);
+ void showMessage(String message);
/**
* Displays the data to the view.
*
* @param data The data to be written.
*/
- public void displayData(String data);
+ void displayData(String data);
}
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
new file mode 100644
index 000000000..9b4aabc4d
--- /dev/null
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/AppTest.java
@@ -0,0 +1,18 @@
+package com.iluwatar.model.view.presenter;
+
+import org.junit.Test;
+
+/**
+ *
+ * Application test
+ *
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+
+}
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
new file mode 100644
index 000000000..ed1fc0e9e
--- /dev/null
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileLoaderTest.java
@@ -0,0 +1,21 @@
+package com.iluwatar.model.view.presenter;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNull;
+
+/**
+ * Date: 12/21/15 - 12:12 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class FileLoaderTest {
+
+ @Test
+ public void testLoadData() throws Exception {
+ final FileLoader fileLoader = new FileLoader();
+ fileLoader.setFileName("non-existing-file");
+ assertNull(fileLoader.loadData());
+ }
+
+}
\ No newline at end of file
diff --git a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
index dfdcba31b..ba371525a 100644
--- a/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
+++ b/model-view-presenter/src/test/java/com/iluwatar/model/view/presenter/FileSelectorPresenterTest.java
@@ -1,14 +1,13 @@
package com.iluwatar.model.view.presenter;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
-import com.iluwatar.model.view.presenter.FileLoader;
-import com.iluwatar.model.view.presenter.FileSelectorPresenter;
-import com.iluwatar.model.view.presenter.FileSelectorStub;
-
/**
* This test case is responsible for testing our application by taking advantage of the
* Model-View-Controller architectural pattern.
@@ -57,13 +56,13 @@ public class FileSelectorPresenterTest {
*/
@Test
public void updateFileNameToLoader() {
- String EXPECTED_FILE = "Stamatis";
- stub.setFileName(EXPECTED_FILE);
+ String expectedFile = "Stamatis";
+ stub.setFileName(expectedFile);
presenter.start();
presenter.fileNameChanged();
- assertEquals(EXPECTED_FILE, loader.getFileName());
+ assertEquals(expectedFile, loader.getFileName());
}
/**
diff --git a/monostate/index.md b/monostate/index.md
index 2b88f131e..415d13f0e 100644
--- a/monostate/index.md
+++ b/monostate/index.md
@@ -4,25 +4,29 @@ title: MonoState
folder: monostate
permalink: /patterns/monostate/
categories: Creational
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** Enforces a behaviour like sharing the same state amongst all instances.
+## Intent
+Enforces a behaviour like sharing the same state amongst all instances.

-**Applicability:** Use the Monostate pattern when
+## Applicability
+Use the Monostate pattern when
* The same state must be shared across all instances of a class.
* Typically this pattern might be used everywhere a Singleton might be used. Singleton usage however is not transparent, Monostate usage is.
* Monostate has one major advantage over singleton. The subclasses might decorate the shared state as they wish and hence can provide dynamically different behaviour than the base class.
-**Typical Use Case:**
+## Typical Use Case
* the logging class
* managing a connection to a database
* file manager
-**Real world examples:**
+## Real world examples
Yet to see this.
diff --git a/monostate/pom.xml b/monostate/pom.xml
index 2f253084d..f18c03e5c 100644
--- a/monostate/pom.xml
+++ b/monostate/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTmonostate
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/monostate/src/main/java/com/iluwatar/monostate/App.java b/monostate/src/main/java/com/iluwatar/monostate/App.java
index 0daad5b67..5c61371fa 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/App.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/App.java
@@ -28,8 +28,8 @@ public class App {
public static void main(String[] args) {
LoadBalancer loadBalancer1 = new LoadBalancer();
LoadBalancer loadBalancer2 = new LoadBalancer();
- loadBalancer1.serverequest(new Request("Hello"));
- loadBalancer2.serverequest(new Request("Hello World"));
+ loadBalancer1.serverRequest(new Request("Hello"));
+ loadBalancer2.serverRequest(new Request("Hello World"));
}
}
diff --git a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
index b81e44251..697c48bb4 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/LoadBalancer.java
@@ -24,6 +24,9 @@ public class LoadBalancer {
servers.add(new Server("localhost", 8084, ++id));
}
+ /**
+ * Add new server
+ */
public final void addServer(Server server) {
synchronized (servers) {
servers.add(server);
@@ -39,7 +42,10 @@ public class LoadBalancer {
return lastServedId;
}
- public void serverequest(Request request) {
+ /**
+ * Handle request
+ */
+ public void serverRequest(Request request) {
if (lastServedId >= servers.size()) {
lastServedId = 0;
}
diff --git a/monostate/src/main/java/com/iluwatar/monostate/Server.java b/monostate/src/main/java/com/iluwatar/monostate/Server.java
index f48f4ad0f..0cf9ac41f 100644
--- a/monostate/src/main/java/com/iluwatar/monostate/Server.java
+++ b/monostate/src/main/java/com/iluwatar/monostate/Server.java
@@ -11,6 +11,9 @@ public class Server {
public final int port;
public final int id;
+ /**
+ * Constructor
+ */
public Server(String host, int port, int id) {
this.host = host;
this.port = port;
@@ -25,7 +28,7 @@ public class Server {
return port;
}
- public final void serve(Request request) {
+ public void serve(Request request) {
System.out.println("Server ID " + id + " associated to host : " + getHost() + " and Port "
+ getPort() + " Processed request with value " + request.value);
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
index c502dd14a..053cd6649 100644
--- a/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
+++ b/monostate/src/test/java/com/iluwatar/monostate/AppTest.java
@@ -1,26 +1,13 @@
package com.iluwatar.monostate;
-import org.junit.Assert;
import org.junit.Test;
public class AppTest {
- @Test
- public void testSameStateAmonstAllInstances() {
- LoadBalancer balancer = new LoadBalancer();
- LoadBalancer balancer2 = new LoadBalancer();
- balancer.addServer(new Server("localhost", 8085, 6));
- // Both should have the same number of servers.
- Assert.assertTrue(balancer.getNoOfServers() == balancer2.getNoOfServers());
- // Both Should have the same LastServedId
- Assert.assertTrue(balancer.getLastServedId() == balancer2.getLastServedId());
- }
-
@Test
public void testMain() {
String[] args = {};
App.main(args);
- Assert.assertTrue(LoadBalancer.getLastServedId() == 2);
}
}
diff --git a/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
new file mode 100644
index 000000000..5488f12f3
--- /dev/null
+++ b/monostate/src/test/java/com/iluwatar/monostate/LoadBalancerTest.java
@@ -0,0 +1,49 @@
+package com.iluwatar.monostate;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.*;
+
+/**
+ * Date: 12/21/15 - 12:26 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class LoadBalancerTest {
+
+ @Test
+ public void testSameStateAmongstAllInstances() {
+ final LoadBalancer firstBalancer = new LoadBalancer();
+ final LoadBalancer secondBalancer = new LoadBalancer();
+ firstBalancer.addServer(new Server("localhost", 8085, 6));
+ // Both should have the same number of servers.
+ Assert.assertTrue(firstBalancer.getNoOfServers() == secondBalancer.getNoOfServers());
+ // Both Should have the same LastServedId
+ Assert.assertTrue(firstBalancer.getLastServedId() == secondBalancer.getLastServedId());
+ }
+
+ @Test
+ public void testServe() {
+ final Server server = mock(Server.class);
+ when(server.getHost()).thenReturn("testhost");
+ when(server.getPort()).thenReturn(1234);
+ doNothing().when(server).serve(any(Request.class));
+
+ final LoadBalancer loadBalancer = new LoadBalancer();
+ loadBalancer.addServer(server);
+
+ verifyZeroInteractions(server);
+
+ final Request request = new Request("test");
+ for (int i = 0; i < loadBalancer.getNoOfServers() * 2; i++) {
+ loadBalancer.serverRequest(request);
+ }
+
+ verify(server, times(2)).serve(request);
+ verifyNoMoreInteractions(server);
+
+ }
+
+}
diff --git a/multiton/index.md b/multiton/index.md
index 617bedb6a..68fb6bbc6 100644
--- a/multiton/index.md
+++ b/multiton/index.md
@@ -4,14 +4,18 @@ title: Multiton
folder: multiton
permalink: /patterns/multiton/
categories: Creational
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** Ensure a class only has limited number of instances, and provide a
+## Intent
+Ensure a class only has limited number of instances, and provide a
global point of access to them.

-**Applicability:** Use the Multiton pattern when
+## Applicability
+Use the Multiton pattern when
* there must be specific number of instances of a class, and they must be accessible to clients from a well-known access point
diff --git a/multiton/pom.xml b/multiton/pom.xml
index 96a80b5f4..5240ba6be 100644
--- a/multiton/pom.xml
+++ b/multiton/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTmultiton
diff --git a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
index 41b1387a6..6901e6086 100644
--- a/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
+++ b/multiton/src/test/java/com/iluwatar/multiton/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.multiton;
import org.junit.Test;
-import com.iluwatar.multiton.App;
-
/**
*
* Application test
diff --git a/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
new file mode 100644
index 000000000..923f76b1e
--- /dev/null
+++ b/multiton/src/test/java/com/iluwatar/multiton/NazgulTest.java
@@ -0,0 +1,29 @@
+package com.iluwatar.multiton;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Date: 12/22/15 - 22:28 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class NazgulTest {
+
+ /**
+ * Verify if {@link Nazgul#getInstance(NazgulName)} returns the correct Nazgul multiton instance
+ */
+ @Test
+ public void testGetInstance() {
+ for (final NazgulName name : NazgulName.values()) {
+ final Nazgul nazgul = Nazgul.getInstance(name);
+ assertNotNull(nazgul);
+ assertSame(nazgul, Nazgul.getInstance(name));
+ assertEquals(name, nazgul.getName());
+ }
+ }
+
+}
diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml
index 60c2043d1..24a054c67 100644
--- a/naked-objects/dom/pom.xml
+++ b/naked-objects/dom/pom.xml
@@ -16,7 +16,7 @@
com.iluwatarnaked-objects
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTnaked-objects-dom
diff --git a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java
index 6769f95dd..fa1e74048 100644
--- a/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java
+++ b/naked-objects/dom/src/main/java/domainapp/dom/app/homepage/HomePageService.java
@@ -21,9 +21,7 @@ import org.apache.isis.applib.annotation.HomePage;
import org.apache.isis.applib.annotation.NatureOfService;
import org.apache.isis.applib.annotation.SemanticsOf;
-@DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY // trick to suppress the actions
- // from the top-level menu
-)
+@DomainService(nature = NatureOfService.VIEW_CONTRIBUTIONS_ONLY)
public class HomePageService {
// region > homePage (action)
diff --git a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java
index 5e4642455..849f01c5d 100644
--- a/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java
+++ b/naked-objects/dom/src/main/java/domainapp/dom/modules/simple/SimpleObjects.java
@@ -69,9 +69,12 @@ public class SimpleObjects {
}
}
+ /**
+ * Create simple object
+ */
@Action(domainEvent = CreateDomainEvent.class)
@MemberOrder(sequence = "3")
- public SimpleObject create(final @ParameterLayout(named = "Name") String name) {
+ public SimpleObject create(@ParameterLayout(named = "Name") final String name) {
final SimpleObject obj = container.newTransientInstance(SimpleObject.class);
obj.setName(name);
container.persistIfNotAlready(obj);
diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml
index 50839c54b..2cc097e92 100644
--- a/naked-objects/fixture/pom.xml
+++ b/naked-objects/fixture/pom.xml
@@ -16,7 +16,7 @@
com.iluwatarnaked-objects
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTnaked-objects-fixture
diff --git a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java
index 2918fe7f6..9a922a7be 100644
--- a/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java
+++ b/naked-objects/fixture/src/main/java/domainapp/fixture/modules/simple/SimpleObjectCreate.java
@@ -45,8 +45,6 @@ public class SimpleObjectCreate extends FixtureScript {
/**
* The created simple object (output).
- *
- * @return
*/
public SimpleObject getSimpleObject() {
return simpleObject;
@@ -57,9 +55,9 @@ public class SimpleObjectCreate extends FixtureScript {
@Override
protected void execute(final ExecutionContext ec) {
- String name = checkParam("name", ec, String.class);
+ String paramName = checkParam("name", ec, String.class);
- this.simpleObject = wrap(simpleObjects).create(name);
+ this.simpleObject = wrap(simpleObjects).create(paramName);
// also make available to UI
ec.addResult(this, simpleObject);
diff --git a/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java b/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java
index c978e0b82..6d17d9b63 100644
--- a/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java
+++ b/naked-objects/fixture/src/main/java/domainapp/fixture/scenarios/RecreateSimpleObjects.java
@@ -29,7 +29,7 @@ import domainapp.fixture.modules.simple.SimpleObjectsTearDown;
public class RecreateSimpleObjects extends FixtureScript {
- public final List NAMES = Collections.unmodifiableList(Arrays.asList("Foo", "Bar", "Baz",
+ public final List names = Collections.unmodifiableList(Arrays.asList("Foo", "Bar", "Baz",
"Frodo", "Froyo", "Fizz", "Bip", "Bop", "Bang", "Boo"));
public RecreateSimpleObjects() {
@@ -69,12 +69,12 @@ public class RecreateSimpleObjects extends FixtureScript {
protected void execute(final ExecutionContext ec) {
// defaults
- final int number = defaultParam("number", ec, 3);
+ final int paramNumber = defaultParam("number", ec, 3);
// validate
- if (number < 0 || number > NAMES.size()) {
+ if (paramNumber < 0 || paramNumber > names.size()) {
throw new IllegalArgumentException(String.format("number must be in range [0,%d)",
- NAMES.size()));
+ names.size()));
}
//
@@ -82,8 +82,8 @@ public class RecreateSimpleObjects extends FixtureScript {
//
ec.executeChild(this, new SimpleObjectsTearDown());
- for (int i = 0; i < number; i++) {
- final SimpleObjectCreate fs = new SimpleObjectCreate().setName(NAMES.get(i));
+ for (int i = 0; i < paramNumber; i++) {
+ final SimpleObjectCreate fs = new SimpleObjectCreate().setName(names.get(i));
ec.executeChild(this, fs.getName(), fs);
simpleObjects.add(fs.getSimpleObject());
}
diff --git a/naked-objects/index.md b/naked-objects/index.md
index 805cea810..eb1c083b1 100644
--- a/naked-objects/index.md
+++ b/naked-objects/index.md
@@ -4,25 +4,29 @@ title: Naked Objects
folder: naked-objects
permalink: /patterns/naked-objects/
categories: Architectural
-tags: Java
+tags:
+ - Java
+ - Difficulty-Expert
---
-**Intent:** The Naked Objects architectural pattern is well suited for rapid
+## Intent
+The Naked Objects architectural pattern is well suited for rapid
prototyping. Using the pattern, you only need to write the domain objects,
everything else is autogenerated by the framework.

-**Applicability:** Use the Naked Objects pattern when
+## Applicability
+Use the Naked Objects pattern when
* you are prototyping and need fast development cycle
* an autogenerated user interface is good enough
* you want to automatically publish the domain as REST services
-**Real world examples:**
+## Real world examples
* [Apache Isis](https://isis.apache.org/)
-**Credits:**
+## Credits
* [Richard Pawson - Naked Objects](http://downloads.nakedobjects.net/resources/Pawson%20thesis.pdf)
diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml
index e0c14547f..d5fb3c581 100644
--- a/naked-objects/integtests/pom.xml
+++ b/naked-objects/integtests/pom.xml
@@ -16,7 +16,7 @@
com.iluwatarnaked-objects
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTnaked-objects-integtests
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java b/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java
index c617915f1..90ae45d95 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/bootstrap/SimpleAppSystemInitializer.java
@@ -21,6 +21,12 @@ import org.apache.isis.objectstore.jdo.datanucleus.IsisConfigurationForJdoIntegT
public class SimpleAppSystemInitializer {
+ private SimpleAppSystemInitializer() {
+ }
+
+ /**
+ * Init test system
+ */
public static void initIsft() {
IsisSystemForTest isft = IsisSystemForTest.getElseNull();
if (isft == null) {
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java
index ef6012919..2ea375b4a 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/specglue/modules/simple/SimpleObjectGlue.java
@@ -29,7 +29,7 @@ import static org.junit.Assert.assertThat;
public class SimpleObjectGlue extends CukeGlueAbstract {
@Given("^there are.* (\\d+) simple objects$")
- public void there_are_N_simple_objects(int n) throws Throwable {
+ public void thereAreNumSimpleObjects(int n) throws Throwable {
try {
final List findAll = service(SimpleObjects.class).listAll();
assertThat(findAll.size(), is(n));
@@ -41,7 +41,7 @@ public class SimpleObjectGlue extends CukeGlueAbstract {
}
@When("^I create a new simple object$")
- public void I_create_a_new_simple_object() throws Throwable {
+ public void createNewSimpleObject() throws Throwable {
service(SimpleObjects.class).create(UUID.randomUUID().toString());
}
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java
index 3ceef4e63..7a7ad91b2 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/SimpleAppIntegTest.java
@@ -27,13 +27,13 @@ import domainapp.integtests.bootstrap.SimpleAppSystemInitializer;
public abstract class SimpleAppIntegTest extends IntegrationTestAbstract {
- @BeforeClass
- public static void initClass() {
- org.apache.log4j.PropertyConfigurator.configure("logging.properties");
- SimpleAppSystemInitializer.initIsft();
+ @BeforeClass
+ public static void initClass() {
+ org.apache.log4j.PropertyConfigurator.configure("logging.properties");
+ SimpleAppSystemInitializer.initIsft();
- // instantiating will install onto ThreadLocal
- new ScenarioExecutionForIntegration();
- }
+ // instantiating will install onto ThreadLocal
+ new ScenarioExecutionForIntegration();
+ }
}
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java
index 610136bb8..872aff7a3 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectIntegTest.java
@@ -35,87 +35,86 @@ import static org.assertj.core.api.Assertions.assertThat;
public class SimpleObjectIntegTest extends SimpleAppIntegTest {
+ @Inject
+ FixtureScripts fixtureScripts;
+
+ RecreateSimpleObjects fs;
+ SimpleObject simpleObjectPojo;
+ SimpleObject simpleObjectWrapped;
+
+ @Before
+ public void setUp() throws Exception {
+ // given
+ fs = new RecreateSimpleObjects().setNumber(1);
+ fixtureScripts.runFixtureScript(fs, null);
+
+ simpleObjectPojo = fs.getSimpleObjects().get(0);
+
+ assertThat(simpleObjectPojo).isNotNull();
+ simpleObjectWrapped = wrap(simpleObjectPojo);
+ }
+
+ public static class Name extends SimpleObjectIntegTest {
+
+ @Test
+ public void accessible() throws Exception {
+ // when
+ final String name = simpleObjectWrapped.getName();
+ // then
+ assertThat(name).isEqualTo(fs.names.get(0));
+ }
+
+ @Test
+ public void cannotBeUpdatedDirectly() throws Exception {
+
+ // expect
+ expectedExceptions.expect(DisabledException.class);
+
+ // when
+ simpleObjectWrapped.setName("new name");
+ }
+ }
+
+ public static class UpdateName extends SimpleObjectIntegTest {
+
+ @Test
+ public void happyCase() throws Exception {
+
+ // when
+ simpleObjectWrapped.updateName("new name");
+
+ // then
+ assertThat(simpleObjectWrapped.getName()).isEqualTo("new name");
+ }
+
+ @Test
+ public void failsValidation() throws Exception {
+
+ // expect
+ expectedExceptions.expect(InvalidException.class);
+ expectedExceptions.expectMessage("Exclamation mark is not allowed");
+
+ // when
+ simpleObjectWrapped.updateName("new name!");
+ }
+ }
+
+ public static class Title extends SimpleObjectIntegTest {
+
@Inject
- FixtureScripts fixtureScripts;
+ DomainObjectContainer container;
- RecreateSimpleObjects fs;
- SimpleObject simpleObjectPojo;
- SimpleObject simpleObjectWrapped;
+ @Test
+ public void interpolatesName() throws Exception {
- @Before
- public void setUp() throws Exception {
- // given
- fs = new RecreateSimpleObjects().setNumber(1);
- fixtureScripts.runFixtureScript(fs, null);
+ // given
+ final String name = simpleObjectWrapped.getName();
- simpleObjectPojo = fs.getSimpleObjects().get(0);
+ // when
+ final String title = container.titleOf(simpleObjectWrapped);
- assertThat(simpleObjectPojo).isNotNull();
- simpleObjectWrapped = wrap(simpleObjectPojo);
- }
-
- public static class Name extends SimpleObjectIntegTest {
-
- @Test
- public void accessible() throws Exception {
- // when
- final String name = simpleObjectWrapped.getName();
- // then
- assertThat(name).isEqualTo(fs.NAMES.get(0));
- }
-
- @Test
- public void cannotBeUpdatedDirectly() throws Exception {
-
- // expect
- expectedExceptions.expect(DisabledException.class);
-
- // when
- simpleObjectWrapped.setName("new name");
- }
- }
-
- public static class UpdateName extends SimpleObjectIntegTest {
-
- @Test
- public void happyCase() throws Exception {
-
- // when
- simpleObjectWrapped.updateName("new name");
-
- // then
- assertThat(simpleObjectWrapped.getName()).isEqualTo("new name");
- }
-
- @Test
- public void failsValidation() throws Exception {
-
- // expect
- expectedExceptions.expect(InvalidException.class);
- expectedExceptions.expectMessage("Exclamation mark is not allowed");
-
- // when
- simpleObjectWrapped.updateName("new name!");
- }
- }
-
-
- public static class Title extends SimpleObjectIntegTest {
-
- @Inject
- DomainObjectContainer container;
-
- @Test
- public void interpolatesName() throws Exception {
-
- // given
- final String name = simpleObjectWrapped.getName();
-
- // when
- final String title = container.titleOf(simpleObjectWrapped);
-
- // then
- assertThat(title).isEqualTo("Object: " + name);
- }
+ // then
+ assertThat(title).isEqualTo("Object: " + name);
}
+ }
}
\ No newline at end of file
diff --git a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java
index fd3b0ff46..332213542 100644
--- a/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java
+++ b/naked-objects/integtests/src/test/java/domainapp/integtests/tests/modules/simple/SimpleObjectsIntegTest.java
@@ -42,102 +42,102 @@ import static org.assertj.core.api.Assertions.assertThat;
public class SimpleObjectsIntegTest extends SimpleAppIntegTest {
- @Inject
- FixtureScripts fixtureScripts;
- @Inject
- SimpleObjects simpleObjects;
+ @Inject
+ FixtureScripts fixtureScripts;
+ @Inject
+ SimpleObjects simpleObjects;
- public static class ListAll extends SimpleObjectsIntegTest {
+ public static class ListAll extends SimpleObjectsIntegTest {
- @Test
- public void happyCase() throws Exception {
+ @Test
+ public void happyCase() throws Exception {
- // given
- RecreateSimpleObjects fs = new RecreateSimpleObjects();
- fixtureScripts.runFixtureScript(fs, null);
- nextTransaction();
+ // given
+ RecreateSimpleObjects fs = new RecreateSimpleObjects();
+ fixtureScripts.runFixtureScript(fs, null);
+ nextTransaction();
- // when
- final List all = wrap(simpleObjects).listAll();
+ // when
+ final List all = wrap(simpleObjects).listAll();
- // then
- assertThat(all).hasSize(fs.getSimpleObjects().size());
+ // then
+ assertThat(all).hasSize(fs.getSimpleObjects().size());
- SimpleObject simpleObject = wrap(all.get(0));
- assertThat(simpleObject.getName()).isEqualTo(fs.getSimpleObjects().get(0).getName());
- }
-
- @Test
- public void whenNone() throws Exception {
-
- // given
- FixtureScript fs = new SimpleObjectsTearDown();
- fixtureScripts.runFixtureScript(fs, null);
- nextTransaction();
-
- // when
- final List all = wrap(simpleObjects).listAll();
-
- // then
- assertThat(all).hasSize(0);
- }
+ SimpleObject simpleObject = wrap(all.get(0));
+ assertThat(simpleObject.getName()).isEqualTo(fs.getSimpleObjects().get(0).getName());
}
- public static class Create extends SimpleObjectsIntegTest {
+ @Test
+ public void whenNone() throws Exception {
- @Test
- public void happyCase() throws Exception {
+ // given
+ FixtureScript fs = new SimpleObjectsTearDown();
+ fixtureScripts.runFixtureScript(fs, null);
+ nextTransaction();
- // given
- FixtureScript fs = new SimpleObjectsTearDown();
- fixtureScripts.runFixtureScript(fs, null);
- nextTransaction();
+ // when
+ final List all = wrap(simpleObjects).listAll();
- // when
- wrap(simpleObjects).create("Faz");
-
- // then
- final List all = wrap(simpleObjects).listAll();
- assertThat(all).hasSize(1);
- }
-
- @Test
- public void whenAlreadyExists() throws Exception {
-
- // given
- FixtureScript fs = new SimpleObjectsTearDown();
- fixtureScripts.runFixtureScript(fs, null);
- nextTransaction();
- wrap(simpleObjects).create("Faz");
- nextTransaction();
-
- // then
- expectedExceptions.expectCause(causalChainContains(SQLIntegrityConstraintViolationException.class));
-
- // when
- wrap(simpleObjects).create("Faz");
- nextTransaction();
- }
-
- private static Matcher extends Throwable> causalChainContains(final Class> cls) {
- return new TypeSafeMatcher() {
- @Override
- protected boolean matchesSafely(Throwable item) {
- final List causalChain = Throwables.getCausalChain(item);
- for (Throwable throwable : causalChain) {
- if(cls.isAssignableFrom(throwable.getClass())){
- return true;
- }
- }
- return false;
- }
-
- @Override
- public void describeTo(Description description) {
- description.appendText("exception with causal chain containing " + cls.getSimpleName());
- }
- };
- }
+ // then
+ assertThat(all).hasSize(0);
}
+ }
+
+ public static class Create extends SimpleObjectsIntegTest {
+
+ @Test
+ public void happyCase() throws Exception {
+
+ // given
+ FixtureScript fs = new SimpleObjectsTearDown();
+ fixtureScripts.runFixtureScript(fs, null);
+ nextTransaction();
+
+ // when
+ wrap(simpleObjects).create("Faz");
+
+ // then
+ final List all = wrap(simpleObjects).listAll();
+ assertThat(all).hasSize(1);
+ }
+
+ @Test
+ public void whenAlreadyExists() throws Exception {
+
+ // given
+ FixtureScript fs = new SimpleObjectsTearDown();
+ fixtureScripts.runFixtureScript(fs, null);
+ nextTransaction();
+ wrap(simpleObjects).create("Faz");
+ nextTransaction();
+
+ // then
+ expectedExceptions.expectCause(causalChainContains(SQLIntegrityConstraintViolationException.class));
+
+ // when
+ wrap(simpleObjects).create("Faz");
+ nextTransaction();
+ }
+
+ private static Matcher extends Throwable> causalChainContains(final Class> cls) {
+ return new TypeSafeMatcher() {
+ @Override
+ protected boolean matchesSafely(Throwable item) {
+ final List causalChain = Throwables.getCausalChain(item);
+ for (Throwable throwable : causalChain) {
+ if (cls.isAssignableFrom(throwable.getClass())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("exception with causal chain containing " + cls.getSimpleName());
+ }
+ };
+ }
+ }
}
\ No newline at end of file
diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml
index 7e8714ce8..c5b188098 100644
--- a/naked-objects/pom.xml
+++ b/naked-objects/pom.xml
@@ -15,7 +15,7 @@
java-design-patternscom.iluwatar
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTnaked-objects
@@ -350,17 +350,17 @@
${project.groupId}naked-objects-dom
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOT${project.groupId}naked-objects-fixture
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOT${project.groupId}naked-objects-webapp
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOT
diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml
index 71d207b70..ad43bf91f 100644
--- a/naked-objects/webapp/pom.xml
+++ b/naked-objects/webapp/pom.xml
@@ -16,7 +16,7 @@
com.iluwatarnaked-objects
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTnaked-objects-webapp
diff --git a/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java b/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
index c7bbd8c80..a292a7779 100644
--- a/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
+++ b/naked-objects/webapp/src/main/java/domainapp/webapp/SimpleApplication.java
@@ -74,7 +74,7 @@ public class SimpleApplication extends IsisWicketApplication {
*
* for demos only, obvious.
*/
- private final static boolean DEMO_MODE_USING_CREDENTIALS_AS_QUERYARGS = false;
+ private static final boolean DEMO_MODE_USING_CREDENTIALS_AS_QUERYARGS = false;
@Override
@@ -116,6 +116,7 @@ public class SimpleApplication extends IsisWicketApplication {
servletRequest.getSession().invalidate();
}
} catch (Exception e) {
+ System.out.println(e);
}
WebRequest request = super.newWebRequest(servletRequest, filterPath);
return request;
diff --git a/null-object/index.md b/null-object/index.md
index 5127e8565..b5fb279db 100644
--- a/null-object/index.md
+++ b/null-object/index.md
@@ -4,10 +4,13 @@ title: Null Object
folder: null-object
permalink: /patterns/null-object/
categories: Behavioral
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** In most object-oriented languages, such as Java or C#, references
+## Intent
+In most object-oriented languages, such as Java or C#, references
may be null. These references need to be checked to ensure they are not null
before invoking any methods, because methods typically cannot be invoked on
null references. Instead of using a null reference to convey absence of an
@@ -18,6 +21,7 @@ Object is very predictable and has no side effects: it does nothing.

-**Applicability:** Use the Null Object pattern when
+## Applicability
+Use the Null Object pattern when
* you want to avoid explicit null checks and keep the algorithm elegant and easy to read.
diff --git a/null-object/pom.xml b/null-object/pom.xml
index 1ffb57320..c7312f227 100644
--- a/null-object/pom.xml
+++ b/null-object/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTnull-object
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java b/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java
index 5de258890..4478b9bfa 100644
--- a/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java
+++ b/null-object/src/main/java/com/iluwatar/nullobject/NodeImpl.java
@@ -11,6 +11,9 @@ public class NodeImpl implements Node {
private final Node left;
private final Node right;
+ /**
+ * Constructor
+ */
public NodeImpl(String name, Node left, Node right) {
this.name = name;
this.left = left;
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java b/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
index 58f03da28..0231c7b1a 100644
--- a/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
+++ b/null-object/src/test/java/com/iluwatar/nullobject/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.nullobject;
import org.junit.Test;
-import com.iluwatar.nullobject.App;
-
/**
*
* Application test
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java b/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java
new file mode 100644
index 000000000..2bb9a1b4a
--- /dev/null
+++ b/null-object/src/test/java/com/iluwatar/nullobject/NullNodeTest.java
@@ -0,0 +1,43 @@
+package com.iluwatar.nullobject;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Date: 12/26/15 - 11:47 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class NullNodeTest extends StdOutTest {
+
+ /**
+ * Verify if {@link NullNode#getInstance()} actually returns the same object instance
+ */
+ @Test
+ public void testGetInstance() {
+ final NullNode instance = NullNode.getInstance();
+ assertNotNull(instance);
+ assertSame(instance, NullNode.getInstance());
+ }
+
+ @Test
+ public void testFields() {
+ final NullNode node = NullNode.getInstance();
+ assertEquals(0, node.getTreeSize());
+ assertNull(node.getName());
+ assertNull(node.getLeft());
+ assertNull(node.getRight());
+ }
+
+ @Test
+ public void testWalk() throws Exception {
+ NullNode.getInstance().walk();
+ Mockito.verifyZeroInteractions(getStdOutMock());
+ }
+
+}
\ No newline at end of file
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/StdOutTest.java b/null-object/src/test/java/com/iluwatar/nullobject/StdOutTest.java
new file mode 100644
index 000000000..5a9bae163
--- /dev/null
+++ b/null-object/src/test/java/com/iluwatar/nullobject/StdOutTest.java
@@ -0,0 +1,54 @@
+package com.iluwatar.nullobject;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since walking through the tree has no
+ * influence on any other accessible object, except for writing to std-out using {@link
+ * System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
new file mode 100644
index 000000000..5d7968584
--- /dev/null
+++ b/null-object/src/test/java/com/iluwatar/nullobject/TreeTest.java
@@ -0,0 +1,101 @@
+package com.iluwatar.nullobject;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Date: 12/26/15 - 11:44 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class TreeTest extends StdOutTest {
+
+ /**
+ * During the tests, the same tree structure will be used, shown below. End points will be
+ * terminated with the {@link NullNode} instance.
+ *
+ *
- * In producer consumer design pattern a shared queue is used to control the flow and this
- * separation allows you to code producer and consumer separately. It also addresses the issue of
- * different timing require to produce item or consuming item. by using producer consumer pattern
- * both Producer and Consumer Thread can work with different speed.
+ * In producer consumer design pattern a shared queue is used to control the flow and this separation allows you to code
+ * producer and consumer separately. It also addresses the issue of different timing require to produce item or
+ * consuming item. by using producer consumer pattern both Producer and Consumer Thread can work with different speed.
*
*/
public class App {
@@ -20,7 +18,8 @@ public class App {
/**
* Program entry point
*
- * @param args command line args
+ * @param args
+ * command line args
*/
public static void main(String[] args) {
@@ -35,7 +34,7 @@ public class App {
producer.produce();
}
});
- };
+ }
for (int i = 0; i < 3; i++) {
final Consumer consumer = new Consumer("Consumer_" + i, queue);
diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java
index 8bb3b75b6..ff63ab41b 100644
--- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java
+++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Consumer.java
@@ -14,6 +14,9 @@ public class Consumer {
this.queue = queue;
}
+ /**
+ * Consume item from the queue
+ */
public void consume() throws InterruptedException {
Item item = queue.take();
diff --git a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java
index 40e71c607..8b122a5fc 100644
--- a/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java
+++ b/producer-consumer/src/main/java/com/iluwatar/producer/consumer/Producer.java
@@ -19,6 +19,9 @@ public class Producer {
this.queue = queue;
}
+ /**
+ * Put item in the queue
+ */
public void produce() throws InterruptedException {
Item item = new Item(name, itemId++);
diff --git a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java
index cdd9ad046..e82e36da1 100644
--- a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java
+++ b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.producer.consumer;
import org.junit.Test;
-import com.iluwatar.producer.consumer.App;
-
/**
*
* Application test
diff --git a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ConsumerTest.java b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ConsumerTest.java
new file mode 100644
index 000000000..4ff203d42
--- /dev/null
+++ b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ConsumerTest.java
@@ -0,0 +1,39 @@
+package com.iluwatar.producer.consumer;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+
+/**
+ * Date: 12/27/15 - 11:01 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ConsumerTest extends StdOutTest {
+
+ private static final int ITEM_COUNT = 5;
+
+ @Test
+ public void testConsume() throws Exception {
+ final ItemQueue queue = spy(new ItemQueue());
+ for (int id = 0; id < ITEM_COUNT; id++) {
+ queue.put(new Item("producer", id));
+ }
+
+ reset(queue); // Don't count the preparation above as interactions with the queue
+ final Consumer consumer = new Consumer("consumer", queue);
+
+ final InOrder inOrder = inOrder(getStdOutMock());
+ for (int id = 0; id < ITEM_COUNT; id++) {
+ consumer.consume();
+ inOrder.verify(getStdOutMock())
+ .println("Consumer [consumer] consume item [" + id + "] produced by [producer]");
+ }
+
+ inOrder.verifyNoMoreInteractions();
+ }
+
+}
diff --git a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ProducerTest.java b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ProducerTest.java
new file mode 100644
index 000000000..0605879dd
--- /dev/null
+++ b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/ProducerTest.java
@@ -0,0 +1,28 @@
+package com.iluwatar.producer.consumer;
+
+import org.junit.Test;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/28/15 - 12:12 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ProducerTest {
+
+ @Test(timeout = 6000)
+ public void testProduce() throws Exception {
+ final ItemQueue queue = mock(ItemQueue.class);
+ final Producer producer = new Producer("producer", queue);
+
+ producer.produce();
+ verify(queue).put(any(Item.class));
+
+ verifyNoMoreInteractions(queue);
+ }
+
+}
\ No newline at end of file
diff --git a/producer-consumer/src/test/java/com/iluwatar/producer/consumer/StdOutTest.java b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/StdOutTest.java
new file mode 100644
index 000000000..85d8fe6c0
--- /dev/null
+++ b/producer-consumer/src/test/java/com/iluwatar/producer/consumer/StdOutTest.java
@@ -0,0 +1,53 @@
+package com.iluwatar.producer.consumer;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/property/index.md b/property/index.md
index 1c5b28db6..0ac5c7a6c 100644
--- a/property/index.md
+++ b/property/index.md
@@ -4,18 +4,22 @@ title: Property
folder: property
permalink: /patterns/property/
categories: Creational
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** Create hierarchy of objects and new objects using already existing
+## Intent
+Create hierarchy of objects and new objects using already existing
objects as parents.

-**Applicability:** Use the Property pattern when
+## Applicability
+Use the Property pattern when
* when you like to have objects with dynamic set of fields and prototype inheritance
-**Real world examples:**
+## Real world examples
* [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) prototype inheritance
diff --git a/property/pom.xml b/property/pom.xml
index 0df1fb258..0d1ff2016 100644
--- a/property/pom.xml
+++ b/property/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTproperty
diff --git a/property/src/main/java/com/iluwatar/property/Character.java b/property/src/main/java/com/iluwatar/property/Character.java
index 10b8f495d..50e564623 100644
--- a/property/src/main/java/com/iluwatar/property/Character.java
+++ b/property/src/main/java/com/iluwatar/property/Character.java
@@ -18,6 +18,9 @@ public class Character implements Prototype {
private String name;
private Type type;
+ /**
+ * Constructor
+ */
public Character() {
this.prototype = new Prototype() { // Null-value object
@Override
@@ -43,6 +46,9 @@ public class Character implements Prototype {
this.prototype = prototype;
}
+ /**
+ * Constructor
+ */
public Character(String name, Character prototype) {
this.name = name;
this.type = prototype.type;
diff --git a/property/src/main/java/com/iluwatar/property/Prototype.java b/property/src/main/java/com/iluwatar/property/Prototype.java
index 13b4c8608..33e2d66d6 100644
--- a/property/src/main/java/com/iluwatar/property/Prototype.java
+++ b/property/src/main/java/com/iluwatar/property/Prototype.java
@@ -5,11 +5,11 @@ package com.iluwatar.property;
*/
public interface Prototype {
- public Integer get(Stats stat);
+ Integer get(Stats stat);
- public boolean has(Stats stat);
+ boolean has(Stats stat);
- public void set(Stats stat, Integer val);
+ void set(Stats stat, Integer val);
- public void remove(Stats stat);
+ void remove(Stats stat);
}
diff --git a/property/src/test/java/com/iluwatar/property/AppTest.java b/property/src/test/java/com/iluwatar/property/AppTest.java
index 75be2f649..bfa48ffab 100644
--- a/property/src/test/java/com/iluwatar/property/AppTest.java
+++ b/property/src/test/java/com/iluwatar/property/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.property;
import org.junit.Test;
-import com.iluwatar.property.App;
-
/**
*
* Application test
diff --git a/property/src/test/java/com/iluwatar/property/CharacterTest.java b/property/src/test/java/com/iluwatar/property/CharacterTest.java
new file mode 100644
index 000000000..6d9a7a14b
--- /dev/null
+++ b/property/src/test/java/com/iluwatar/property/CharacterTest.java
@@ -0,0 +1,103 @@
+package com.iluwatar.property;
+
+import org.junit.Test;
+
+import static com.iluwatar.property.Character.Type;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/28/15 - 7:46 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CharacterTest {
+
+ @Test
+ public void testPrototypeStats() throws Exception {
+ final Character prototype = new Character();
+
+ for (final Stats stat : Stats.values()) {
+ assertFalse(prototype.has(stat));
+ assertNull(prototype.get(stat));
+
+ final Integer expectedValue = stat.ordinal();
+ prototype.set(stat, expectedValue);
+ assertTrue(prototype.has(stat));
+ assertEquals(expectedValue, prototype.get(stat));
+
+ prototype.remove(stat);
+ assertFalse(prototype.has(stat));
+ assertNull(prototype.get(stat));
+ }
+
+ }
+
+ @Test
+ public void testCharacterStats() throws Exception {
+ final Character prototype = new Character();
+ for (final Stats stat : Stats.values()) {
+ prototype.set(stat, stat.ordinal());
+ }
+
+ final Character mage = new Character(Type.MAGE, prototype);
+ for (final Stats stat : Stats.values()) {
+ final Integer expectedValue = stat.ordinal();
+ assertTrue(mage.has(stat));
+ assertEquals(expectedValue, mage.get(stat));
+ }
+ }
+
+ @Test
+ public void testToString() throws Exception {
+ final Character prototype = new Character();
+ prototype.set(Stats.ARMOR, 1);
+ prototype.set(Stats.AGILITY, 2);
+ prototype.set(Stats.INTELLECT, 3);
+ assertEquals("Stats:\n - AGILITY:2\n - ARMOR:1\n - INTELLECT:3\n", prototype.toString());
+
+ final Character stupid = new Character(Type.ROGUE, prototype);
+ stupid.remove(Stats.INTELLECT);
+ assertEquals("Character type: ROGUE\nStats:\n - AGILITY:2\n - ARMOR:1\n", stupid.toString());
+
+ final Character weak = new Character("weak", prototype);
+ weak.remove(Stats.ARMOR);
+ assertEquals("Player: weak\nStats:\n - AGILITY:2\n - INTELLECT:3\n", weak.toString());
+
+ }
+
+ @Test
+ public void testName() throws Exception {
+ final Character prototype = new Character();
+ prototype.set(Stats.ARMOR, 1);
+ prototype.set(Stats.INTELLECT, 2);
+ assertNull(prototype.name());
+
+ final Character stupid = new Character(Type.ROGUE, prototype);
+ stupid.remove(Stats.INTELLECT);
+ assertNull(stupid.name());
+
+ final Character weak = new Character("weak", prototype);
+ weak.remove(Stats.ARMOR);
+ assertEquals("weak", weak.name());
+ }
+
+ @Test
+ public void testType() throws Exception {
+ final Character prototype = new Character();
+ prototype.set(Stats.ARMOR, 1);
+ prototype.set(Stats.INTELLECT, 2);
+ assertNull(prototype.type());
+
+ final Character stupid = new Character(Type.ROGUE, prototype);
+ stupid.remove(Stats.INTELLECT);
+ assertEquals(Type.ROGUE, stupid.type());
+
+ final Character weak = new Character("weak", prototype);
+ weak.remove(Stats.ARMOR);
+ assertNull(weak.type());
+ }
+
+}
\ No newline at end of file
diff --git a/prototype/index.md b/prototype/index.md
index 9d108ff06..632daca93 100644
--- a/prototype/index.md
+++ b/prototype/index.md
@@ -7,23 +7,26 @@ categories: Creational
tags:
- Java
- Gang Of Four
+ - Difficulty-Beginner
---
-**Intent:** Specify the kinds of objects to create using a prototypical
+## Intent
+Specify the kinds of objects to create using a prototypical
instance, and create new objects by copying this prototype.

-**Applicability:** Use the Prototype pattern when a system should be independent of how its products are created, composed and represented; and
+## Applicability
+Use the Prototype pattern when a system should be independent of how its products are created, composed and represented; and
* when the classes to instantiate are specified at run-time, for example, by dynamic loading; or
* to avoid building a class hierarchy of factories that parallels the class hierarchy of products; or
* when instances of a class can have one of only a few different combinations of state. It may be more convenient to install a corresponding number of prototypes and clone them rather than instantiating the class manually, each time with the appropriate state
-**Real world examples:**
+## Real world examples
* [java.lang.Object#clone()](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone%28%29)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/prototype/pom.xml b/prototype/pom.xml
index 5e91880a6..411517d2e 100644
--- a/prototype/pom.xml
+++ b/prototype/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTprototype
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java b/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
index f5cb8bdaf..679882097 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfBeast.java
@@ -9,11 +9,9 @@ public class ElfBeast extends Beast {
public ElfBeast() {}
- public ElfBeast(ElfBeast beast) {}
-
@Override
public Beast clone() throws CloneNotSupportedException {
- return new ElfBeast(this);
+ return new ElfBeast();
}
@Override
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java b/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
index c801e4007..42ce9d530 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfMage.java
@@ -9,11 +9,9 @@ public class ElfMage extends Mage {
public ElfMage() {}
- public ElfMage(ElfMage mage) {}
-
@Override
public Mage clone() throws CloneNotSupportedException {
- return new ElfMage(this);
+ return new ElfMage();
}
@Override
diff --git a/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java b/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
index 8b5167b0e..1cba6943c 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/ElfWarlord.java
@@ -9,11 +9,9 @@ public class ElfWarlord extends Warlord {
public ElfWarlord() {}
- public ElfWarlord(ElfWarlord warlord) {}
-
@Override
public Warlord clone() throws CloneNotSupportedException {
- return new ElfWarlord(this);
+ return new ElfWarlord();
}
@Override
diff --git a/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java b/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
index 4c5a60bcd..85792104d 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/HeroFactoryImpl.java
@@ -11,12 +11,18 @@ public class HeroFactoryImpl implements HeroFactory {
private Warlord warlord;
private Beast beast;
+ /**
+ * Constructor
+ */
public HeroFactoryImpl(Mage mage, Warlord warlord, Beast beast) {
this.mage = mage;
this.warlord = warlord;
this.beast = beast;
}
+ /**
+ * Create mage
+ */
public Mage createMage() {
try {
return mage.clone();
@@ -25,6 +31,9 @@ public class HeroFactoryImpl implements HeroFactory {
}
}
+ /**
+ * Create warlord
+ */
public Warlord createWarlord() {
try {
return warlord.clone();
@@ -33,6 +42,9 @@ public class HeroFactoryImpl implements HeroFactory {
}
}
+ /**
+ * Create beast
+ */
public Beast createBeast() {
try {
return beast.clone();
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java b/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
index 50a6b5ae2..a45afb767 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcBeast.java
@@ -9,11 +9,9 @@ public class OrcBeast extends Beast {
public OrcBeast() {}
- public OrcBeast(OrcBeast beast) {}
-
@Override
public Beast clone() throws CloneNotSupportedException {
- return new OrcBeast(this);
+ return new OrcBeast();
}
@Override
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java b/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
index f27d12519..47a33379b 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcMage.java
@@ -9,11 +9,9 @@ public class OrcMage extends Mage {
public OrcMage() {}
- public OrcMage(OrcMage mage) {}
-
@Override
public Mage clone() throws CloneNotSupportedException {
- return new OrcMage(this);
+ return new OrcMage();
}
@Override
diff --git a/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java b/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
index d21816d8e..40ab91113 100644
--- a/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
+++ b/prototype/src/main/java/com/iluwatar/prototype/OrcWarlord.java
@@ -9,11 +9,9 @@ public class OrcWarlord extends Warlord {
public OrcWarlord() {}
- public OrcWarlord(OrcWarlord warlord) {}
-
@Override
public Warlord clone() throws CloneNotSupportedException {
- return new OrcWarlord(this);
+ return new OrcWarlord();
}
@Override
diff --git a/prototype/src/test/java/com/iluwatar/prototype/AppTest.java b/prototype/src/test/java/com/iluwatar/prototype/AppTest.java
index c2b8ea4ff..772a88a03 100644
--- a/prototype/src/test/java/com/iluwatar/prototype/AppTest.java
+++ b/prototype/src/test/java/com/iluwatar/prototype/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.prototype;
import org.junit.Test;
-import com.iluwatar.prototype.App;
-
/**
*
* Application test
diff --git a/prototype/src/test/java/com/iluwatar/prototype/HeroFactoryImplTest.java b/prototype/src/test/java/com/iluwatar/prototype/HeroFactoryImplTest.java
new file mode 100644
index 000000000..e237b43b7
--- /dev/null
+++ b/prototype/src/test/java/com/iluwatar/prototype/HeroFactoryImplTest.java
@@ -0,0 +1,39 @@
+package com.iluwatar.prototype;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Date: 12/28/15 - 8:34 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class HeroFactoryImplTest {
+
+ @Test
+ public void testFactory() throws Exception {
+ final Mage mage = mock(Mage.class);
+ final Warlord warlord = mock(Warlord.class);
+ final Beast beast = mock(Beast.class);
+
+ when(mage.clone()).thenThrow(CloneNotSupportedException.class);
+ when(warlord.clone()).thenThrow(CloneNotSupportedException.class);
+ when(beast.clone()).thenThrow(CloneNotSupportedException.class);
+
+ final HeroFactoryImpl factory = new HeroFactoryImpl(mage, warlord, beast);
+ assertNull(factory.createMage());
+ assertNull(factory.createWarlord());
+ assertNull(factory.createBeast());
+
+ verify(mage).clone();
+ verify(warlord).clone();
+ verify(beast).clone();
+ verifyNoMoreInteractions(mage, warlord, beast);
+ }
+
+}
\ No newline at end of file
diff --git a/prototype/src/test/java/com/iluwatar/prototype/PrototypeTest.java b/prototype/src/test/java/com/iluwatar/prototype/PrototypeTest.java
new file mode 100644
index 000000000..3e3d8f88b
--- /dev/null
+++ b/prototype/src/test/java/com/iluwatar/prototype/PrototypeTest.java
@@ -0,0 +1,66 @@
+package com.iluwatar.prototype;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+/**
+ * Date: 12/28/15 - 8:45 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+@RunWith(Parameterized.class)
+public class PrototypeTest
{
+
+ @Parameterized.Parameters
+ public static Collection data() {
+ return Arrays.asList(
+ new Object[]{new OrcBeast(), "Orcish wolf"},
+ new Object[]{new OrcMage(), "Orcish mage"},
+ new Object[]{new OrcWarlord(), "Orcish warlord"},
+ new Object[]{new ElfBeast(), "Elven eagle"},
+ new Object[]{new ElfMage(), "Elven mage"},
+ new Object[]{new ElfWarlord(), "Elven warlord"}
+ );
+ }
+
+ /**
+ * The tested prototype instance
+ */
+ private final Prototype testedPrototype;
+
+ /**
+ * The expected {@link Prototype#toString()} value
+ */
+ private final String expectedToString;
+
+ /**
+ * Create a new test instance, using the given test object and expected value
+ *
+ * @param testedPrototype The tested prototype instance
+ * @param expectedToString The expected {@link Prototype#toString()} value
+ */
+ public PrototypeTest(final Prototype testedPrototype, final String expectedToString) {
+ this.expectedToString = expectedToString;
+ this.testedPrototype = testedPrototype;
+ }
+
+ @Test
+ public void testPrototype() throws Exception {
+ assertEquals(this.expectedToString, this.testedPrototype.toString());
+
+ final Object clone = this.testedPrototype.clone();
+ assertNotNull(clone);
+ assertNotSame(clone, this.testedPrototype);
+ assertSame(this.testedPrototype.getClass(), clone.getClass());
+ }
+
+}
diff --git a/proxy/index.md b/proxy/index.md
index baa759600..a3e03708e 100644
--- a/proxy/index.md
+++ b/proxy/index.md
@@ -7,17 +7,20 @@ categories: Structural
tags:
- Java
- Gang Of Four
- - Difficulty-Intermediate
+ - Difficulty-Beginner
---
-**Also known as:** Surrogate
+## Also known as
+Surrogate
-**Intent:** Provide a surrogate or placeholder for another object to control
+## Intent
+Provide a surrogate or placeholder for another object to control
access to it.

-**Applicability:** Proxy is applicable whenever there is a need for a more
+## Applicability
+Proxy is applicable whenever there is a need for a more
versatile or sophisticated reference to an object than a simple pointer. Here
are several common situations in which the Proxy pattern is applicable
@@ -25,7 +28,7 @@ are several common situations in which the Proxy pattern is applicable
* a virtual proxy creates expensive objects on demand.
* a protection proxy controls access to the original object. Protection proxies are useful when objects should have different access rights.
-**Typical Use Case:**
+## Typical Use Case
* control access to another object
* lazy initialization
@@ -33,11 +36,11 @@ are several common situations in which the Proxy pattern is applicable
* facilitate network connection
* to count references to an object
-**Real world examples:**
+## Real world examples
* [java.lang.reflect.Proxy](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html)
* [Apache Commons Proxy](https://commons.apache.org/proper/commons-proxy/)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/proxy/pom.xml b/proxy/pom.xml
index 3a662b37a..139934c13 100644
--- a/proxy/pom.xml
+++ b/proxy/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTproxy
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/proxy/src/main/java/com/iluwatar/proxy/App.java b/proxy/src/main/java/com/iluwatar/proxy/App.java
index 25a903e41..837424f28 100644
--- a/proxy/src/main/java/com/iluwatar/proxy/App.java
+++ b/proxy/src/main/java/com/iluwatar/proxy/App.java
@@ -18,6 +18,9 @@ package com.iluwatar.proxy;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) {
WizardTowerProxy tower = new WizardTowerProxy();
diff --git a/proxy/src/test/java/com/iluwatar/proxy/AppTest.java b/proxy/src/test/java/com/iluwatar/proxy/AppTest.java
index a68629646..0485dabb6 100644
--- a/proxy/src/test/java/com/iluwatar/proxy/AppTest.java
+++ b/proxy/src/test/java/com/iluwatar/proxy/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.proxy;
import org.junit.Test;
-import com.iluwatar.proxy.App;
-
/**
*
* Application test
diff --git a/proxy/src/test/java/com/iluwatar/proxy/StdOutTest.java b/proxy/src/test/java/com/iluwatar/proxy/StdOutTest.java
new file mode 100644
index 000000000..a145b7b80
--- /dev/null
+++ b/proxy/src/test/java/com/iluwatar/proxy/StdOutTest.java
@@ -0,0 +1,53 @@
+package com.iluwatar.proxy;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/proxy/src/test/java/com/iluwatar/proxy/WizardTest.java b/proxy/src/test/java/com/iluwatar/proxy/WizardTest.java
new file mode 100644
index 000000000..c1b9e6fed
--- /dev/null
+++ b/proxy/src/test/java/com/iluwatar/proxy/WizardTest.java
@@ -0,0 +1,22 @@
+package com.iluwatar.proxy;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Date: 12/28/15 - 9:02 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class WizardTest {
+
+ @Test
+ public void testToString() throws Exception {
+ final String[] wizardNames = {"Gandalf", "Dumbledore", "Oz", "Merlin"};
+ for (final String name : wizardNames) {
+ assertEquals(name, new Wizard(name).toString());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/proxy/src/test/java/com/iluwatar/proxy/WizardTowerProxyTest.java b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerProxyTest.java
new file mode 100644
index 000000000..dcde88f8c
--- /dev/null
+++ b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerProxyTest.java
@@ -0,0 +1,38 @@
+package com.iluwatar.proxy;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.inOrder;
+
+/**
+ * Date: 12/28/15 - 9:18 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class WizardTowerProxyTest extends StdOutTest {
+
+ @Test
+ public void testEnter() throws Exception {
+ final Wizard[] wizards = new Wizard[]{
+ new Wizard("Gandalf"),
+ new Wizard("Dumbledore"),
+ new Wizard("Oz"),
+ new Wizard("Merlin")
+ };
+
+ final WizardTowerProxy tower = new WizardTowerProxy();
+ for (final Wizard wizard : wizards) {
+ tower.enter(wizard);
+ }
+
+ final InOrder inOrder = inOrder(getStdOutMock());
+ inOrder.verify(getStdOutMock()).println("Gandalf enters the tower.");
+ inOrder.verify(getStdOutMock()).println("Dumbledore enters the tower.");
+ inOrder.verify(getStdOutMock()).println("Oz enters the tower.");
+ inOrder.verify(getStdOutMock()).println("Merlin is not allowed to enter!");
+ inOrder.verifyNoMoreInteractions();
+
+ }
+
+}
\ No newline at end of file
diff --git a/proxy/src/test/java/com/iluwatar/proxy/WizardTowerTest.java b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerTest.java
new file mode 100644
index 000000000..007b92a33
--- /dev/null
+++ b/proxy/src/test/java/com/iluwatar/proxy/WizardTowerTest.java
@@ -0,0 +1,38 @@
+package com.iluwatar.proxy;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.inOrder;
+
+/**
+ * Date: 12/28/15 - 9:18 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class WizardTowerTest extends StdOutTest {
+
+ @Test
+ public void testEnter() throws Exception {
+ final Wizard[] wizards = new Wizard[]{
+ new Wizard("Gandalf"),
+ new Wizard("Dumbledore"),
+ new Wizard("Oz"),
+ new Wizard("Merlin")
+ };
+
+ final WizardTower tower = new WizardTower();
+ for (final Wizard wizard : wizards) {
+ tower.enter(wizard);
+ }
+
+ final InOrder inOrder = inOrder(getStdOutMock());
+ inOrder.verify(getStdOutMock()).println("Gandalf enters the tower.");
+ inOrder.verify(getStdOutMock()).println("Dumbledore enters the tower.");
+ inOrder.verify(getStdOutMock()).println("Oz enters the tower.");
+ inOrder.verify(getStdOutMock()).println("Merlin enters the tower.");
+ inOrder.verifyNoMoreInteractions();
+
+ }
+
+}
\ No newline at end of file
diff --git a/publish-subscribe/index.md b/publish-subscribe/index.md
index b91f22e3b..a9fa7d437 100644
--- a/publish-subscribe/index.md
+++ b/publish-subscribe/index.md
@@ -7,12 +7,15 @@ categories: Integration
tags:
- Java
- EIP
+ - Camel
---
-**Intent:** Broadcast messages from sender to all the interested receivers.
+## Intent
+Broadcast messages from sender to all the interested receivers.

-**Applicability:** Use the Publish Subscribe Channel pattern when
+## Applicability
+Use the Publish Subscribe Channel pattern when
* two or more applications need to communicate using a messaging system for broadcasts.
diff --git a/publish-subscribe/pom.xml b/publish-subscribe/pom.xml
index 1d5c0501d..fad968b19 100644
--- a/publish-subscribe/pom.xml
+++ b/publish-subscribe/pom.xml
@@ -4,7 +4,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTpublish-subscribe
diff --git a/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java b/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java
index 30f982ed1..f80dd1ad1 100644
--- a/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java
+++ b/publish-subscribe/src/main/java/com/iluwatar/publish/subscribe/App.java
@@ -28,10 +28,6 @@ public class App {
/**
* Program entry point
- *
- * @param args
- * command line args
- * @throws Exception
*/
public static void main(String[] args) throws Exception {
CamelContext context = new DefaultCamelContext();
diff --git a/reactor/index.md b/reactor/index.md
index 6e20598d2..b9ba98948 100644
--- a/reactor/index.md
+++ b/reactor/index.md
@@ -3,27 +3,30 @@ layout: pattern
title: Reactor
folder: reactor
permalink: /patterns/reactor/
-categories: Architectural
+categories: Concurrency
tags:
- Java
- Difficulty-Expert
+ - I/O
---
-**Intent:** The Reactor design pattern handles service requests that are delivered concurrently to an application by one or more clients. The application can register specific handlers for processing which are called by reactor on specific events. Dispatching of event handlers is performed by an initiation dispatcher, which manages the registered event handlers. Demultiplexing of service requests is performed by a synchronous event demultiplexer.
+## Intent
+The Reactor design pattern handles service requests that are delivered concurrently to an application by one or more clients. The application can register specific handlers for processing which are called by reactor on specific events. Dispatching of event handlers is performed by an initiation dispatcher, which manages the registered event handlers. Demultiplexing of service requests is performed by a synchronous event demultiplexer.

-**Applicability:** Use Reactor pattern when
+## Applicability
+Use Reactor pattern when
* a server application needs to handle concurrent service requests from multiple clients.
* a server application needs to be available for receiving requests from new clients even when handling older client requests.
* a server must maximize throughput, minimize latency and use CPU efficiently without blocking.
-**Real world examples:**
+## Real world examples
* [Spring Reactor](http://projectreactor.io/)
-**Credits**
+## Credits
* [Douglas C. Schmidt - Reactor](https://www.dre.vanderbilt.edu/~schmidt/PDF/Reactor.pdf)
* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697)
diff --git a/reactor/pom.xml b/reactor/pom.xml
index 1d450bcc8..c980d3b10 100644
--- a/reactor/pom.xml
+++ b/reactor/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTreactor
diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/App.java b/reactor/src/main/java/com/iluwatar/reactor/app/App.java
index 2c49d9001..d074c9b19 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/app/App.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/app/App.java
@@ -80,8 +80,6 @@ public class App {
/**
* App entry.
- *
- * @throws IOException
*/
public static void main(String[] args) throws IOException {
new App(new ThreadPoolDispatcher(2)).start();
diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java
index ee25b0be0..13cdd70e1 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java
@@ -37,10 +37,10 @@ public class AppClient {
* @throws IOException if any I/O error occurs.
*/
public void start() throws IOException {
- service.execute(new TCPLoggingClient("Client 1", 6666));
- service.execute(new TCPLoggingClient("Client 2", 6667));
- service.execute(new UDPLoggingClient("Client 3", 6668));
- service.execute(new UDPLoggingClient("Client 4", 6668));
+ service.execute(new TcpLoggingClient("Client 1", 6666));
+ service.execute(new TcpLoggingClient("Client 2", 6667));
+ service.execute(new UdpLoggingClient("Client 3", 6668));
+ service.execute(new UdpLoggingClient("Client 4", 6668));
}
/**
@@ -69,7 +69,7 @@ public class AppClient {
/**
* A logging client that sends requests to Reactor on TCP socket.
*/
- static class TCPLoggingClient implements Runnable {
+ static class TcpLoggingClient implements Runnable {
private final int serverPort;
private final String clientName;
@@ -80,7 +80,7 @@ public class AppClient {
* @param clientName the name of the client to be sent in logging requests.
* @param port the port on which client will send logging requests.
*/
- public TCPLoggingClient(String clientName, int serverPort) {
+ public TcpLoggingClient(String clientName, int serverPort) {
this.clientName = clientName;
this.serverPort = serverPort;
}
@@ -118,7 +118,7 @@ public class AppClient {
/**
* A logging client that sends requests to Reactor on UDP socket.
*/
- static class UDPLoggingClient implements Runnable {
+ static class UdpLoggingClient implements Runnable {
private final String clientName;
private final InetSocketAddress remoteAddress;
@@ -129,7 +129,7 @@ public class AppClient {
* @param port the port on which client will send logging requests.
* @throws UnknownHostException if localhost is unknown
*/
- public UDPLoggingClient(String clientName, int port) throws UnknownHostException {
+ public UdpLoggingClient(String clientName, int port) throws UnknownHostException {
this.clientName = clientName;
this.remoteAddress = new InetSocketAddress(InetAddress.getLocalHost(), port);
}
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java
index df08426d0..cd1318c89 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java
@@ -131,6 +131,7 @@ public abstract class AbstractNioChannel {
* channel.write(buffer, key);
* }
*
+ *
*
* @param data the data to be written on underlying channel.
* @param key the key which is writable.
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
index 16c13e5f9..271a6975d 100644
--- a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java
@@ -14,40 +14,41 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
- * This class acts as Synchronous Event De-multiplexer and Initiation Dispatcher of Reactor pattern.
- * Multiple handles i.e. {@link AbstractNioChannel}s can be registered to the reactor and it blocks
- * for events from all these handles. Whenever an event occurs on any of the registered handles, it
- * synchronously de-multiplexes the event which can be any of read, write or accept, and dispatches
- * the event to the appropriate {@link ChannelHandler} using the {@link Dispatcher}.
+ * This class acts as Synchronous Event De-multiplexer and Initiation Dispatcher of Reactor pattern. Multiple handles
+ * i.e. {@link AbstractNioChannel}s can be registered to the reactor and it blocks for events from all these handles.
+ * Whenever an event occurs on any of the registered handles, it synchronously de-multiplexes the event which can be any
+ * of read, write or accept, and dispatches the event to the appropriate {@link ChannelHandler} using the
+ * {@link Dispatcher}.
*
*
- * Implementation: A NIO reactor runs in its own thread when it is started using {@link #start()}
- * method. {@link NioReactor} uses {@link Selector} for realizing Synchronous Event De-multiplexing.
+ * Implementation: A NIO reactor runs in its own thread when it is started using {@link #start()} method.
+ * {@link NioReactor} uses {@link Selector} for realizing Synchronous Event De-multiplexing.
*
*
- * NOTE: This is one of the ways to implement NIO reactor and it does not take care of all possible
- * edge cases which are required in a real application. This implementation is meant to demonstrate
- * the fundamental concepts that lie behind Reactor pattern.
+ * NOTE: This is one of the ways to implement NIO reactor and it does not take care of all possible edge cases which are
+ * required in a real application. This implementation is meant to demonstrate the fundamental concepts that lie behind
+ * Reactor pattern.
*/
public class NioReactor {
private final Selector selector;
private final Dispatcher dispatcher;
/**
- * All the work of altering the SelectionKey operations and Selector operations are performed in
- * the context of main event loop of reactor. So when any channel needs to change its readability
- * or writability, a new command is added in the command queue and then the event loop picks up
- * the command and executes it in next iteration.
+ * All the work of altering the SelectionKey operations and Selector operations are performed in the context of main
+ * event loop of reactor. So when any channel needs to change its readability or writability, a new command is added
+ * in the command queue and then the event loop picks up the command and executes it in next iteration.
*/
private final Queue pendingCommands = new ConcurrentLinkedQueue<>();
private final ExecutorService reactorMain = Executors.newSingleThreadExecutor();
/**
- * Creates a reactor which will use provided {@code dispatcher} to dispatch events. The
- * application can provide various implementations of dispatcher which suits its needs.
+ * Creates a reactor which will use provided {@code dispatcher} to dispatch events. The application can provide
+ * various implementations of dispatcher which suits its needs.
*
- * @param dispatcher a non-null dispatcher used to dispatch events on registered channels.
- * @throws IOException if any I/O error occurs.
+ * @param dispatcher
+ * a non-null dispatcher used to dispatch events on registered channels.
+ * @throws IOException
+ * if any I/O error occurs.
*/
public NioReactor(Dispatcher dispatcher) throws IOException {
this.dispatcher = dispatcher;
@@ -57,7 +58,8 @@ public class NioReactor {
/**
* Starts the reactor event loop in a new thread.
*
- * @throws IOException if any I/O error occurs.
+ * @throws IOException
+ * if any I/O error occurs.
*/
public void start() throws IOException {
reactorMain.execute(() -> {
@@ -73,8 +75,10 @@ public class NioReactor {
/**
* Stops the reactor and related resources such as dispatcher.
*
- * @throws InterruptedException if interrupted while stopping the reactor.
- * @throws IOException if any I/O error occurs.
+ * @throws InterruptedException
+ * if interrupted while stopping the reactor.
+ * @throws IOException
+ * if any I/O error occurs.
*/
public void stop() throws InterruptedException, IOException {
reactorMain.shutdownNow();
@@ -84,15 +88,15 @@ public class NioReactor {
}
/**
- * Registers a new channel (handle) with this reactor. Reactor will start waiting for events on
- * this channel and notify of any events. While registering the channel the reactor uses
- * {@link AbstractNioChannel#getInterestedOps()} to know about the interested operation of this
- * channel.
+ * Registers a new channel (handle) with this reactor. Reactor will start waiting for events on this channel and
+ * notify of any events. While registering the channel the reactor uses {@link AbstractNioChannel#getInterestedOps()}
+ * to know about the interested operation of this channel.
*
- * @param channel a new channel on which reactor will wait for events. The channel must be bound
- * prior to being registered.
+ * @param channel
+ * a new channel on which reactor will wait for events. The channel must be bound prior to being registered.
* @return this
- * @throws IOException if any I/O error occurs.
+ * @throws IOException
+ * if any I/O error occurs.
*/
public NioReactor registerChannel(AbstractNioChannel channel) throws IOException {
SelectionKey key = channel.getJavaChannel().register(selector, channel.getInterestedOps());
@@ -113,8 +117,8 @@ public class NioReactor {
processPendingCommands();
/*
- * Synchronous event de-multiplexing happens here, this is blocking call which returns when it
- * is possible to initiate non-blocking operation on any of the registered channels.
+ * Synchronous event de-multiplexing happens here, this is blocking call which returns when it is possible to
+ * initiate non-blocking operation on any of the registered channels.
*/
selector.select();
@@ -147,8 +151,8 @@ public class NioReactor {
}
/*
- * Initiation dispatcher logic, it checks the type of event and notifier application specific
- * event handler to handle the event.
+ * Initiation dispatcher logic, it checks the type of event and notifier application specific event handler to handle
+ * the event.
*/
private void processKey(SelectionKey key) throws IOException {
if (key.isAcceptable()) {
@@ -196,14 +200,15 @@ public class NioReactor {
}
/**
- * Queues the change of operations request of a channel, which will change the interested
- * operations of the channel sometime in future.
+ * Queues the change of operations request of a channel, which will change the interested operations of the channel
+ * sometime in future.
*
- * This is a non-blocking method and does not guarantee that the operations have changed when this
- * method returns.
+ * This is a non-blocking method and does not guarantee that the operations have changed when this method returns.
*
- * @param key the key for which operations have to be changed.
- * @param interestedOps the new interest operations.
+ * @param key
+ * the key for which operations have to be changed.
+ * @param interestedOps
+ * the new interest operations.
*/
public void changeOps(SelectionKey key, int interestedOps) {
pendingCommands.add(new ChangeKeyOpsCommand(key, interestedOps));
diff --git a/repository/index.md b/repository/index.md
index 8ecd16528..67b3ea44e 100644
--- a/repository/index.md
+++ b/repository/index.md
@@ -3,11 +3,15 @@ layout: pattern
title: Repository
folder: repository
permalink: /patterns/repository/
-categories: Architectural
-tags: Java
+categories: Persistence Tier
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Spring
---
-**Intent:** Repository layer is added between the domain and data mapping
+## Intent
+Repository layer is added between the domain and data mapping
layers to isolate domain objects from details of the database access code and
to minimize scattering and duplication of query code. The Repository pattern is
especially useful in systems where number of domain classes is large or heavy
@@ -15,19 +19,19 @@ querying is utilized.

-**Applicability:** Use the Repository pattern when
+## Applicability
+Use the Repository pattern when
* the number of domain objects is large
* you want to avoid duplication of query code
* you want to keep the database querying code in single place
* you have multiple data sources
-**Real world examples:**
+## Real world examples
* [Spring Data](http://projects.spring.io/spring-data/)
-**Credits:**
+## Credits
* [Don’t use DAO, use Repository](http://thinkinginobjects.com/2012/08/26/dont-use-dao-use-repository/)
* [Advanced Spring Data JPA - Specifications and Querydsl](https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/)
-
diff --git a/repository/pom.xml b/repository/pom.xml
index 90056ab0c..05b468a04 100644
--- a/repository/pom.xml
+++ b/repository/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTrepository
diff --git a/repository/src/main/java/com/iluwatar/repository/AppConfig.java b/repository/src/main/java/com/iluwatar/repository/AppConfig.java
index cca09d8aa..62b9a4c04 100644
--- a/repository/src/main/java/com/iluwatar/repository/AppConfig.java
+++ b/repository/src/main/java/com/iluwatar/repository/AppConfig.java
@@ -39,8 +39,6 @@ public class AppConfig {
/**
* Factory to create a especific instance of Entity Manager
- *
- * @return
*/
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
@@ -55,8 +53,6 @@ public class AppConfig {
/**
* Properties for Jpa
- *
- * @return
*/
private Properties jpaProperties() {
Properties properties = new Properties();
@@ -65,6 +61,9 @@ public class AppConfig {
return properties;
}
+ /**
+ * Get transaction manager
+ */
@Bean
public JpaTransactionManager transactionManager() throws SQLException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
diff --git a/repository/src/main/java/com/iluwatar/repository/Person.java b/repository/src/main/java/com/iluwatar/repository/Person.java
index ca4013b54..04d65a6d0 100644
--- a/repository/src/main/java/com/iluwatar/repository/Person.java
+++ b/repository/src/main/java/com/iluwatar/repository/Person.java
@@ -23,6 +23,9 @@ public class Person {
public Person() {
}
+ /**
+ * Constructor
+ */
public Person(String name, String surname, int age) {
this.name = name;
this.surname = surname;
@@ -80,30 +83,40 @@ public class Person {
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
Person other = (Person) obj;
- if (age != other.age)
+ if (age != other.age) {
return false;
+ }
if (id == null) {
- if (other.id != null)
+ if (other.id != null) {
return false;
- } else if (!id.equals(other.id))
+ }
+ } else if (!id.equals(other.id)) {
return false;
+ }
if (name == null) {
- if (other.name != null)
+ if (other.name != null) {
return false;
- } else if (!name.equals(other.name))
+ }
+ } else if (!name.equals(other.name)) {
return false;
+ }
if (surname == null) {
- if (other.surname != null)
+ if (other.surname != null) {
return false;
- } else if (!surname.equals(other.surname))
+ }
+ } else if (!surname.equals(other.surname)) {
return false;
+ }
return true;
}
diff --git a/repository/src/main/java/com/iluwatar/repository/PersonRepository.java b/repository/src/main/java/com/iluwatar/repository/PersonRepository.java
index 98bb7abce..8d687f32d 100644
--- a/repository/src/main/java/com/iluwatar/repository/PersonRepository.java
+++ b/repository/src/main/java/com/iluwatar/repository/PersonRepository.java
@@ -13,5 +13,5 @@ import org.springframework.stereotype.Repository;
public interface PersonRepository
extends CrudRepository, JpaSpecificationExecutor {
- public Person findByName(String name);
+ Person findByName(String name);
}
diff --git a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
index ce9842dff..fa96f3ca6 100644
--- a/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
+++ b/repository/src/main/java/com/iluwatar/repository/PersonSpecifications.java
@@ -32,6 +32,10 @@ public class PersonSpecifications {
}
+ /**
+ * Name specification
+ *
+ */
public static class NameEqualSpec implements Specification {
public String name;
@@ -40,6 +44,9 @@ public class PersonSpecifications {
this.name = name;
}
+ /**
+ * Get predicate
+ */
public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb) {
return cb.equal(root.get("name"), this.name);
diff --git a/repository/src/main/resources/META-INF/persistence.xml b/repository/src/main/resources/META-INF/persistence.xml
index 0aded0dbd..00767fbc2 100644
--- a/repository/src/main/resources/META-INF/persistence.xml
+++ b/repository/src/main/resources/META-INF/persistence.xml
@@ -1,8 +1,8 @@
+ xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
-
+
diff --git a/repository/src/main/resources/applicationContext.xml b/repository/src/main/resources/applicationContext.xml
index 9322c9f64..ed03aba0a 100644
--- a/repository/src/main/resources/applicationContext.xml
+++ b/repository/src/main/resources/applicationContext.xml
@@ -1,39 +1,37 @@
-
+
-
-
-
-
-
+
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/repository/src/test/java/com/iluwatar/repository/AppConfigTest.java b/repository/src/test/java/com/iluwatar/repository/AppConfigTest.java
index 49e684bf1..17393f2ff 100644
--- a/repository/src/test/java/com/iluwatar/repository/AppConfigTest.java
+++ b/repository/src/test/java/com/iluwatar/repository/AppConfigTest.java
@@ -1,6 +1,7 @@
package com.iluwatar.repository;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -36,8 +37,6 @@ public class AppConfigTest {
/**
* Test for correct query execution
- *
- * @throws SQLException
*/
@Test
@Transactional
diff --git a/resource-acquisition-is-initialization/index.md b/resource-acquisition-is-initialization/index.md
index c3aa6c045..821f220d7 100644
--- a/resource-acquisition-is-initialization/index.md
+++ b/resource-acquisition-is-initialization/index.md
@@ -4,13 +4,18 @@ title: Resource Acquisition Is Initialization
folder: resource-acquisition-is-initialization
permalink: /patterns/resource-acquisition-is-initialization/
categories: Other
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Idiom
---
-**Intent:** Resource Acquisition Is Initialization pattern can be used to implement exception safe resource management.
+## Intent
+Resource Acquisition Is Initialization pattern can be used to implement exception safe resource management.

-**Applicability:** Use the Resource Acquisition Is Initialization pattern when
+## Applicability
+Use the Resource Acquisition Is Initialization pattern when
* you have resources that must be closed in every condition
diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml
index 133c7f3c1..3e3fc8729 100644
--- a/resource-acquisition-is-initialization/pom.xml
+++ b/resource-acquisition-is-initialization/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTresource-acquisition-is-initialization
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java
index 32cd3792e..f734432af 100644
--- a/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java
+++ b/resource-acquisition-is-initialization/src/main/java/com/iluwatar/resource/acquisition/is/initialization/App.java
@@ -24,9 +24,6 @@ public class App {
/**
* Program entry point
- *
- * @param args command line args
- * @throws Exception
*/
public static void main(String[] args) throws Exception {
diff --git a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java
index 2859f74ba..71b104b7c 100644
--- a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java
+++ b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.resource.acquisition.is.initialization;
import org.junit.Test;
-import com.iluwatar.resource.acquisition.is.initialization.App;
-
/**
*
* Application test
diff --git a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java
new file mode 100644
index 000000000..423d0ab51
--- /dev/null
+++ b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/ClosableTest.java
@@ -0,0 +1,27 @@
+package com.iluwatar.resource.acquisition.is.initialization;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.inOrder;
+
+/**
+ * Date: 12/28/15 - 9:31 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ClosableTest extends StdOutTest {
+
+ @Test
+ public void testOpenClose() throws Exception {
+ final InOrder inOrder = inOrder(getStdOutMock());
+ try (final SlidingDoor door = new SlidingDoor(); final TreasureChest chest = new TreasureChest()) {
+ inOrder.verify(getStdOutMock()).println("Sliding door opens.");
+ inOrder.verify(getStdOutMock()).println("Treasure chest opens.");
+ }
+ inOrder.verify(getStdOutMock()).println("Treasure chest closes.");
+ inOrder.verify(getStdOutMock()).println("Sliding door closes.");
+ inOrder.verifyNoMoreInteractions();
+ }
+
+}
\ No newline at end of file
diff --git a/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/StdOutTest.java b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/StdOutTest.java
new file mode 100644
index 000000000..2fdc09e27
--- /dev/null
+++ b/resource-acquisition-is-initialization/src/test/java/com/iluwatar/resource/acquisition/is/initialization/StdOutTest.java
@@ -0,0 +1,53 @@
+package com.iluwatar.resource.acquisition.is.initialization;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/servant/index.md b/servant/index.md
index 38a8e2c60..895b87502 100644
--- a/servant/index.md
+++ b/servant/index.md
@@ -4,15 +4,19 @@ title: Servant
folder: servant
permalink: /patterns/servant/
categories: Structural
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** Servant is used for providing some behavior to a group of classes.
+## Intent
+Servant is used for providing some behavior to a group of classes.
Instead of defining that behavior in each class - or when we cannot factor out
this behavior in the common parent class - it is defined once in the Servant.

-**Applicability:** Use the Servant pattern when
+## Applicability
+Use the Servant pattern when
* when we want some objects to perform a common action and don't want to define this action as a method in every class.
diff --git a/servant/pom.xml b/servant/pom.xml
index 19d58490d..3da9cae69 100644
--- a/servant/pom.xml
+++ b/servant/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTservant
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/servant/src/main/java/com/iluwatar/servant/App.java b/servant/src/main/java/com/iluwatar/servant/App.java
index 42babbc1d..cb5a63fa5 100644
--- a/servant/src/main/java/com/iluwatar/servant/App.java
+++ b/servant/src/main/java/com/iluwatar/servant/App.java
@@ -18,15 +18,13 @@ public class App {
/**
* Program entry point
- *
- * @param args
*/
public static void main(String[] args) {
scenario(jenkins, 1);
scenario(travis, 0);
}
- /*
+ /**
* Can add a List with enum Actions for variable scenarios
*/
public static void scenario(Servant servant, int compliment) {
@@ -44,16 +42,18 @@ public class App {
servant.giveWine(k);
servant.giveWine(q);
// compliment
- servant.GiveCompliments(guests.get(compliment));
+ servant.giveCompliments(guests.get(compliment));
// outcome of the night
- for (Royalty r : guests)
+ for (Royalty r : guests) {
r.changeMood();
+ }
// check your luck
- if (servant.checkIfYouWillBeHanged(guests))
+ if (servant.checkIfYouWillBeHanged(guests)) {
System.out.println(servant.name + " will live another day");
- else
+ } else {
System.out.println("Poor " + servant.name + ". His days are numbered");
+ }
}
}
diff --git a/servant/src/main/java/com/iluwatar/servant/King.java b/servant/src/main/java/com/iluwatar/servant/King.java
index 5e931c149..ab99252ad 100644
--- a/servant/src/main/java/com/iluwatar/servant/King.java
+++ b/servant/src/main/java/com/iluwatar/servant/King.java
@@ -28,10 +28,12 @@ public class King implements Royalty {
@Override
public void changeMood() {
- if (!isHungry && isDrunk)
+ if (!isHungry && isDrunk) {
isHappy = true;
- if (complimentReceived)
+ }
+ if (complimentReceived) {
isHappy = false;
+ }
}
@Override
diff --git a/servant/src/main/java/com/iluwatar/servant/Queen.java b/servant/src/main/java/com/iluwatar/servant/Queen.java
index db5446d34..b8568bdf1 100644
--- a/servant/src/main/java/com/iluwatar/servant/Queen.java
+++ b/servant/src/main/java/com/iluwatar/servant/Queen.java
@@ -29,8 +29,9 @@ public class Queen implements Royalty {
@Override
public void changeMood() {
- if (complimentReceived && isFlirty && isDrunk)
+ if (complimentReceived && isFlirty && isDrunk && !isHungry) {
isHappy = true;
+ }
}
@Override
diff --git a/servant/src/main/java/com/iluwatar/servant/Servant.java b/servant/src/main/java/com/iluwatar/servant/Servant.java
index 987bf8791..dbb623331 100644
--- a/servant/src/main/java/com/iluwatar/servant/Servant.java
+++ b/servant/src/main/java/com/iluwatar/servant/Servant.java
@@ -11,6 +11,9 @@ public class Servant {
public String name;
+ /**
+ * Constructor
+ */
public Servant(String name) {
this.name = name;
}
@@ -23,15 +26,20 @@ public class Servant {
r.getDrink();
}
- public void GiveCompliments(Royalty r) {
+ public void giveCompliments(Royalty r) {
r.receiveCompliments();
}
+ /**
+ * Check if we will be hanged
+ */
public boolean checkIfYouWillBeHanged(ArrayList tableGuests) {
boolean anotherDay = true;
- for (Royalty r : tableGuests)
- if (!r.getMood())
+ for (Royalty r : tableGuests) {
+ if (!r.getMood()) {
anotherDay = false;
+ }
+ }
return anotherDay;
}
diff --git a/servant/src/test/java/com/iluwatar/servant/AppTest.java b/servant/src/test/java/com/iluwatar/servant/AppTest.java
index d5a404291..20d5e6c0f 100644
--- a/servant/src/test/java/com/iluwatar/servant/AppTest.java
+++ b/servant/src/test/java/com/iluwatar/servant/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.servant;
import org.junit.Test;
-import com.iluwatar.servant.App;
-
/**
*
* Application test
diff --git a/servant/src/test/java/com/iluwatar/servant/KingTest.java b/servant/src/test/java/com/iluwatar/servant/KingTest.java
new file mode 100644
index 000000000..3c0811bc5
--- /dev/null
+++ b/servant/src/test/java/com/iluwatar/servant/KingTest.java
@@ -0,0 +1,82 @@
+package com.iluwatar.servant;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Date: 12/28/15 - 9:40 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class KingTest {
+
+ @Test
+ public void testHungrySoberUncomplimentedKing() {
+ final King king = new King();
+ king.changeMood();
+ assertFalse(king.getMood());
+ }
+
+ @Test
+ public void testFedSoberUncomplimentedKing() {
+ final King king = new King();
+ king.getFed();
+ king.changeMood();
+ assertFalse(king.getMood());
+ }
+
+ @Test
+ public void testHungryDrunkUncomplimentedKing() {
+ final King king = new King();
+ king.getDrink();
+ king.changeMood();
+ assertFalse(king.getMood());
+ }
+
+ @Test
+ public void testHungrySoberComplimentedKing() {
+ final King king = new King();
+ king.receiveCompliments();
+ king.changeMood();
+ assertFalse(king.getMood());
+ }
+
+ @Test
+ public void testFedDrunkUncomplimentedKing() {
+ final King king = new King();
+ king.getFed();
+ king.getDrink();
+ king.changeMood();
+ assertTrue(king.getMood());
+ }
+
+ @Test
+ public void testFedSoberComplimentedKing() {
+ final King king = new King();
+ king.getFed();
+ king.receiveCompliments();
+ king.changeMood();
+ assertFalse(king.getMood());
+ }
+
+ @Test
+ public void testFedDrunkComplimentedKing() {
+ final King king = new King();
+ king.getFed();
+ king.getDrink();
+ king.receiveCompliments();
+ king.changeMood();
+ assertFalse(king.getMood());
+ }
+
+ @Test
+ public void testHungryDrunkComplimentedKing() {
+ final King king = new King();
+ king.getDrink();
+ king.receiveCompliments();
+ king.changeMood();
+ assertFalse(king.getMood());
+ }
+
+}
\ No newline at end of file
diff --git a/servant/src/test/java/com/iluwatar/servant/QueenTest.java b/servant/src/test/java/com/iluwatar/servant/QueenTest.java
new file mode 100644
index 000000000..d6f02774c
--- /dev/null
+++ b/servant/src/test/java/com/iluwatar/servant/QueenTest.java
@@ -0,0 +1,46 @@
+package com.iluwatar.servant;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Date: 12/28/15 - 9:52 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class QueenTest {
+
+ @Test
+ public void testNotFlirtyUncomplemented() throws Exception {
+ final Queen queen = new Queen();
+ queen.setFlirtiness(false);
+ queen.changeMood();
+ assertFalse(queen.getMood());
+ }
+
+ @Test
+ public void testNotFlirtyComplemented() throws Exception {
+ final Queen queen = new Queen();
+ queen.setFlirtiness(false);
+ queen.receiveCompliments();
+ queen.changeMood();
+ assertFalse(queen.getMood());
+ }
+
+ @Test
+ public void testFlirtyUncomplemented() throws Exception {
+ final Queen queen = new Queen();
+ queen.changeMood();
+ assertFalse(queen.getMood());
+ }
+
+ @Test
+ public void testFlirtyComplemented() throws Exception {
+ final Queen queen = new Queen();
+ queen.receiveCompliments();
+ queen.changeMood();
+ assertTrue(queen.getMood());
+ }
+
+}
\ No newline at end of file
diff --git a/servant/src/test/java/com/iluwatar/servant/ServantTest.java b/servant/src/test/java/com/iluwatar/servant/ServantTest.java
new file mode 100644
index 000000000..9527bdbc9
--- /dev/null
+++ b/servant/src/test/java/com/iluwatar/servant/ServantTest.java
@@ -0,0 +1,70 @@
+package com.iluwatar.servant;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Date: 12/28/15 - 10:02 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ServantTest {
+
+ @Test
+ public void testFeed() throws Exception {
+ final Royalty royalty = mock(Royalty.class);
+ final Servant servant = new Servant("test");
+ servant.feed(royalty);
+ verify(royalty).getFed();
+ verifyNoMoreInteractions(royalty);
+ }
+
+ @Test
+ public void testGiveWine() throws Exception {
+ final Royalty royalty = mock(Royalty.class);
+ final Servant servant = new Servant("test");
+ servant.giveWine(royalty);
+ verify(royalty).getDrink();
+ verifyNoMoreInteractions(royalty);
+ }
+
+ @Test
+ public void testGiveCompliments() throws Exception {
+ final Royalty royalty = mock(Royalty.class);
+ final Servant servant = new Servant("test");
+ servant.giveCompliments(royalty);
+ verify(royalty).receiveCompliments();
+ verifyNoMoreInteractions(royalty);
+ }
+
+ @Test
+ public void testCheckIfYouWillBeHanged() throws Exception {
+ final Royalty goodMoodRoyalty = mock(Royalty.class);
+ when(goodMoodRoyalty.getMood()).thenReturn(true);
+
+ final Royalty badMoodRoyalty = mock(Royalty.class);
+ when(badMoodRoyalty.getMood()).thenReturn(true);
+
+ final ArrayList goodCompany = new ArrayList<>();
+ goodCompany.add(goodMoodRoyalty);
+ goodCompany.add(goodMoodRoyalty);
+ goodCompany.add(goodMoodRoyalty);
+
+ final ArrayList badCompany = new ArrayList<>();
+ goodCompany.add(goodMoodRoyalty);
+ goodCompany.add(goodMoodRoyalty);
+ goodCompany.add(badMoodRoyalty);
+
+ assertTrue(new Servant("test").checkIfYouWillBeHanged(goodCompany));
+ assertTrue(new Servant("test").checkIfYouWillBeHanged(badCompany));
+
+ }
+
+}
\ No newline at end of file
diff --git a/service-layer/index.md b/service-layer/index.md
index ea3f3d0ba..9b685d4e3 100644
--- a/service-layer/index.md
+++ b/service-layer/index.md
@@ -4,10 +4,13 @@ title: Service Layer
folder: service-layer
permalink: /patterns/service-layer/
categories: Architectural
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** Service Layer is an abstraction over domain logic. Typically
+## Intent
+Service Layer is an abstraction over domain logic. Typically
applications require multiple kinds of interfaces to the data they store and
logic they implement: data loaders, user interfaces, integration gateways, and
others. Despite their different purposes, these interfaces often need common
@@ -16,12 +19,13 @@ its business logic. The Service Layer fulfills this role.

-**Applicability:** Use the Service Layer pattern when
+## Applicability
+Use the Service Layer pattern when
* you want to encapsulate domain logic under API
* you need to implement multiple interfaces with common logic and data
-**Credits:**
+## Credits
* [Martin Fowler - Service Layer](http://martinfowler.com/eaaCatalog/serviceLayer.html)
* [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420)
diff --git a/service-layer/pom.xml b/service-layer/pom.xml
index b0a57cf5b..b8b977829 100644
--- a/service-layer/pom.xml
+++ b/service-layer/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTservice-layer
@@ -22,5 +22,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java
index a7053165d..ab0d3f9a0 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java
@@ -47,6 +47,9 @@ public class App {
queryData();
}
+ /**
+ * Initialize data
+ */
public static void initData() {
// spells
Spell spell1 = new Spell("Ice dart");
@@ -149,6 +152,9 @@ public class App {
wizardDao.merge(wizard4);
}
+ /**
+ * Query the data
+ */
public static void queryData() {
MagicService service =
new MagicServiceImpl(new WizardDaoImpl(), new SpellbookDaoImpl(), new SpellDaoImpl());
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/common/BaseEntity.java b/service-layer/src/main/java/com/iluwatar/servicelayer/common/BaseEntity.java
index d8c796427..ab0000922 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/common/BaseEntity.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/common/BaseEntity.java
@@ -12,8 +12,37 @@ import javax.persistence.Version;
*/
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
-public class BaseEntity {
+public abstract class BaseEntity {
@Version
private Long version;
+
+ /**
+ * Indicates the unique id of this entity
+ *
+ * @return The id of the entity, or 'null' when not persisted
+ */
+ public abstract Long getId();
+
+ /**
+ * Set the id of this entity
+ *
+ * @param id The new id
+ */
+ public abstract void setId(Long id);
+
+ /**
+ * Get the name of this entity
+ *
+ * @return The name of the entity
+ */
+ public abstract String getName();
+
+ /**
+ * Set the name of this entity
+ *
+ * @param name The new name
+ */
+ public abstract void setName(final String name);
+
}
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java
index eae9286fa..2665ff858 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/common/DaoBaseImpl.java
@@ -39,8 +39,9 @@ public abstract class DaoBaseImpl implements Dao {
result = (E) criteria.uniqueResult();
tx.commit();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
@@ -57,8 +58,9 @@ public abstract class DaoBaseImpl implements Dao {
session.persist(entity);
tx.commit();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
@@ -75,8 +77,9 @@ public abstract class DaoBaseImpl implements Dao {
result = (E) session.merge(entity);
tx.commit();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
@@ -93,8 +96,9 @@ public abstract class DaoBaseImpl implements Dao {
session.delete(entity);
tx.commit();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
@@ -111,8 +115,9 @@ public abstract class DaoBaseImpl implements Dao {
Criteria criteria = session.createCriteria(persistentClass);
result = criteria.list();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java b/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java
index 9d1aec488..9920a50df 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java
@@ -1,38 +1,56 @@
package com.iluwatar.servicelayer.hibernate;
-import org.hibernate.SessionFactory;
-import org.hibernate.cfg.Configuration;
-
import com.iluwatar.servicelayer.spell.Spell;
import com.iluwatar.servicelayer.spellbook.Spellbook;
import com.iluwatar.servicelayer.wizard.Wizard;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+
/**
- *
* Produces the Hibernate {@link SessionFactory}.
- *
*/
public class HibernateUtil {
- private static final SessionFactory sessionFactory;
+ /**
+ * The cached session factory
+ */
+ private static volatile SessionFactory sessionFactory;
- static {
- try {
- sessionFactory =
- new Configuration().addAnnotatedClass(Wizard.class).addAnnotatedClass(Spellbook.class)
- .addAnnotatedClass(Spell.class)
- .setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
- .setProperty("hibernate.connection.url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1")
- .setProperty("hibernate.current_session_context_class", "thread")
- .setProperty("hibernate.show_sql", "true")
- .setProperty("hibernate.hbm2ddl.auto", "create-drop").buildSessionFactory();
- } catch (Throwable ex) {
- System.err.println("Initial SessionFactory creation failed." + ex);
- throw new ExceptionInInitializerError(ex);
- }
+ private HibernateUtil() {
}
- public static SessionFactory getSessionFactory() {
+ /**
+ * Create the current session factory instance, create a new one when there is none yet.
+ *
+ * @return The session factory
+ */
+ public static synchronized SessionFactory getSessionFactory() {
+ if (sessionFactory == null) {
+ try {
+ sessionFactory =
+ new Configuration().addAnnotatedClass(Wizard.class).addAnnotatedClass(Spellbook.class)
+ .addAnnotatedClass(Spell.class)
+ .setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect")
+ .setProperty("hibernate.connection.url", "jdbc:h2:mem:test;DB_CLOSE_DELAY=-1")
+ .setProperty("hibernate.current_session_context_class", "thread")
+ .setProperty("hibernate.show_sql", "true")
+ .setProperty("hibernate.hbm2ddl.auto", "create-drop").buildSessionFactory();
+ } catch (Throwable ex) {
+ System.err.println("Initial SessionFactory creation failed." + ex);
+ throw new ExceptionInInitializerError(ex);
+ }
+ }
return sessionFactory;
}
+
+ /**
+ * Drop the current connection, resulting in a create-drop clean database next time. This is
+ * mainly used for JUnit testing since one test should not influence the other
+ */
+ public static void dropSession() {
+ getSessionFactory().close();
+ sessionFactory = null;
+ }
+
}
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java
index f46f55184..cda3fe58d 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java
@@ -21,6 +21,9 @@ public class MagicServiceImpl implements MagicService {
private SpellbookDao spellbookDao;
private SpellDao spellDao;
+ /**
+ * Constructor
+ */
public MagicServiceImpl(WizardDao wizardDao, SpellbookDao spellbookDao, SpellDao spellDao) {
this.wizardDao = wizardDao;
this.spellbookDao = spellbookDao;
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java
index f5f017625..708ba033e 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java
@@ -1,12 +1,12 @@
package com.iluwatar.servicelayer.spell;
+import com.iluwatar.servicelayer.common.DaoBaseImpl;
+
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
-import com.iluwatar.servicelayer.common.DaoBaseImpl;
-
/**
*
* SpellDao implementation.
@@ -24,11 +24,11 @@ public class SpellDaoImpl extends DaoBaseImpl implements SpellDao {
Criteria criteria = session.createCriteria(persistentClass);
criteria.add(Restrictions.eq("name", name));
result = (Spell) criteria.uniqueResult();
- result.getSpellbook().getWizards().size();
tx.commit();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java
index 49d81a955..165dcdc22 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java
@@ -6,6 +6,7 @@ import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
+import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
@@ -50,7 +51,7 @@ public class Spellbook extends BaseEntity {
private String name;
- @ManyToMany(mappedBy = "spellbooks")
+ @ManyToMany(mappedBy = "spellbooks", fetch = FetchType.EAGER)
private Set wizards;
@OneToMany(mappedBy = "spellbook", orphanRemoval = true, cascade = CascadeType.ALL)
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java
index 1de82d4a9..842764056 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImpl.java
@@ -28,8 +28,9 @@ public class SpellbookDaoImpl extends DaoBaseImpl implements Spellboo
result.getWizards().size();
tx.commit();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java
index ad89dd28a..9ff36edef 100644
--- a/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java
+++ b/service-layer/src/main/java/com/iluwatar/servicelayer/wizard/WizardDaoImpl.java
@@ -30,8 +30,9 @@ public class WizardDaoImpl extends DaoBaseImpl implements WizardDao {
}
tx.commit();
} catch (Exception e) {
- if (tx != null)
+ if (tx != null) {
tx.rollback();
+ }
throw e;
} finally {
session.close();
diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java
index 2a6202104..f92af7cff 100644
--- a/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java
+++ b/service-layer/src/test/java/com/iluwatar/servicelayer/app/AppTest.java
@@ -1,8 +1,9 @@
package com.iluwatar.servicelayer.app;
-import org.junit.Test;
+import com.iluwatar.servicelayer.hibernate.HibernateUtil;
-import com.iluwatar.servicelayer.app.App;
+import org.junit.After;
+import org.junit.Test;
/**
*
@@ -16,4 +17,10 @@ public class AppTest {
String[] args = {};
App.main(args);
}
+
+ @After
+ public void tearDown() throws Exception {
+ HibernateUtil.dropSession();
+ }
+
}
diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/common/BaseDaoTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/common/BaseDaoTest.java
new file mode 100644
index 000000000..1dabe117a
--- /dev/null
+++ b/service-layer/src/test/java/com/iluwatar/servicelayer/common/BaseDaoTest.java
@@ -0,0 +1,123 @@
+package com.iluwatar.servicelayer.common;
+
+import com.iluwatar.servicelayer.hibernate.HibernateUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+/**
+ * Date: 12/28/15 - 10:53 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class BaseDaoTest> {
+
+ /**
+ * The number of entities stored before each test
+ */
+ private static final int INITIAL_COUNT = 5;
+
+ /**
+ * The unique id generator, shared between all entities
+ */
+ private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
+
+ /**
+ * Factory, used to create new entity instances with the given name
+ */
+ private final Function factory;
+
+ /**
+ * The tested data access object
+ */
+ private final D dao;
+
+ /**
+ * Create a new test using the given factory and dao
+ *
+ * @param factory The factory, used to create new entity instances with the given name
+ * @param dao The tested data access object
+ */
+ public BaseDaoTest(final Function factory, final D dao) {
+ this.factory = factory;
+ this.dao = dao;
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ for (int i = 0; i < INITIAL_COUNT; i++) {
+ final String className = dao.persistentClass.getSimpleName();
+ final String entityName = String.format("%s%d", className, ID_GENERATOR.incrementAndGet());
+ this.dao.persist(this.factory.apply(entityName));
+ }
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ HibernateUtil.dropSession();
+ }
+
+ protected final D getDao() {
+ return this.dao;
+ }
+
+ @Test
+ public void testFind() throws Exception {
+ final List all = this.dao.findAll();
+ for (final E entity : all) {
+ final E byId = this.dao.find(entity.getId());
+ assertNotNull(byId);
+ assertEquals(byId.getId(), byId.getId());
+ }
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ final List originalEntities = this.dao.findAll();
+ this.dao.delete(originalEntities.get(1));
+ this.dao.delete(originalEntities.get(2));
+
+ final List entitiesLeft = this.dao.findAll();
+ assertNotNull(entitiesLeft);
+ assertEquals(INITIAL_COUNT - 2, entitiesLeft.size());
+ }
+
+ @Test
+ public void testFindAll() throws Exception {
+ final List all = this.dao.findAll();
+ assertNotNull(all);
+ assertEquals(INITIAL_COUNT, all.size());
+ }
+
+ @Test
+ public void testSetId() throws Exception {
+ final E entity = this.factory.apply("name");
+ assertNull(entity.getId());
+
+ final Long expectedId = Long.valueOf(1);
+ entity.setId(expectedId);
+ assertEquals(expectedId, entity.getId());
+ }
+
+ @Test
+ public void testSetName() throws Exception {
+ final E entity = this.factory.apply("name");
+ assertEquals("name", entity.getName());
+ assertEquals("name", entity.toString());
+
+ final String expectedName = "new name";
+ entity.setName(expectedName);
+ assertEquals(expectedName, entity.getName());
+ assertEquals(expectedName, entity.toString());
+ }
+
+}
\ No newline at end of file
diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/magic/MagicServiceImplTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/magic/MagicServiceImplTest.java
new file mode 100644
index 000000000..48f3ae9d3
--- /dev/null
+++ b/service-layer/src/test/java/com/iluwatar/servicelayer/magic/MagicServiceImplTest.java
@@ -0,0 +1,138 @@
+package com.iluwatar.servicelayer.magic;
+
+import com.iluwatar.servicelayer.spell.Spell;
+import com.iluwatar.servicelayer.spell.SpellDao;
+import com.iluwatar.servicelayer.spellbook.Spellbook;
+import com.iluwatar.servicelayer.spellbook.SpellbookDao;
+import com.iluwatar.servicelayer.wizard.Wizard;
+import com.iluwatar.servicelayer.wizard.WizardDao;
+
+import org.junit.Test;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * Date: 12/29/15 - 12:06 AM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class MagicServiceImplTest {
+
+ @Test
+ public void testFindAllWizards() throws Exception {
+ final WizardDao wizardDao = mock(WizardDao.class);
+ final SpellbookDao spellbookDao = mock(SpellbookDao.class);
+ final SpellDao spellDao = mock(SpellDao.class);
+
+ final MagicServiceImpl service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
+ verifyZeroInteractions(wizardDao, spellbookDao, spellDao);
+
+ service.findAllWizards();
+ verify(wizardDao).findAll();
+ verifyNoMoreInteractions(wizardDao, spellbookDao, spellDao);
+ }
+
+ @Test
+ public void testFindAllSpellbooks() throws Exception {
+ final WizardDao wizardDao = mock(WizardDao.class);
+ final SpellbookDao spellbookDao = mock(SpellbookDao.class);
+ final SpellDao spellDao = mock(SpellDao.class);
+
+ final MagicServiceImpl service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
+ verifyZeroInteractions(wizardDao, spellbookDao, spellDao);
+
+ service.findAllSpellbooks();
+ verify(spellbookDao).findAll();
+ verifyNoMoreInteractions(wizardDao, spellbookDao, spellDao);
+ }
+
+ @Test
+ public void testFindAllSpells() throws Exception {
+ final WizardDao wizardDao = mock(WizardDao.class);
+ final SpellbookDao spellbookDao = mock(SpellbookDao.class);
+ final SpellDao spellDao = mock(SpellDao.class);
+
+ final MagicServiceImpl service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
+ verifyZeroInteractions(wizardDao, spellbookDao, spellDao);
+
+ service.findAllSpells();
+ verify(spellDao).findAll();
+ verifyNoMoreInteractions(wizardDao, spellbookDao, spellDao);
+ }
+
+ @Test
+ public void testFindWizardsWithSpellbook() throws Exception {
+ final String bookname = "bookname";
+ final Spellbook spellbook = mock(Spellbook.class);
+ final Set wizards = new HashSet<>();
+ wizards.add(mock(Wizard.class));
+ wizards.add(mock(Wizard.class));
+ wizards.add(mock(Wizard.class));
+
+ when(spellbook.getWizards()).thenReturn(wizards);
+
+ final SpellbookDao spellbookDao = mock(SpellbookDao.class);
+ when(spellbookDao.findByName(eq(bookname))).thenReturn(spellbook);
+
+ final WizardDao wizardDao = mock(WizardDao.class);
+ final SpellDao spellDao = mock(SpellDao.class);
+
+
+ final MagicServiceImpl service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
+ verifyZeroInteractions(wizardDao, spellbookDao, spellDao, spellbook);
+
+ final List result = service.findWizardsWithSpellbook(bookname);
+ verify(spellbookDao).findByName(eq(bookname));
+ verify(spellbook).getWizards();
+
+ assertNotNull(result);
+ assertEquals(3, result.size());
+
+ verifyNoMoreInteractions(wizardDao, spellbookDao, spellDao);
+ }
+
+ @Test
+ public void testFindWizardsWithSpell() throws Exception {
+ final Set wizards = new HashSet<>();
+ wizards.add(mock(Wizard.class));
+ wizards.add(mock(Wizard.class));
+ wizards.add(mock(Wizard.class));
+
+ final Spellbook spellbook = mock(Spellbook.class);
+ when(spellbook.getWizards()).thenReturn(wizards);
+
+ final SpellbookDao spellbookDao = mock(SpellbookDao.class);
+ final WizardDao wizardDao = mock(WizardDao.class);
+
+ final Spell spell = mock(Spell.class);
+ when(spell.getSpellbook()).thenReturn(spellbook);
+
+ final String spellName = "spellname";
+ final SpellDao spellDao = mock(SpellDao.class);
+ when(spellDao.findByName(eq(spellName))).thenReturn(spell);
+
+ final MagicServiceImpl service = new MagicServiceImpl(wizardDao, spellbookDao, spellDao);
+ verifyZeroInteractions(wizardDao, spellbookDao, spellDao, spellbook);
+
+ final List result = service.findWizardsWithSpell(spellName);
+ verify(spellDao).findByName(eq(spellName));
+ verify(spellbook).getWizards();
+
+ assertNotNull(result);
+ assertEquals(3, result.size());
+
+ verifyNoMoreInteractions(wizardDao, spellbookDao, spellDao);
+ }
+
+}
diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/spell/SpellDaoImplTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/spell/SpellDaoImplTest.java
new file mode 100644
index 000000000..99a8e142f
--- /dev/null
+++ b/service-layer/src/test/java/com/iluwatar/servicelayer/spell/SpellDaoImplTest.java
@@ -0,0 +1,35 @@
+package com.iluwatar.servicelayer.spell;
+
+import com.iluwatar.servicelayer.common.BaseDaoTest;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/28/15 - 11:02 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SpellDaoImplTest extends BaseDaoTest {
+
+ public SpellDaoImplTest() {
+ super(Spell::new, new SpellDaoImpl());
+ }
+
+ @Test
+ public void testFindByName() throws Exception {
+ final SpellDaoImpl dao = getDao();
+ final List allSpells = dao.findAll();
+ for (final Spell spell : allSpells) {
+ final Spell spellByName = dao.findByName(spell.getName());
+ assertNotNull(spellByName);
+ assertEquals(spell.getId(), spellByName.getId());
+ assertEquals(spell.getName(), spellByName.getName());
+ }
+ }
+
+}
diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImplTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImplTest.java
new file mode 100644
index 000000000..fda46009e
--- /dev/null
+++ b/service-layer/src/test/java/com/iluwatar/servicelayer/spellbook/SpellbookDaoImplTest.java
@@ -0,0 +1,35 @@
+package com.iluwatar.servicelayer.spellbook;
+
+import com.iluwatar.servicelayer.common.BaseDaoTest;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/28/15 - 11:44 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SpellbookDaoImplTest extends BaseDaoTest {
+
+ public SpellbookDaoImplTest() {
+ super(Spellbook::new, new SpellbookDaoImpl());
+ }
+
+ @Test
+ public void testFindByName() throws Exception {
+ final SpellbookDaoImpl dao = getDao();
+ final List allBooks = dao.findAll();
+ for (final Spellbook book : allBooks) {
+ final Spellbook spellByName = dao.findByName(book.getName());
+ assertNotNull(spellByName);
+ assertEquals(book.getId(), spellByName.getId());
+ assertEquals(book.getName(), spellByName.getName());
+ }
+ }
+
+}
diff --git a/service-layer/src/test/java/com/iluwatar/servicelayer/wizard/WizardDaoImplTest.java b/service-layer/src/test/java/com/iluwatar/servicelayer/wizard/WizardDaoImplTest.java
new file mode 100644
index 000000000..1812f4c36
--- /dev/null
+++ b/service-layer/src/test/java/com/iluwatar/servicelayer/wizard/WizardDaoImplTest.java
@@ -0,0 +1,35 @@
+package com.iluwatar.servicelayer.wizard;
+
+import com.iluwatar.servicelayer.common.BaseDaoTest;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/28/15 - 11:46 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class WizardDaoImplTest extends BaseDaoTest {
+
+ public WizardDaoImplTest() {
+ super(Wizard::new, new WizardDaoImpl());
+ }
+
+ @Test
+ public void testFindByName() throws Exception {
+ final WizardDaoImpl dao = getDao();
+ final List allWizards = dao.findAll();
+ for (final Wizard spell : allWizards) {
+ final Wizard byName = dao.findByName(spell.getName());
+ assertNotNull(byName);
+ assertEquals(spell.getId(), byName.getId());
+ assertEquals(spell.getName(), byName.getName());
+ }
+ }
+
+}
diff --git a/service-locator/index.md b/service-locator/index.md
index 03c432749..af4d8c3ac 100644
--- a/service-locator/index.md
+++ b/service-locator/index.md
@@ -4,15 +4,20 @@ title: Service Locator
folder: service-locator
permalink: /patterns/service-locator/
categories: Structural
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
+ - Performance
---
-**Intent:** Encapsulate the processes involved in obtaining a service with a
+## Intent
+Encapsulate the processes involved in obtaining a service with a
strong abstraction layer.

-**Applicability:** The service locator pattern is applicable whenever we want
+## Applicability
+The service locator pattern is applicable whenever we want
to locate/fetch various services using JNDI which, typically, is a redundant
and expensive lookup. The service Locator pattern addresses this expensive
lookup by making use of caching techniques ie. for the very first time a
@@ -21,12 +26,12 @@ the relevant service and then finally caches this service object. Now, further
lookups of the same service via Service Locator is done in its cache which
improves the performance of application to great extent.
-**Typical Use Case:**
+## Typical Use Case
* when network hits are expensive and time consuming
* lookups of services are done quite frequently
* large number of services are being used
-**Credits:**
+## Credits
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
diff --git a/service-locator/pom.xml b/service-locator/pom.xml
index 5ccef1fe2..09acb03b8 100644
--- a/service-locator/pom.xml
+++ b/service-locator/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTservice-locator
diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java
index f2d338cdc..f2dd31221 100644
--- a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java
+++ b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceImpl.java
@@ -12,6 +12,9 @@ public class ServiceImpl implements Service {
private final String serviceName;
private final int id;
+ /**
+ * Constructor
+ */
public ServiceImpl(String serviceName) {
// set the service name
this.serviceName = serviceName;
diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java
index 6df74f84e..6ec51b989 100644
--- a/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java
+++ b/service-locator/src/main/java/com/iluwatar/servicelocator/ServiceLocator.java
@@ -10,6 +10,9 @@ public class ServiceLocator {
private static ServiceCache serviceCache = new ServiceCache();
+ private ServiceLocator() {
+ }
+
/**
* Fetch the service with the name param from the cache first, if no service is found, lookup the
* service from the {@link InitContext} and then add the newly created service into the cache map
@@ -29,7 +32,9 @@ public class ServiceLocator {
*/
InitContext ctx = new InitContext();
serviceObj = (Service) ctx.lookup(serviceJndiName);
- serviceCache.addService(serviceObj);
+ if (serviceObj != null) { // Only cache a service if it actually exists
+ serviceCache.addService(serviceObj);
+ }
return serviceObj;
}
}
diff --git a/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java b/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java
index ab1549182..0ed27656c 100644
--- a/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java
+++ b/service-locator/src/test/java/com/iluwatar/servicelocator/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.servicelocator;
import org.junit.Test;
-import com.iluwatar.servicelocator.App;
-
/**
*
* Application test
diff --git a/service-locator/src/test/java/com/iluwatar/servicelocator/ServiceLocatorTest.java b/service-locator/src/test/java/com/iluwatar/servicelocator/ServiceLocatorTest.java
new file mode 100644
index 000000000..ce54e054f
--- /dev/null
+++ b/service-locator/src/test/java/com/iluwatar/servicelocator/ServiceLocatorTest.java
@@ -0,0 +1,46 @@
+package com.iluwatar.servicelocator;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/29/15 - 19:07 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ServiceLocatorTest {
+
+ /**
+ * Verify if we just receive 'null' when requesting a non-existing service
+ */
+ @Test
+ public void testGetNonExistentService() {
+ assertNull(ServiceLocator.getService("fantastic/unicorn/service"));
+ assertNull(ServiceLocator.getService("another/fantastic/unicorn/service"));
+ }
+
+ /**
+ * Verify if we get the same cached instance when requesting the same service twice
+ */
+ @Test
+ public void testServiceCache() {
+ final String[] serviceNames = new String[]{
+ "jndi/serviceA", "jndi/serviceB"
+ };
+
+ for (final String serviceName : serviceNames) {
+ final Service service = ServiceLocator.getService(serviceName);
+ assertNotNull(service);
+ assertEquals(serviceName, service.getName());
+ assertTrue(service.getId() > 0); // The id is generated randomly, but the minimum value is '1'
+ assertSame(service, ServiceLocator.getService(serviceName));
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/singleton/index.md b/singleton/index.md
index 18c137448..dcbd63902 100644
--- a/singleton/index.md
+++ b/singleton/index.md
@@ -10,26 +10,28 @@ tags:
- Difficulty-Beginner
---
-**Intent:** Ensure a class only has one instance, and provide a global point of
+## Intent
+Ensure a class only has one instance, and provide a global point of
access to it.

-**Applicability:** Use the Singleton pattern when
+## Applicability
+Use the Singleton pattern when
* there must be exactly one instance of a class, and it must be accessible to clients from a well-known access point
* when the sole instance should be extensible by subclassing, and clients should be able to use an extended instance without modifying their code
-**Typical Use Case:**
+## Typical Use Case
* the logging class
* managing a connection to a database
* file manager
-**Real world examples:**
+## Real world examples
* [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/singleton/pom.xml b/singleton/pom.xml
index 36d326504..e08ffec86 100644
--- a/singleton/pom.xml
+++ b/singleton/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTsingleton
diff --git a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java
index 585b11e61..f8b7e170f 100644
--- a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java
+++ b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java
@@ -8,7 +8,7 @@ public final class IvoryTower {
/**
* Static to class instance of the class.
*/
- private static final IvoryTower instance = new IvoryTower();
+ private static final IvoryTower INSTANCE = new IvoryTower();
/**
* Private constructor so nobody can instantiate the class.
@@ -21,6 +21,6 @@ public final class IvoryTower {
* @return instance of the singleton.
*/
public static IvoryTower getInstance() {
- return instance;
+ return INSTANCE;
}
}
diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java
index 1aca15b30..ab39a652d 100644
--- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java
+++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java
@@ -11,14 +11,14 @@ package com.iluwatar.singleton;
*/
public class ThreadSafeDoubleCheckLocking {
- private static volatile ThreadSafeDoubleCheckLocking INSTANCE;
+ private static volatile ThreadSafeDoubleCheckLocking instance;
/**
* private constructor to prevent client from instantiating.
*/
private ThreadSafeDoubleCheckLocking() {
// to prevent instantiating by Reflection call
- if (INSTANCE != null) {
+ if (instance != null) {
throw new IllegalStateException("Already initialized.");
}
}
@@ -31,12 +31,12 @@ public class ThreadSafeDoubleCheckLocking {
public static ThreadSafeDoubleCheckLocking getInstance() {
// local variable increases performance by 25 percent
// Joshua Bloch "Effective Java, Second Edition", p. 283-284
- ThreadSafeDoubleCheckLocking result = INSTANCE;
+ ThreadSafeDoubleCheckLocking result = instance;
if (result == null) {
synchronized (ThreadSafeDoubleCheckLocking.class) {
- result = INSTANCE;
+ result = instance;
if (result == null) {
- INSTANCE = result = new ThreadSafeDoubleCheckLocking();
+ instance = result = new ThreadSafeDoubleCheckLocking();
}
}
}
diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java
index 98281b4c8..e67922016 100644
--- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java
+++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java
@@ -16,7 +16,7 @@ public class ThreadSafeLazyLoadedIvoryTower {
/**
* The instance gets created only when it is called for first time. Lazy-loading
*/
- public synchronized static ThreadSafeLazyLoadedIvoryTower getInstance() {
+ public static synchronized ThreadSafeLazyLoadedIvoryTower getInstance() {
if (instance == null) {
instance = new ThreadSafeLazyLoadedIvoryTower();
diff --git a/singleton/src/test/java/com/iluwatar/singleton/AppTest.java b/singleton/src/test/java/com/iluwatar/singleton/AppTest.java
index 4957eec6b..232de4e40 100644
--- a/singleton/src/test/java/com/iluwatar/singleton/AppTest.java
+++ b/singleton/src/test/java/com/iluwatar/singleton/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.singleton;
import org.junit.Test;
-import com.iluwatar.singleton.App;
-
/**
*
* Application test
diff --git a/singleton/src/test/java/com/iluwatar/singleton/EnumIvoryTowerTest.java b/singleton/src/test/java/com/iluwatar/singleton/EnumIvoryTowerTest.java
new file mode 100644
index 000000000..49c65c716
--- /dev/null
+++ b/singleton/src/test/java/com/iluwatar/singleton/EnumIvoryTowerTest.java
@@ -0,0 +1,17 @@
+package com.iluwatar.singleton;
+
+/**
+ * Date: 12/29/15 - 19:20 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class EnumIvoryTowerTest extends SingletonTest {
+
+ /**
+ * Create a new singleton test instance using the given 'getInstance' method
+ */
+ public EnumIvoryTowerTest() {
+ super(() -> EnumIvoryTower.INSTANCE);
+ }
+
+}
diff --git a/singleton/src/test/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiomTest.java b/singleton/src/test/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiomTest.java
new file mode 100644
index 000000000..60ae4798d
--- /dev/null
+++ b/singleton/src/test/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiomTest.java
@@ -0,0 +1,17 @@
+package com.iluwatar.singleton;
+
+/**
+ * Date: 12/29/15 - 19:22 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class InitializingOnDemandHolderIdiomTest extends SingletonTest {
+
+ /**
+ * Create a new singleton test instance using the given 'getInstance' method
+ */
+ public InitializingOnDemandHolderIdiomTest() {
+ super(InitializingOnDemandHolderIdiom::getInstance);
+ }
+
+}
\ No newline at end of file
diff --git a/singleton/src/test/java/com/iluwatar/singleton/IvoryTowerTest.java b/singleton/src/test/java/com/iluwatar/singleton/IvoryTowerTest.java
new file mode 100644
index 000000000..e9a222aef
--- /dev/null
+++ b/singleton/src/test/java/com/iluwatar/singleton/IvoryTowerTest.java
@@ -0,0 +1,17 @@
+package com.iluwatar.singleton;
+
+/**
+ * Date: 12/29/15 - 19:23 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class IvoryTowerTest extends SingletonTest {
+
+ /**
+ * Create a new singleton test instance using the given 'getInstance' method
+ */
+ public IvoryTowerTest() {
+ super(IvoryTower::getInstance);
+ }
+
+}
\ No newline at end of file
diff --git a/singleton/src/test/java/com/iluwatar/singleton/LazyLoadedSingletonThreadSafetyTest.java b/singleton/src/test/java/com/iluwatar/singleton/LazyLoadedSingletonThreadSafetyTest.java
deleted file mode 100644
index 3afc1bf14..000000000
--- a/singleton/src/test/java/com/iluwatar/singleton/LazyLoadedSingletonThreadSafetyTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package com.iluwatar.singleton;
-
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.*;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * This class provides several test case that test singleton construction.
- *
- * The first proves that multiple calls to the singleton getInstance object are the same when called
- * in the SAME thread. The second proves that multiple calls to the singleton getInstance object are
- * the same when called in the DIFFERENT thread.
- *
- */
-public class LazyLoadedSingletonThreadSafetyTest {
-
- private static final int NUM_THREADS = 5;
- private List threadObjects = Collections
- .synchronizedList(new ArrayList<>());
-
- // NullObject class so Callable has to return something
- private class NullObject {
- private NullObject() {}
- }
-
- @Test
- public void test_MultipleCallsReturnTheSameObjectInSameThread() {
- // Create several instances in the same calling thread
- ThreadSafeLazyLoadedIvoryTower instance1 = ThreadSafeLazyLoadedIvoryTower.getInstance();
- ThreadSafeLazyLoadedIvoryTower instance2 = ThreadSafeLazyLoadedIvoryTower.getInstance();
- ThreadSafeLazyLoadedIvoryTower instance3 = ThreadSafeLazyLoadedIvoryTower.getInstance();
- // now check they are equal
- assertEquals(instance1, instance1);
- assertEquals(instance1, instance2);
- assertEquals(instance2, instance3);
- assertEquals(instance1, instance3);
- }
-
- @Test
- public void test_MultipleCallsReturnTheSameObjectInDifferentThreads()
- throws InterruptedException, ExecutionException {
- {// create several threads and inside each callable instantiate the singleton class
- ExecutorService executorService = Executors.newSingleThreadExecutor();
-
- List> threadList = new ArrayList<>();
- for (int i = 0; i < NUM_THREADS; i++) {
- threadList.add(new SingletonCreatingThread());
- }
-
- ExecutorService service = Executors.newCachedThreadPool();
- List> results = service.invokeAll(threadList);
-
- // wait for all of the threads to complete
- for (Future res : results) {
- res.get();
- }
-
- // tidy up the executor
- executorService.shutdown();
- }
- {// now check the contents that were added to threadObjects by each thread
- assertEquals(NUM_THREADS, threadObjects.size());
- assertEquals(threadObjects.get(0), threadObjects.get(1));
- assertEquals(threadObjects.get(1), threadObjects.get(2));
- assertEquals(threadObjects.get(2), threadObjects.get(3));
- assertEquals(threadObjects.get(3), threadObjects.get(4));
- }
- }
-
- private class SingletonCreatingThread implements Callable {
- @Override
- public NullObject call() {
- // instantiate the thread safety class and add to list to test afterwards
- ThreadSafeLazyLoadedIvoryTower instance = ThreadSafeLazyLoadedIvoryTower.getInstance();
- threadObjects.add(instance);
- return new NullObject();// return null object (cannot return Void)
- }
- }
-}
diff --git a/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java
new file mode 100644
index 000000000..6c6c4a3f4
--- /dev/null
+++ b/singleton/src/test/java/com/iluwatar/singleton/SingletonTest.java
@@ -0,0 +1,88 @@
+package com.iluwatar.singleton;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.function.Supplier;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+
+/**
+ * This class provides several test case that test singleton construction.
+ *
+ * The first proves that multiple calls to the singleton getInstance object are the same when called
+ * in the SAME thread. The second proves that multiple calls to the singleton getInstance object are
+ * the same when called in the DIFFERENT thread.
+ *
+ * Date: 12/29/15 - 19:25 PM
+ *
+ * @author Jeroen Meulemeester
+ * @author Richard Jones
+ */
+public abstract class SingletonTest {
+
+ /**
+ * The singleton's getInstance method
+ */
+ private final Supplier singletonInstanceMethod;
+
+ /**
+ * Create a new singleton test instance using the given 'getInstance' method
+ *
+ * @param singletonInstanceMethod The singleton's getInstance method
+ */
+ public SingletonTest(final Supplier singletonInstanceMethod) {
+ this.singletonInstanceMethod = singletonInstanceMethod;
+ }
+
+ /**
+ * Test the singleton in a non-concurrent setting
+ */
+ @Test
+ public void testMultipleCallsReturnTheSameObjectInSameThread() {
+ // Create several instances in the same calling thread
+ S instance1 = this.singletonInstanceMethod.get();
+ S instance2 = this.singletonInstanceMethod.get();
+ S instance3 = this.singletonInstanceMethod.get();
+ // now check they are equal
+ assertSame(instance1, instance2);
+ assertSame(instance1, instance3);
+ assertSame(instance2, instance3);
+ }
+
+ /**
+ * Test singleton instance in a concurrent setting
+ */
+ @Test(timeout = 10000)
+ public void testMultipleCallsReturnTheSameObjectInDifferentThreads() throws Exception {
+
+ // Create 10000 tasks and inside each callable instantiate the singleton class
+ final List> tasks = new ArrayList<>();
+ for (int i = 0; i < 10000; i++) {
+ tasks.add(this.singletonInstanceMethod::get);
+ }
+
+ // Use up to 8 concurrent threads to handle the tasks
+ final ExecutorService executorService = Executors.newFixedThreadPool(8);
+ final List> results = executorService.invokeAll(tasks);
+
+ // wait for all of the threads to complete
+ final S expectedInstance = this.singletonInstanceMethod.get();
+ for (Future res : results) {
+ final S instance = res.get();
+ assertNotNull(instance);
+ assertSame(expectedInstance, instance);
+ }
+
+ // tidy up the executor
+ executorService.shutdown();
+
+ }
+
+}
diff --git a/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLockingTest.java b/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLockingTest.java
new file mode 100644
index 000000000..f40f0cbc7
--- /dev/null
+++ b/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLockingTest.java
@@ -0,0 +1,17 @@
+package com.iluwatar.singleton;
+
+/**
+ * Date: 12/29/15 - 19:26 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ThreadSafeDoubleCheckLockingTest extends SingletonTest {
+
+ /**
+ * Create a new singleton test instance using the given 'getInstance' method
+ */
+ public ThreadSafeDoubleCheckLockingTest() {
+ super(ThreadSafeDoubleCheckLocking::getInstance);
+ }
+
+}
\ No newline at end of file
diff --git a/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTowerTest.java b/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTowerTest.java
new file mode 100644
index 000000000..8f2a5e6e1
--- /dev/null
+++ b/singleton/src/test/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTowerTest.java
@@ -0,0 +1,17 @@
+package com.iluwatar.singleton;
+
+/**
+ * Date: 12/29/15 - 19:26 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ThreadSafeLazyLoadedIvoryTowerTest extends SingletonTest {
+
+ /**
+ * Create a new singleton test instance using the given 'getInstance' method
+ */
+ public ThreadSafeLazyLoadedIvoryTowerTest() {
+ super(ThreadSafeLazyLoadedIvoryTower::getInstance);
+ }
+
+}
diff --git a/specification/index.md b/specification/index.md
index 6b76d5102..df6a4c3eb 100644
--- a/specification/index.md
+++ b/specification/index.md
@@ -4,21 +4,25 @@ title: Specification
folder: specification
permalink: /patterns/specification/
categories: Behavioral
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** Specification pattern separates the statement of how to match a
+## Intent
+Specification pattern separates the statement of how to match a
candidate, from the candidate object that it is matched against. As well as its
usefulness in selection, it is also valuable for validation and for building to
order

-**Applicability:** Use the Specification pattern when
+## Applicability
+Use the Specification pattern when
* you need to select a subset of objects based on some criteria, and to refresh the selection at various times
* you need to check that only suitable objects are used for a certain role (validation)
-**Credits:**
+## Credits
* [Martin Fowler - Specifications](http://martinfowler.com/apsupp/spec.pdf)
diff --git a/specification/pom.xml b/specification/pom.xml
index 8c79fa9e6..64caa16b0 100644
--- a/specification/pom.xml
+++ b/specification/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTspecification
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/specification/src/main/java/com/iluwatar/specification/app/App.java b/specification/src/main/java/com/iluwatar/specification/app/App.java
index d755d6c2e..373a24f92 100644
--- a/specification/src/main/java/com/iluwatar/specification/app/App.java
+++ b/specification/src/main/java/com/iluwatar/specification/app/App.java
@@ -31,6 +31,9 @@ import com.iluwatar.specification.selector.MovementSelector;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) {
// initialize creatures list
List creatures =
diff --git a/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java b/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java
index 2ec3ccf55..f02befb73 100644
--- a/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java
+++ b/specification/src/main/java/com/iluwatar/specification/creature/AbstractCreature.java
@@ -16,6 +16,9 @@ public abstract class AbstractCreature implements Creature {
private Movement movement;
private Color color;
+ /**
+ * Constructor
+ */
public AbstractCreature(String name, Size size, Movement movement, Color color) {
this.name = name;
this.size = size;
diff --git a/specification/src/test/java/com/iluwatar/specification/app/AppTest.java b/specification/src/test/java/com/iluwatar/specification/app/AppTest.java
index fe613eab7..b1bf00c24 100644
--- a/specification/src/test/java/com/iluwatar/specification/app/AppTest.java
+++ b/specification/src/test/java/com/iluwatar/specification/app/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.specification.app;
import org.junit.Test;
-import com.iluwatar.specification.app.App;
-
/**
*
* Application test
diff --git a/specification/src/test/java/com/iluwatar/specification/creature/CreatureTest.java b/specification/src/test/java/com/iluwatar/specification/creature/CreatureTest.java
new file mode 100644
index 000000000..0548788a4
--- /dev/null
+++ b/specification/src/test/java/com/iluwatar/specification/creature/CreatureTest.java
@@ -0,0 +1,111 @@
+package com.iluwatar.specification.creature;
+
+import com.iluwatar.specification.property.Color;
+import com.iluwatar.specification.property.Movement;
+import com.iluwatar.specification.property.Size;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/29/15 - 7:47 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+@RunWith(Parameterized.class)
+public class CreatureTest {
+
+ /**
+ * @return The tested {@link Creature} instance and its expected specs
+ */
+ @Parameterized.Parameters
+ public static Collection data() {
+ return Arrays.asList(
+ new Object[]{new Dragon(), "Dragon", Size.LARGE, Movement.FLYING, Color.RED},
+ new Object[]{new Goblin(), "Goblin", Size.SMALL, Movement.WALKING, Color.GREEN},
+ new Object[]{new KillerBee(), "KillerBee", Size.SMALL, Movement.FLYING, Color.LIGHT},
+ new Object[]{new Octopus(), "Octopus", Size.NORMAL, Movement.SWIMMING, Color.DARK},
+ new Object[]{new Shark(), "Shark", Size.NORMAL, Movement.SWIMMING, Color.LIGHT},
+ new Object[]{new Troll(), "Troll", Size.LARGE, Movement.WALKING, Color.DARK}
+ );
+ }
+
+ /**
+ * The tested creature
+ */
+ private final Creature testedCreature;
+
+ /**
+ * The expected name of the tested creature
+ */
+ private final String name;
+
+ /**
+ * The expected size of the tested creature
+ */
+ private final Size size;
+
+ /**
+ * The expected movement type of the tested creature
+ */
+ private final Movement movement;
+
+ /**
+ * The expected color of the tested creature
+ */
+ private final Color color;
+
+ /**
+ * @param testedCreature The tested creature
+ * @param name The expected name of the creature
+ * @param size The expected size of the creature
+ * @param movement The expected movement type of the creature
+ * @param color The expected color of the creature
+ */
+ public CreatureTest(final Creature testedCreature, final String name, final Size size,
+ final Movement movement, final Color color) {
+ this.testedCreature = testedCreature;
+ this.name = name;
+ this.size = size;
+ this.movement = movement;
+ this.color = color;
+ }
+
+
+ @Test
+ public void testGetName() throws Exception {
+ assertEquals(this.name, this.testedCreature.getName());
+ }
+
+ @Test
+ public void testGetSize() throws Exception {
+ assertEquals(this.size, this.testedCreature.getSize());
+ }
+
+ @Test
+ public void testGetMovement() throws Exception {
+ assertEquals(this.movement, this.testedCreature.getMovement());
+ }
+
+ @Test
+ public void testGetColor() throws Exception {
+ assertEquals(this.color, this.testedCreature.getColor());
+ }
+
+ @Test
+ public void testToString() throws Exception {
+ final String toString = this.testedCreature.toString();
+ assertNotNull(toString);
+ assertEquals(
+ String.format("%s [size=%s, movement=%s, color=%s]", name, size, movement, color),
+ toString
+ );
+ }
+}
\ No newline at end of file
diff --git a/specification/src/test/java/com/iluwatar/specification/selector/ColorSelectorTest.java b/specification/src/test/java/com/iluwatar/specification/selector/ColorSelectorTest.java
new file mode 100644
index 000000000..894f6c58e
--- /dev/null
+++ b/specification/src/test/java/com/iluwatar/specification/selector/ColorSelectorTest.java
@@ -0,0 +1,37 @@
+package com.iluwatar.specification.selector;
+
+import com.iluwatar.specification.creature.Creature;
+import com.iluwatar.specification.property.Color;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Date: 12/29/15 - 7:35 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class ColorSelectorTest {
+
+ /**
+ * Verify if the color selector gives the correct results
+ */
+ @Test
+ public void testColor() {
+ final Creature greenCreature = mock(Creature.class);
+ when(greenCreature.getColor()).thenReturn(Color.GREEN);
+
+ final Creature redCreature = mock(Creature.class);
+ when(redCreature.getColor()).thenReturn(Color.RED);
+
+ final ColorSelector greenSelector = new ColorSelector(Color.GREEN);
+ assertTrue(greenSelector.test(greenCreature));
+ assertFalse(greenSelector.test(redCreature));
+
+ }
+
+}
\ No newline at end of file
diff --git a/specification/src/test/java/com/iluwatar/specification/selector/MovementSelectorTest.java b/specification/src/test/java/com/iluwatar/specification/selector/MovementSelectorTest.java
new file mode 100644
index 000000000..c2a251b5a
--- /dev/null
+++ b/specification/src/test/java/com/iluwatar/specification/selector/MovementSelectorTest.java
@@ -0,0 +1,38 @@
+package com.iluwatar.specification.selector;
+
+import com.iluwatar.specification.creature.Creature;
+import com.iluwatar.specification.property.Color;
+import com.iluwatar.specification.property.Movement;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Date: 12/29/15 - 7:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class MovementSelectorTest {
+
+ /**
+ * Verify if the movement selector gives the correct results
+ */
+ @Test
+ public void testMovement() {
+ final Creature swimmingCreature = mock(Creature.class);
+ when(swimmingCreature.getMovement()).thenReturn(Movement.SWIMMING);
+
+ final Creature flyingCreature = mock(Creature.class);
+ when(flyingCreature.getMovement()).thenReturn(Movement.FLYING);
+
+ final MovementSelector swimmingSelector = new MovementSelector(Movement.SWIMMING);
+ assertTrue(swimmingSelector.test(swimmingCreature));
+ assertFalse(swimmingSelector.test(flyingCreature));
+
+ }
+
+}
\ No newline at end of file
diff --git a/specification/src/test/java/com/iluwatar/specification/selector/SizeSelectorTest.java b/specification/src/test/java/com/iluwatar/specification/selector/SizeSelectorTest.java
new file mode 100644
index 000000000..d2a534c18
--- /dev/null
+++ b/specification/src/test/java/com/iluwatar/specification/selector/SizeSelectorTest.java
@@ -0,0 +1,36 @@
+package com.iluwatar.specification.selector;
+
+import com.iluwatar.specification.creature.Creature;
+import com.iluwatar.specification.property.Size;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Date: 12/29/15 - 7:43 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SizeSelectorTest {
+
+ /**
+ * Verify if the size selector gives the correct results
+ */
+ @Test
+ public void testMovement() {
+ final Creature normalCreature = mock(Creature.class);
+ when(normalCreature.getSize()).thenReturn(Size.NORMAL);
+
+ final Creature smallCreature = mock(Creature.class);
+ when(smallCreature.getSize()).thenReturn(Size.SMALL);
+
+ final SizeSelector normalSelector = new SizeSelector(Size.NORMAL);
+ assertTrue(normalSelector.test(normalCreature));
+ assertFalse(normalSelector.test(smallCreature));
+ }
+
+}
diff --git a/state/index.md b/state/index.md
index 3beeb480a..f5cb189fd 100644
--- a/state/index.md
+++ b/state/index.md
@@ -10,18 +10,21 @@ tags:
- Gang Of Four
---
-**Also known as:** Objects for States
+## Also known as
+Objects for States
-**Intent:** Allow an object to alter its behavior when its internal state
+## Intent
+Allow an object to alter its behavior when its internal state
changes. The object will appear to change its class.

-**Applicability:** Use the State pattern in either of the following cases
+## Applicability
+Use the State pattern in either of the following cases
* an object's behavior depends on its state, and it must change its behavior at run-time depending on that state
* operations have large, multipart conditional statements that depend on the object's state. This state is usually represented by one or more enumerated constants. Often, several operations will contain this same conditional structure. The State pattern puts each branch of the conditional in a separate class. This lets you treat the object's state as an object in its own right that can vary independently from other objects.
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/state/pom.xml b/state/pom.xml
index 8aa1ae812..4c0dbe8d3 100644
--- a/state/pom.xml
+++ b/state/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTstate
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/state/src/main/java/com/iluwatar/state/App.java b/state/src/main/java/com/iluwatar/state/App.java
index 2013466e0..63b59ad59 100644
--- a/state/src/main/java/com/iluwatar/state/App.java
+++ b/state/src/main/java/com/iluwatar/state/App.java
@@ -13,6 +13,9 @@ package com.iluwatar.state;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) {
Mammoth mammoth = new Mammoth();
diff --git a/state/src/main/java/com/iluwatar/state/Mammoth.java b/state/src/main/java/com/iluwatar/state/Mammoth.java
index 8269ecb3d..92f4d7188 100644
--- a/state/src/main/java/com/iluwatar/state/Mammoth.java
+++ b/state/src/main/java/com/iluwatar/state/Mammoth.java
@@ -13,6 +13,9 @@ public class Mammoth {
state = new PeacefulState(this);
}
+ /**
+ * Makes time pass for the mammoth
+ */
public void timePasses() {
if (state.getClass().equals(PeacefulState.class)) {
changeStateTo(new AngryState(this));
diff --git a/state/src/test/java/com/iluwatar/state/AppTest.java b/state/src/test/java/com/iluwatar/state/AppTest.java
index 0961a1c26..d03592739 100644
--- a/state/src/test/java/com/iluwatar/state/AppTest.java
+++ b/state/src/test/java/com/iluwatar/state/AppTest.java
@@ -2,10 +2,8 @@ package com.iluwatar.state;
import org.junit.Test;
-import com.iluwatar.state.App;
-
/**
- *
+ *
* Application test
*
*/
diff --git a/state/src/test/java/com/iluwatar/state/MammothTest.java b/state/src/test/java/com/iluwatar/state/MammothTest.java
new file mode 100644
index 000000000..4f7224208
--- /dev/null
+++ b/state/src/test/java/com/iluwatar/state/MammothTest.java
@@ -0,0 +1,90 @@
+package com.iluwatar.state;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.mockito.Mockito;
+
+import java.io.PrintStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/29/15 - 8:27 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class MammothTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Switch to a complete mammoth 'mood'-cycle and verify if the observed mood matches the expected
+ * value.
+ */
+ @Test
+ public void testTimePasses() {
+ final InOrder inOrder = Mockito.inOrder(this.stdOutMock);
+ final Mammoth mammoth = new Mammoth();
+
+ mammoth.observe();
+ inOrder.verify(this.stdOutMock).println("The mammoth is calm and peaceful.");
+ inOrder.verifyNoMoreInteractions();
+
+ mammoth.timePasses();
+ inOrder.verify(this.stdOutMock).println("The mammoth gets angry!");
+ inOrder.verifyNoMoreInteractions();
+
+ mammoth.observe();
+ inOrder.verify(this.stdOutMock).println("The mammoth is furious!");
+ inOrder.verifyNoMoreInteractions();
+
+ mammoth.timePasses();
+ inOrder.verify(this.stdOutMock).println("The mammoth calms down.");
+ inOrder.verifyNoMoreInteractions();
+
+ mammoth.observe();
+ inOrder.verify(this.stdOutMock).println("The mammoth is calm and peaceful.");
+ inOrder.verifyNoMoreInteractions();
+
+ }
+
+ /**
+ * Verify if {@link Mammoth#toString()} gives the expected value
+ */
+ @Test
+ public void testToString() {
+ final String toString = new Mammoth().toString();
+ assertNotNull(toString);
+ assertEquals("The mammoth", toString);
+ }
+
+}
\ No newline at end of file
diff --git a/step-builder/index.md b/step-builder/index.md
index 766479358..bc636e37a 100644
--- a/step-builder/index.md
+++ b/step-builder/index.md
@@ -4,16 +4,20 @@ title: Step Builder
folder: step-builder
permalink: /patterns/step-builder/
categories: Creational
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** An extension of the Builder pattern that fully guides the user through the creation of the object with no chances of confusion.
+## Intent
+An extension of the Builder pattern that fully guides the user through the creation of the object with no chances of confusion.
The user experience will be much more improved by the fact that he will only see the next step methods available, NO build method until is the right time to build the object.

-**Applicability:** Use the Step Builder pattern when the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled the construction process must allow different representations for the object that's constructed when in the process of constructing the order is important.
+## Applicability
+Use the Step Builder pattern when the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled the construction process must allow different representations for the object that's constructed when in the process of constructing the order is important.
-**Credits:**
+## Credits
* [Marco Castigliego - Step Builder](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html)
diff --git a/step-builder/pom.xml b/step-builder/pom.xml
index a2a7462c8..a00d7e8d6 100644
--- a/step-builder/pom.xml
+++ b/step-builder/pom.xml
@@ -6,7 +6,7 @@
java-design-patternscom.iluwatar
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTstep-builder
diff --git a/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java b/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java
index 3bf7b9a68..a839cd49e 100644
--- a/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java
+++ b/step-builder/src/main/java/com/iluwatar/stepbuilder/App.java
@@ -11,7 +11,7 @@ package com.iluwatar.stepbuilder;
* methods available, NO build method until is the right time to build the object.
*
*
- * Implementation
+ * Implementation
*
* The concept is simple:
*
diff --git a/step-builder/src/test/java/com/iluwatar/stepbuilder/CharacterStepBuilderTest.java b/step-builder/src/test/java/com/iluwatar/stepbuilder/CharacterStepBuilderTest.java
new file mode 100644
index 000000000..b26635416
--- /dev/null
+++ b/step-builder/src/test/java/com/iluwatar/stepbuilder/CharacterStepBuilderTest.java
@@ -0,0 +1,155 @@
+package com.iluwatar.stepbuilder;
+
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Date: 12/29/15 - 9:21 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CharacterStepBuilderTest {
+
+ /**
+ * Build a new wizard {@link Character} and verify if it has the expected attributes
+ */
+ @Test
+ public void testBuildWizard() {
+ final Character character = CharacterStepBuilder.newBuilder()
+ .name("Merlin")
+ .wizardClass("alchemist")
+ .withSpell("poison")
+ .withAbility("invisibility")
+ .withAbility("wisdom")
+ .noMoreAbilities()
+ .build();
+
+ assertEquals("Merlin", character.getName());
+ assertEquals("alchemist", character.getWizardClass());
+ assertEquals("poison", character.getSpell());
+ assertNotNull(character.toString());
+
+ final List abilities = character.getAbilities();
+ assertNotNull(abilities);
+ assertEquals(2, abilities.size());
+ assertTrue(abilities.contains("invisibility"));
+ assertTrue(abilities.contains("wisdom"));
+
+ }
+
+ /**
+ * Build a new wizard {@link Character} without spell or abilities and verify if it has the
+ * expected attributes
+ */
+ @Test
+ public void testBuildPoorWizard() {
+ final Character character = CharacterStepBuilder.newBuilder()
+ .name("Merlin")
+ .wizardClass("alchemist")
+ .noSpell()
+ .build();
+
+ assertEquals("Merlin", character.getName());
+ assertEquals("alchemist", character.getWizardClass());
+ assertNull(character.getSpell());
+ assertNull(character.getAbilities());
+ assertNotNull(character.toString());
+
+ }
+
+ /**
+ * Build a new wizard {@link Character} and verify if it has the expected attributes
+ */
+ @Test
+ public void testBuildWeakWizard() {
+ final Character character = CharacterStepBuilder.newBuilder()
+ .name("Merlin")
+ .wizardClass("alchemist")
+ .withSpell("poison")
+ .noAbilities()
+ .build();
+
+ assertEquals("Merlin", character.getName());
+ assertEquals("alchemist", character.getWizardClass());
+ assertEquals("poison", character.getSpell());
+ assertNull(character.getAbilities());
+ assertNotNull(character.toString());
+
+ }
+
+
+ /**
+ * Build a new warrior {@link Character} and verify if it has the expected attributes
+ */
+ @Test
+ public void testBuildWarrior() {
+ final Character character = CharacterStepBuilder.newBuilder()
+ .name("Cuauhtemoc")
+ .fighterClass("aztec")
+ .withWeapon("spear")
+ .withAbility("speed")
+ .withAbility("strength")
+ .noMoreAbilities()
+ .build();
+
+ assertEquals("Cuauhtemoc", character.getName());
+ assertEquals("aztec", character.getFighterClass());
+ assertEquals("spear", character.getWeapon());
+ assertNotNull(character.toString());
+
+ final List abilities = character.getAbilities();
+ assertNotNull(abilities);
+ assertEquals(2, abilities.size());
+ assertTrue(abilities.contains("speed"));
+ assertTrue(abilities.contains("strength"));
+
+ }
+
+ /**
+ * Build a new wizard {@link Character} without weapon and abilities and verify if it has the
+ * expected attributes
+ */
+ @Test
+ public void testBuildPoorWarrior() {
+ final Character character = CharacterStepBuilder.newBuilder()
+ .name("Poor warrior")
+ .fighterClass("none")
+ .noWeapon()
+ .build();
+
+ assertEquals("Poor warrior", character.getName());
+ assertEquals("none", character.getFighterClass());
+ assertNull(character.getWeapon());
+ assertNull(character.getAbilities());
+ assertNotNull(character.toString());
+
+ }
+
+ /**
+ * Build a new warrior {@link Character} without any abilities, but with a weapon and verify if it
+ * has the expected attributes
+ */
+ @Test
+ public void testBuildWeakWarrior() {
+ final Character character = CharacterStepBuilder.newBuilder()
+ .name("Weak warrior")
+ .fighterClass("none")
+ .withWeapon("Slingshot")
+ .noAbilities()
+ .build();
+
+ assertEquals("Weak warrior", character.getName());
+ assertEquals("none", character.getFighterClass());
+ assertEquals("Slingshot", character.getWeapon());
+ assertNull(character.getAbilities());
+ assertNotNull(character.toString());
+
+ }
+
+}
\ No newline at end of file
diff --git a/strategy/index.md b/strategy/index.md
index 288276015..9b35b806d 100644
--- a/strategy/index.md
+++ b/strategy/index.md
@@ -10,21 +10,24 @@ tags:
- Gang Of Four
---
-**Also known as:** Policy
+## Also known as
+Policy
-**Intent:** Define a family of algorithms, encapsulate each one, and make them
+## Intent
+Define a family of algorithms, encapsulate each one, and make them
interchangeable. Strategy lets the algorithm vary independently from clients
that use it.

-**Applicability:** Use the Strategy pattern when
+## Applicability
+Use the Strategy pattern when
* many related classes differ only in their behavior. Strategies provide a way to configure a class either one of many behaviors
* you need different variants of an algorithm. for example, you might define algorithms reflecting different space/time trade-offs. Strategies can be used when these variants are implemented as a class hierarchy of algorithms
* an algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures
* a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/strategy/pom.xml b/strategy/pom.xml
index c1668277a..b194365f1 100644
--- a/strategy/pom.xml
+++ b/strategy/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTstrategy
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/strategy/src/test/java/com/iluwatar/strategy/AppTest.java b/strategy/src/test/java/com/iluwatar/strategy/AppTest.java
index d3c970b89..88ee28be4 100644
--- a/strategy/src/test/java/com/iluwatar/strategy/AppTest.java
+++ b/strategy/src/test/java/com/iluwatar/strategy/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.strategy;
import org.junit.Test;
-import com.iluwatar.strategy.App;
-
/**
*
* Application test
diff --git a/strategy/src/test/java/com/iluwatar/strategy/DragonSlayerTest.java b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayerTest.java
new file mode 100644
index 000000000..907d65ac4
--- /dev/null
+++ b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayerTest.java
@@ -0,0 +1,48 @@
+package com.iluwatar.strategy;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/29/15 - 10:50 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class DragonSlayerTest {
+
+ /**
+ * Verify if the dragon slayer uses the strategy during battle
+ */
+ @Test
+ public void testGoToBattle() {
+ final DragonSlayingStrategy strategy = mock(DragonSlayingStrategy.class);
+ final DragonSlayer dragonSlayer = new DragonSlayer(strategy);
+
+ dragonSlayer.goToBattle();
+ verify(strategy).execute();
+ verifyNoMoreInteractions(strategy);
+ }
+
+ /**
+ * Verify if the dragon slayer uses the new strategy during battle after a change of strategy
+ */
+ @Test
+ public void testChangeStrategy() throws Exception {
+ final DragonSlayingStrategy initialStrategy = mock(DragonSlayingStrategy.class);
+ final DragonSlayer dragonSlayer = new DragonSlayer(initialStrategy);
+
+ dragonSlayer.goToBattle();
+ verify(initialStrategy).execute();
+
+ final DragonSlayingStrategy newStrategy = mock(DragonSlayingStrategy.class);
+ dragonSlayer.changeStrategy(newStrategy);
+
+ dragonSlayer.goToBattle();
+ verify(newStrategy).execute();
+
+ verifyNoMoreInteractions(initialStrategy, newStrategy);
+ }
+}
\ No newline at end of file
diff --git a/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java
new file mode 100644
index 000000000..f9d18e22c
--- /dev/null
+++ b/strategy/src/test/java/com/iluwatar/strategy/DragonSlayingStrategyTest.java
@@ -0,0 +1,104 @@
+package com.iluwatar.strategy;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Collection;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/29/15 - 10:58 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+@RunWith(Parameterized.class)
+public class DragonSlayingStrategyTest {
+
+ /**
+ * @return The test parameters for each cycle
+ */
+ @Parameterized.Parameters
+ public static Collection data() {
+ return Arrays.asList(
+ new Object[]{
+ new MeleeStrategy(),
+ "With your Excalibur you severe the dragon's head!"
+ },
+ new Object[]{
+ new ProjectileStrategy(),
+ "You shoot the dragon with the magical crossbow and it falls dead on the ground!"
+ },
+ new Object[]{
+ new SpellStrategy(),
+ "You cast the spell of disintegration and the dragon vaporizes in a pile of dust!"
+ }
+ );
+ }
+
+ /**
+ * The tested strategy
+ */
+ private final DragonSlayingStrategy strategy;
+
+ /**
+ * The expected action on the std-out
+ */
+ private final String expectedResult;
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Create a new test instance for the given strategy
+ *
+ * @param strategy The tested strategy
+ * @param expectedResult The expected result
+ */
+ public DragonSlayingStrategyTest(final DragonSlayingStrategy strategy, final String expectedResult) {
+ this.strategy = strategy;
+ this.expectedResult = expectedResult;
+ }
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Test if executing the strategy gives the correct response
+ */
+ @Test
+ public void testExecute() {
+ this.strategy.execute();
+ verify(this.stdOutMock).println(this.expectedResult);
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+}
\ No newline at end of file
diff --git a/template-method/index.md b/template-method/index.md
index 8b8b7878e..ad972f06b 100644
--- a/template-method/index.md
+++ b/template-method/index.md
@@ -10,18 +10,20 @@ tags:
- Gang Of Four
---
-**Intent:** Define the skeleton of an algorithm in an operation, deferring some
+## Intent
+Define the skeleton of an algorithm in an operation, deferring some
steps to subclasses. Template method lets subclasses redefine certain steps of
an algorithm without changing the algorithm's structure.

-**Applicability:** The Template Method pattern should be used
+## Applicability
+The Template Method pattern should be used
* to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary
* when common behavior among subclasses should be factored and localized in a common class to avoid code duplication. This is good example of "refactoring to generalize" as described by Opdyke and Johnson. You first identify the differences in the existing code and then separate the differences into new operations. Finally, you replace the differing code with a template method that calls one of these new operations
* to control subclasses extensions. You can define a template method that calls "hook" operations at specific points, thereby permitting extensions only at those points
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/template-method/pom.xml b/template-method/pom.xml
index 482a7c5ca..ef2980203 100644
--- a/template-method/pom.xml
+++ b/template-method/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTtemplate-method
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java b/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java
index bad3d790f..096d51b4e 100644
--- a/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java
+++ b/template-method/src/main/java/com/iluwatar/templatemethod/StealingMethod.java
@@ -13,6 +13,9 @@ public abstract class StealingMethod {
protected abstract void stealTheItem(String target);
+ /**
+ * Steal
+ */
public void steal() {
String target = pickTarget();
System.out.println("The target has been chosen as " + target + ".");
diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java
index ddc46de5b..80e867327 100644
--- a/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java
+++ b/template-method/src/test/java/com/iluwatar/templatemethod/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.templatemethod;
import org.junit.Test;
-import com.iluwatar.templatemethod.App;
-
/**
*
* Application test
diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/HalflingThiefTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/HalflingThiefTest.java
new file mode 100644
index 000000000..be049720f
--- /dev/null
+++ b/template-method/src/test/java/com/iluwatar/templatemethod/HalflingThiefTest.java
@@ -0,0 +1,50 @@
+package com.iluwatar.templatemethod;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/29/15 - 18:15 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class HalflingThiefTest {
+
+ /**
+ * Verify if the thief uses the provided stealing method
+ */
+ @Test
+ public void testSteal() {
+ final StealingMethod method = mock(StealingMethod.class);
+ final HalflingThief thief = new HalflingThief(method);
+
+ thief.steal();
+ verify(method).steal();
+
+ verifyNoMoreInteractions(method);
+ }
+
+ /**
+ * Verify if the thief uses the provided stealing method, and the new method after changing it
+ */
+ @Test
+ public void testChangeMethod() {
+ final StealingMethod initialMethod = mock(StealingMethod.class);
+ final HalflingThief thief = new HalflingThief(initialMethod);
+
+ thief.steal();
+ verify(initialMethod).steal();
+
+ final StealingMethod newMethod = mock(StealingMethod.class);
+ thief.changeMethod(newMethod);
+
+ thief.steal();
+ verify(newMethod).steal();
+
+ verifyNoMoreInteractions(initialMethod, newMethod);
+
+ }
+}
\ No newline at end of file
diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/HitAndRunMethodTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/HitAndRunMethodTest.java
new file mode 100644
index 000000000..86fc2591d
--- /dev/null
+++ b/template-method/src/test/java/com/iluwatar/templatemethod/HitAndRunMethodTest.java
@@ -0,0 +1,23 @@
+package com.iluwatar.templatemethod;
+
+/**
+ * Date: 12/30/15 - 18:12 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class HitAndRunMethodTest extends StealingMethodTest {
+
+ /**
+ * Create a new test for the {@link HitAndRunMethod}
+ */
+ public HitAndRunMethodTest() {
+ super(
+ new HitAndRunMethod(),
+ "old goblin woman",
+ "The target has been chosen as old goblin woman.",
+ "Approach the old goblin woman from behind.",
+ "Grab the handbag and run away fast!"
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java
new file mode 100644
index 000000000..61143a15d
--- /dev/null
+++ b/template-method/src/test/java/com/iluwatar/templatemethod/StealingMethodTest.java
@@ -0,0 +1,142 @@
+package com.iluwatar.templatemethod;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import java.io.PrintStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+/**
+ * Date: 12/30/15 - 18:12 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StealingMethodTest {
+
+ /**
+ * The tested stealing method
+ */
+ private final M method;
+
+ /**
+ * The expected target
+ */
+ private final String expectedTarget;
+
+ /**
+ * The expected target picking result
+ */
+ private final String expectedTargetResult;
+
+ /**
+ * The expected confusion method
+ */
+ private final String expectedConfuseMethod;
+
+ /**
+ * The expected stealing method
+ */
+ private final String expectedStealMethod;
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Create a new test for the given stealing method, together with the expected results
+ *
+ * @param method The tested stealing method
+ * @param expectedTarget The expected target name
+ * @param expectedTargetResult The expected target picking result
+ * @param expectedConfuseMethod The expected confusion method
+ * @param expectedStealMethod The expected stealing method
+ */
+ public StealingMethodTest(final M method, String expectedTarget, final String expectedTargetResult,
+ final String expectedConfuseMethod, final String expectedStealMethod) {
+
+ this.method = method;
+ this.expectedTarget = expectedTarget;
+ this.expectedTargetResult = expectedTargetResult;
+ this.expectedConfuseMethod = expectedConfuseMethod;
+ this.expectedStealMethod = expectedStealMethod;
+ }
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Verify if the thief picks the correct target
+ */
+ @Test
+ public void testPickTarget() {
+ assertEquals(expectedTarget, this.method.pickTarget());
+ }
+
+ /**
+ * Verify if the target confusing step goes as planned
+ */
+ @Test
+ public void testConfuseTarget() {
+ verifyZeroInteractions(this.stdOutMock);
+
+ this.method.confuseTarget(this.expectedTarget);
+ verify(this.stdOutMock).println(this.expectedConfuseMethod);
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+ /**
+ * Verify if the stealing step goes as planned
+ */
+ @Test
+ public void testStealTheItem() {
+ verifyZeroInteractions(this.stdOutMock);
+
+ this.method.stealTheItem(this.expectedTarget);
+ verify(this.stdOutMock).println(this.expectedStealMethod);
+ verifyNoMoreInteractions(this.stdOutMock);
+ }
+
+ /**
+ * Verify if the complete steal process goes as planned
+ */
+ @Test
+ public void testSteal() {
+ final InOrder inOrder = inOrder(this.stdOutMock);
+
+ this.method.steal();
+
+ inOrder.verify(this.stdOutMock).println(this.expectedTargetResult);
+ inOrder.verify(this.stdOutMock).println(this.expectedConfuseMethod);
+ inOrder.verify(this.stdOutMock).println(this.expectedStealMethod);
+ inOrder.verifyNoMoreInteractions();
+ }
+
+}
\ No newline at end of file
diff --git a/template-method/src/test/java/com/iluwatar/templatemethod/SubtleMethodTest.java b/template-method/src/test/java/com/iluwatar/templatemethod/SubtleMethodTest.java
new file mode 100644
index 000000000..8b3681a76
--- /dev/null
+++ b/template-method/src/test/java/com/iluwatar/templatemethod/SubtleMethodTest.java
@@ -0,0 +1,23 @@
+package com.iluwatar.templatemethod;
+
+/**
+ * Date: 12/30/15 - 18:19 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SubtleMethodTest extends StealingMethodTest {
+
+ /**
+ * Create a new test for the {@link SubtleMethod}
+ */
+ public SubtleMethodTest() {
+ super(
+ new SubtleMethod(),
+ "shop keeper",
+ "The target has been chosen as shop keeper.",
+ "Approach the shop keeper with tears running and hug him!",
+ "While in close contact grab the shop keeper's wallet."
+ );
+ }
+
+}
\ No newline at end of file
diff --git a/thread-pool/index.md b/thread-pool/index.md
index d9f00f428..9806fa8e0 100644
--- a/thread-pool/index.md
+++ b/thread-pool/index.md
@@ -4,10 +4,14 @@ title: Thread Pool
folder: thread-pool
permalink: /patterns/thread-pool/
categories: Concurrency
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
+ - Performance
---
-**Intent:** It is often the case that tasks to be executed are short-lived and
+## Intent
+It is often the case that tasks to be executed are short-lived and
the number of tasks is large. Creating a new thread for each task would make
the system spend more time creating and destroying the threads than executing
the actual tasks. Thread Pool solves this problem by reusing existing threads
@@ -15,6 +19,7 @@ and eliminating the latency of creating new threads.

-**Applicability:** Use the Thread Pool pattern when
+## Applicability
+Use the Thread Pool pattern when
* you have a large number of short-lived tasks to be executed in parallel
diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml
index c50140237..5965b46bb 100644
--- a/thread-pool/pom.xml
+++ b/thread-pool/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTthread-pool
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/thread-pool/src/main/java/com/iluwatar/threadpool/App.java b/thread-pool/src/main/java/com/iluwatar/threadpool/App.java
index 75971cd18..1833f3950 100644
--- a/thread-pool/src/main/java/com/iluwatar/threadpool/App.java
+++ b/thread-pool/src/main/java/com/iluwatar/threadpool/App.java
@@ -65,6 +65,7 @@ public class App {
// All tasks were executed, now shutdown
executor.shutdown();
while (!executor.isTerminated()) {
+ Thread.yield();
}
System.out.println("Program finished");
}
diff --git a/thread-pool/src/main/java/com/iluwatar/threadpool/CoffeeMakingTask.java b/thread-pool/src/main/java/com/iluwatar/threadpool/CoffeeMakingTask.java
index f1247101c..3a8464092 100644
--- a/thread-pool/src/main/java/com/iluwatar/threadpool/CoffeeMakingTask.java
+++ b/thread-pool/src/main/java/com/iluwatar/threadpool/CoffeeMakingTask.java
@@ -7,7 +7,7 @@ package com.iluwatar.threadpool;
*/
public class CoffeeMakingTask extends Task {
- private static final int TIME_PER_CUP = 300;
+ private static final int TIME_PER_CUP = 100;
public CoffeeMakingTask(int numCups) {
super(numCups * TIME_PER_CUP);
diff --git a/thread-pool/src/main/java/com/iluwatar/threadpool/PotatoPeelingTask.java b/thread-pool/src/main/java/com/iluwatar/threadpool/PotatoPeelingTask.java
index a90bf4bec..2be941406 100644
--- a/thread-pool/src/main/java/com/iluwatar/threadpool/PotatoPeelingTask.java
+++ b/thread-pool/src/main/java/com/iluwatar/threadpool/PotatoPeelingTask.java
@@ -7,7 +7,7 @@ package com.iluwatar.threadpool;
*/
public class PotatoPeelingTask extends Task {
- private static final int TIME_PER_POTATO = 500;
+ private static final int TIME_PER_POTATO = 200;
public PotatoPeelingTask(int numPotatoes) {
super(numPotatoes * TIME_PER_POTATO);
diff --git a/thread-pool/src/main/java/com/iluwatar/threadpool/Task.java b/thread-pool/src/main/java/com/iluwatar/threadpool/Task.java
index 12fecbbd0..2426948b3 100644
--- a/thread-pool/src/main/java/com/iluwatar/threadpool/Task.java
+++ b/thread-pool/src/main/java/com/iluwatar/threadpool/Task.java
@@ -1,19 +1,21 @@
package com.iluwatar.threadpool;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
- *
+ *
* Abstract base class for tasks
*
*/
public abstract class Task {
- private static int nextId = 1;
+ private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
private final int id;
private final int timeMs;
public Task(final int timeMs) {
- this.id = nextId++;
+ this.id = ID_GENERATOR.incrementAndGet();
this.timeMs = timeMs;
}
diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java
index c725983e2..f0f7b74bb 100644
--- a/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java
+++ b/thread-pool/src/test/java/com/iluwatar/threadpool/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.threadpool;
import org.junit.Test;
-import com.iluwatar.threadpool.App;
-
/**
* Application test
*
diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/CoffeeMakingTaskTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/CoffeeMakingTaskTest.java
new file mode 100644
index 000000000..ab3d47d9a
--- /dev/null
+++ b/thread-pool/src/test/java/com/iluwatar/threadpool/CoffeeMakingTaskTest.java
@@ -0,0 +1,17 @@
+package com.iluwatar.threadpool;
+
+/**
+ * Date: 12/30/15 - 18:23 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CoffeeMakingTaskTest extends TaskTest {
+
+ /**
+ * Create a new test instance
+ */
+ public CoffeeMakingTaskTest() {
+ super(CoffeeMakingTask::new, 100);
+ }
+
+}
diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/PotatoPeelingTaskTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/PotatoPeelingTaskTest.java
new file mode 100644
index 000000000..4f9b1496c
--- /dev/null
+++ b/thread-pool/src/test/java/com/iluwatar/threadpool/PotatoPeelingTaskTest.java
@@ -0,0 +1,17 @@
+package com.iluwatar.threadpool;
+
+/**
+ * Date: 12/30/15 - 18:23 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class PotatoPeelingTaskTest extends TaskTest {
+
+ /**
+ * Create a new test instance
+ */
+ public PotatoPeelingTaskTest() {
+ super(PotatoPeelingTask::new, 200);
+ }
+
+}
\ No newline at end of file
diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java
new file mode 100644
index 000000000..f1ef8160f
--- /dev/null
+++ b/thread-pool/src/test/java/com/iluwatar/threadpool/TaskTest.java
@@ -0,0 +1,121 @@
+package com.iluwatar.threadpool;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * Date: 12/30/15 - 18:22 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class TaskTest {
+
+ /**
+ * The number of tasks used during the concurrency test
+ */
+ private static final int TASK_COUNT = 128 * 1024;
+
+ /**
+ * The number of threads used during the concurrency test
+ */
+ private static final int THREAD_COUNT = 8;
+
+ /**
+ * The task factory, used to create new test items
+ */
+ private final Function factory;
+
+ /**
+ * The expected time needed to run the task 1 single time, in milli seconds
+ */
+ private final int expectedExecutionTime;
+
+ /**
+ * Create a new test instance
+ *
+ * @param factory The task factory, used to create new test items
+ * @param expectedExecutionTime The expected time needed to run the task 1 time, in milli seconds
+ */
+ public TaskTest(final Function factory, final int expectedExecutionTime) {
+ this.factory = factory;
+ this.expectedExecutionTime = expectedExecutionTime;
+ }
+
+ /**
+ * Verify if the generated id is unique for each task, even if the tasks are created in separate
+ * threads
+ */
+ @Test(timeout = 10000)
+ public void testIdGeneration() throws Exception {
+ final ExecutorService service = Executors.newFixedThreadPool(THREAD_COUNT);
+
+ final List> tasks = new ArrayList<>();
+ for (int i = 0; i < TASK_COUNT; i++) {
+ tasks.add(() -> factory.apply(1).getId());
+ }
+
+ final List ids = service.invokeAll(tasks)
+ .stream()
+ .map(TaskTest::get)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ service.shutdownNow();
+
+ final long uniqueIdCount = ids.stream()
+ .distinct()
+ .count();
+
+ assertEquals(TASK_COUNT, ids.size());
+ assertEquals(TASK_COUNT, uniqueIdCount);
+
+ }
+
+ /**
+ * Verify if the time per execution of a task matches the actual time required to execute the task
+ * a given number of times
+ */
+ @Test
+ public void testTimeMs() {
+ for (int i = 0; i < 10; i++) {
+ assertEquals(this.expectedExecutionTime * i, this.factory.apply(i).getTimeMs());
+ }
+ }
+
+ /**
+ * Verify if the task has some sort of {@link T#toString()}, different from 'null'
+ */
+ @Test
+ public void testToString() {
+ assertNotNull(this.factory.apply(0).toString());
+ }
+
+ /**
+ * Extract the result from a future or returns 'null' when an exception occurred
+ *
+ * @param future The future we want the result from
+ * @param The result type
+ * @return The result or 'null' when a checked exception occurred
+ */
+ private static O get(Future future) {
+ try {
+ return future.get();
+ } catch (InterruptedException | ExecutionException e) {
+ return null;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/thread-pool/src/test/java/com/iluwatar/threadpool/WorkerTest.java b/thread-pool/src/test/java/com/iluwatar/threadpool/WorkerTest.java
new file mode 100644
index 000000000..53a1d8694
--- /dev/null
+++ b/thread-pool/src/test/java/com/iluwatar/threadpool/WorkerTest.java
@@ -0,0 +1,31 @@
+package com.iluwatar.threadpool;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+/**
+ * Date: 12/30/15 - 18:21 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class WorkerTest {
+
+ /**
+ * Verify if a worker does the actual job
+ */
+ @Test
+ public void testRun() {
+ final Task task = mock(Task.class);
+ final Worker worker = new Worker(task);
+ verifyZeroInteractions(task);
+
+ worker.run();
+ verify(task).getTimeMs();
+ verifyNoMoreInteractions(task);
+ }
+
+}
\ No newline at end of file
diff --git a/tolerant-reader/index.md b/tolerant-reader/index.md
index b2bfd376a..be0085f2c 100644
--- a/tolerant-reader/index.md
+++ b/tolerant-reader/index.md
@@ -4,20 +4,24 @@ title: Tolerant Reader
folder: tolerant-reader
permalink: /patterns/tolerant-reader/
categories: Integration
-tags: Java
+tags:
+ - Java
+ - Difficulty-Beginner
---
-**Intent:** Tolerant Reader is an integration pattern that helps creating
+## Intent
+Tolerant Reader is an integration pattern that helps creating
robust communication systems. The idea is to be as tolerant as possible when
reading data from another service. This way, when the communication schema
changes, the readers must not break.

-**Applicability:** Use the Tolerant Reader pattern when
+## Applicability
+Use the Tolerant Reader pattern when
* the communication schema can evolve and change and yet the receiving side should not break
-**Credits:**
+## Credits
* [Martin Fowler - Tolerant Reader](http://martinfowler.com/bliki/TolerantReader.html)
diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml
index 2d8b26ca6..c7677b934 100644
--- a/tolerant-reader/pom.xml
+++ b/tolerant-reader/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTtolerant-reader
diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java
index eb73fb7f3..242b71390 100644
--- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java
+++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/App.java
@@ -19,6 +19,9 @@ import java.io.IOException;
*/
public class App {
+ /**
+ * Program entry point
+ */
public static void main(String[] args) throws IOException, ClassNotFoundException {
// Write V1
RainbowFish fishV1 = new RainbowFish("Zed", 10, 11, 12);
diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java
index 74c4526a0..d12ed4dbf 100644
--- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java
+++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFish.java
@@ -16,6 +16,9 @@ public class RainbowFish implements Serializable {
private int lengthMeters;
private int weightTons;
+ /**
+ * Constructor
+ */
public RainbowFish(String name, int age, int lengthMeters, int weightTons) {
this.name = name;
this.age = age;
diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java
index 3929e06e7..5d2a13735 100644
--- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java
+++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishSerializer.java
@@ -18,12 +18,11 @@ import java.util.Map;
*/
public class RainbowFishSerializer {
+ private RainbowFishSerializer() {
+ }
+
/**
* Write V1 RainbowFish to file
- *
- * @param rainbowFish
- * @param filename
- * @throws IOException
*/
public static void writeV1(RainbowFish rainbowFish, String filename) throws IOException {
Map map = new HashMap<>();
@@ -40,10 +39,6 @@ public class RainbowFishSerializer {
/**
* Write V2 RainbowFish to file
- *
- * @param rainbowFish
- * @param filename
- * @throws IOException
*/
public static void writeV2(RainbowFishV2 rainbowFish, String filename) throws IOException {
Map map = new HashMap<>();
@@ -63,17 +58,11 @@ public class RainbowFishSerializer {
/**
* Read V1 RainbowFish from file
- *
- * @param filename
- * @return
- * @throws IOException
- * @throws ClassNotFoundException
*/
public static RainbowFish readV1(String filename) throws IOException, ClassNotFoundException {
- Map map = null;
FileInputStream fileIn = new FileInputStream(filename);
ObjectInputStream objIn = new ObjectInputStream(fileIn);
- map = (Map) objIn.readObject();
+ Map map = (Map) objIn.readObject();
objIn.close();
fileIn.close();
return new RainbowFish(map.get("name"), Integer.parseInt(map.get("age")), Integer.parseInt(map
diff --git a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishV2.java b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishV2.java
index 6146946e1..2c72bee4d 100644
--- a/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishV2.java
+++ b/tolerant-reader/src/main/java/com/iluwatar/tolerantreader/RainbowFishV2.java
@@ -17,6 +17,9 @@ public class RainbowFishV2 extends RainbowFish {
super(name, age, lengthMeters, weightTons);
}
+ /**
+ * Constructor
+ */
public RainbowFishV2(String name, int age, int lengthMeters, int weightTons, boolean sleeping,
boolean hungry, boolean angry) {
this(name, age, lengthMeters, weightTons);
diff --git a/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java
index ceb1c3f66..c7906adb2 100644
--- a/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java
+++ b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/AppTest.java
@@ -1,13 +1,11 @@
package com.iluwatar.tolerantreader;
-import java.io.File;
-import java.io.IOException;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import com.iluwatar.tolerantreader.App;
+import java.io.File;
+import java.io.IOException;
/**
*
diff --git a/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishSerializerTest.java b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishSerializerTest.java
new file mode 100644
index 000000000..5f7ca0262
--- /dev/null
+++ b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishSerializerTest.java
@@ -0,0 +1,68 @@
+package com.iluwatar.tolerantreader;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+
+/**
+ * Date: 12/30/15 - 18:39 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class RainbowFishSerializerTest {
+
+ /**
+ * Create a temporary folder, used to generate files in during this test
+ */
+ @Rule
+ public final TemporaryFolder testFolder = new TemporaryFolder();
+
+ /**
+ * Rainbow fish version 1 used during the tests
+ */
+ private static final RainbowFish V1 = new RainbowFish("version1", 1, 2, 3);
+
+ /**
+ * Rainbow fish version 2 used during the tests
+ */
+ private static final RainbowFishV2 V2 = new RainbowFishV2("version2", 4, 5, 6, true, false, true);
+
+ /**
+ * Verify if a fish, written as version 1 can be read back as version 1
+ */
+ @Test
+ public void testWriteV1ReadV1() throws Exception {
+ final File outputFile = this.testFolder.newFile();
+ RainbowFishSerializer.writeV1(V1, outputFile.getPath());
+
+ final RainbowFish fish = RainbowFishSerializer.readV1(outputFile.getPath());
+ assertNotSame(V1, fish);
+ assertEquals(V1.getName(), fish.getName());
+ assertEquals(V1.getAge(), fish.getAge());
+ assertEquals(V1.getLengthMeters(), fish.getLengthMeters());
+ assertEquals(V1.getWeightTons(), fish.getWeightTons());
+
+ }
+
+ /**
+ * Verify if a fish, written as version 2 can be read back as version 1
+ */
+ @Test
+ public void testWriteV2ReadV1() throws Exception {
+ final File outputFile = this.testFolder.newFile();
+ RainbowFishSerializer.writeV2(V2, outputFile.getPath());
+
+ final RainbowFish fish = RainbowFishSerializer.readV1(outputFile.getPath());
+ assertNotSame(V2, fish);
+ assertEquals(V2.getName(), fish.getName());
+ assertEquals(V2.getAge(), fish.getAge());
+ assertEquals(V2.getLengthMeters(), fish.getLengthMeters());
+ assertEquals(V2.getWeightTons(), fish.getWeightTons());
+ }
+
+}
\ No newline at end of file
diff --git a/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishTest.java b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishTest.java
new file mode 100644
index 000000000..0f7df25c8
--- /dev/null
+++ b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishTest.java
@@ -0,0 +1,26 @@
+package com.iluwatar.tolerantreader;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Date: 12/30/15 - 18:34 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class RainbowFishTest {
+
+ /**
+ * Verify if the getters of a {@link RainbowFish} return the expected values
+ */
+ @Test
+ public void testValues() {
+ final RainbowFish fish = new RainbowFish("name", 1, 2, 3);
+ assertEquals("name", fish.getName());
+ assertEquals(1, fish.getAge());
+ assertEquals(2, fish.getLengthMeters());
+ assertEquals(3, fish.getWeightTons());
+ }
+
+}
\ No newline at end of file
diff --git a/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishV2Test.java b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishV2Test.java
new file mode 100644
index 000000000..5e8bdcef5
--- /dev/null
+++ b/tolerant-reader/src/test/java/com/iluwatar/tolerantreader/RainbowFishV2Test.java
@@ -0,0 +1,29 @@
+package com.iluwatar.tolerantreader;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Date: 12/30/15 - 18:35 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class RainbowFishV2Test {
+
+ /**
+ * Verify if the getters of a {@link RainbowFish} return the expected values
+ */
+ @Test
+ public void testValues() {
+ final RainbowFishV2 fish = new RainbowFishV2("name", 1, 2, 3, false, true, false);
+ assertEquals("name", fish.getName());
+ assertEquals(1, fish.getAge());
+ assertEquals(2, fish.getLengthMeters());
+ assertEquals(3, fish.getWeightTons());
+ assertEquals(false, fish.getSleeping());
+ assertEquals(true, fish.getHungry());
+ assertEquals(false, fish.getAngry());
+ }
+
+}
\ No newline at end of file
diff --git a/twin/index.md b/twin/index.md
index 475437754..3795236bb 100644
--- a/twin/index.md
+++ b/twin/index.md
@@ -4,21 +4,23 @@ title: Twin
folder: twin
permalink: /patterns/twin/
categories: Creational
-tags: Java
+tags:
+ - Java
+ - Difficulty-Intermediate
---
-**Intent:** Twin pattern is a design pattern which provides a standard solution to simulate multiple
+## Intent
+ Twin pattern is a design pattern which provides a standard solution to simulate multiple
inheritance in java
-
-

-**Applicability:** Use the Twin idiom when
+## Applicability
+Use the Twin idiom when
* to simulate multiple inheritance in a language that does not support this feature.
* to avoid certain problems of multiple inheritance such as name clashes.
-**Credits:**
+## Credits
-* [Twin – A Design Pattern for Modeling Multiple Inheritance](http://www.ssw.uni-linz.ac.at/Research/Papers/Moe99/Paper.pdf)
\ No newline at end of file
+* [Twin – A Design Pattern for Modeling Multiple Inheritance](http://www.ssw.uni-linz.ac.at/Research/Papers/Moe99/Paper.pdf)
diff --git a/twin/pom.xml b/twin/pom.xml
index 95e942493..46e8de15a 100644
--- a/twin/pom.xml
+++ b/twin/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTtwin
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/twin/src/main/java/com/iluwatar/twin/App.java b/twin/src/main/java/com/iluwatar/twin/App.java
index eaa21a849..cb971c490 100644
--- a/twin/src/main/java/com/iluwatar/twin/App.java
+++ b/twin/src/main/java/com/iluwatar/twin/App.java
@@ -41,6 +41,6 @@ public class App {
}
private static void waiting() throws Exception {
- Thread.sleep(2500);
+ Thread.sleep(750);
}
}
diff --git a/twin/src/main/java/com/iluwatar/twin/BallThread.java b/twin/src/main/java/com/iluwatar/twin/BallThread.java
index dae537e64..2d9e7c41a 100644
--- a/twin/src/main/java/com/iluwatar/twin/BallThread.java
+++ b/twin/src/main/java/com/iluwatar/twin/BallThread.java
@@ -19,18 +19,20 @@ public class BallThread extends Thread {
this.twin = twin;
}
+ /**
+ * Run the thread
+ */
public void run() {
while (isRunning) {
- while (!isSuspended) {
+ if (!isSuspended) {
twin.draw();
twin.move();
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
-
+ }
+ try {
+ Thread.sleep(250);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
}
}
}
diff --git a/twin/src/main/java/com/iluwatar/twin/GameItem.java b/twin/src/main/java/com/iluwatar/twin/GameItem.java
index d797eda95..e98202d0c 100644
--- a/twin/src/main/java/com/iluwatar/twin/GameItem.java
+++ b/twin/src/main/java/com/iluwatar/twin/GameItem.java
@@ -9,9 +9,6 @@ public abstract class GameItem {
/**
* Template method, do some common logic before draw
- *
- * @param other
- * @return
*/
public void draw() {
System.out.println("draw");
diff --git a/twin/src/test/java/com/iluwatar/twin/BallItemTest.java b/twin/src/test/java/com/iluwatar/twin/BallItemTest.java
new file mode 100644
index 000000000..ca1da7ac8
--- /dev/null
+++ b/twin/src/test/java/com/iluwatar/twin/BallItemTest.java
@@ -0,0 +1,62 @@
+package com.iluwatar.twin;
+
+import org.junit.Test;
+import org.mockito.InOrder;
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/30/15 - 18:44 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class BallItemTest extends StdOutTest {
+
+ @Test
+ public void testClick() {
+ final BallThread ballThread = mock(BallThread.class);
+ final BallItem ballItem = new BallItem();
+ ballItem.setTwin(ballThread);
+
+ final InOrder inOrder = inOrder(ballThread);
+
+ for (int i = 0; i < 10; i++) {
+ ballItem.click();
+ inOrder.verify(ballThread).suspendMe();
+
+ ballItem.click();
+ inOrder.verify(ballThread).resumeMe();
+ }
+
+ inOrder.verifyNoMoreInteractions();
+ }
+
+ @Test
+ public void testDoDraw() {
+ final BallItem ballItem = new BallItem();
+ final BallThread ballThread = mock(BallThread.class);
+ ballItem.setTwin(ballThread);
+
+ ballItem.draw();
+ verify(getStdOutMock()).println("draw");
+ verify(getStdOutMock()).println("doDraw");
+
+ verifyNoMoreInteractions(ballThread, getStdOutMock());
+ }
+
+ @Test
+ public void testMove() {
+ final BallItem ballItem = new BallItem();
+ final BallThread ballThread = mock(BallThread.class);
+ ballItem.setTwin(ballThread);
+
+ ballItem.move();
+ verify(getStdOutMock()).println("move");
+
+ verifyNoMoreInteractions(ballThread, getStdOutMock());
+ }
+
+}
\ No newline at end of file
diff --git a/twin/src/test/java/com/iluwatar/twin/BallThreadTest.java b/twin/src/test/java/com/iluwatar/twin/BallThreadTest.java
new file mode 100644
index 000000000..7e0bdc11e
--- /dev/null
+++ b/twin/src/test/java/com/iluwatar/twin/BallThreadTest.java
@@ -0,0 +1,89 @@
+package com.iluwatar.twin;
+
+import org.junit.Test;
+
+import static java.lang.Thread.UncaughtExceptionHandler;
+import static java.lang.Thread.sleep;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+/**
+ * Date: 12/30/15 - 18:55 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class BallThreadTest {
+
+ /**
+ * Verify if the {@link BallThread} can be resumed
+ */
+ @Test(timeout = 5000)
+ public void testSuspend() throws Exception {
+ final BallThread ballThread = new BallThread();
+
+ final BallItem ballItem = mock(BallItem.class);
+ ballThread.setTwin(ballItem);
+
+ ballThread.start();
+
+ verify(ballItem, timeout(2000).atLeastOnce()).draw();
+ verify(ballItem, timeout(2000).atLeastOnce()).move();
+ ballThread.suspendMe();
+
+ sleep(1000);
+
+ ballThread.stopMe();
+ ballThread.join();
+
+ verifyNoMoreInteractions(ballItem);
+ }
+
+ /**
+ * Verify if the {@link BallThread} can be resumed
+ */
+ @Test(timeout = 5000)
+ public void testResume() throws Exception {
+ final BallThread ballThread = new BallThread();
+
+ final BallItem ballItem = mock(BallItem.class);
+ ballThread.setTwin(ballItem);
+
+ ballThread.suspendMe();
+ ballThread.start();
+
+ sleep(1000);
+
+ verifyZeroInteractions(ballItem);
+
+ ballThread.resumeMe();
+ verify(ballItem, timeout(2000).atLeastOnce()).draw();
+ verify(ballItem, timeout(2000).atLeastOnce()).move();
+
+ ballThread.stopMe();
+ ballThread.join();
+
+ verifyNoMoreInteractions(ballItem);
+ }
+
+ /**
+ * Verify if the {@link BallThread} is interruptible
+ */
+ @Test(timeout = 5000)
+ public void testInterrupt() throws Exception {
+ final BallThread ballThread = new BallThread();
+ final UncaughtExceptionHandler exceptionHandler = mock(UncaughtExceptionHandler.class);
+ ballThread.setUncaughtExceptionHandler(exceptionHandler);
+ ballThread.setTwin(mock(BallItem.class));
+ ballThread.start();
+ ballThread.interrupt();
+ ballThread.join();
+
+ verify(exceptionHandler).uncaughtException(eq(ballThread), any(RuntimeException.class));
+ verifyNoMoreInteractions(exceptionHandler);
+ }
+}
\ No newline at end of file
diff --git a/twin/src/test/java/com/iluwatar/twin/StdOutTest.java b/twin/src/test/java/com/iluwatar/twin/StdOutTest.java
new file mode 100644
index 000000000..f506886e1
--- /dev/null
+++ b/twin/src/test/java/com/iluwatar/twin/StdOutTest.java
@@ -0,0 +1,53 @@
+package com.iluwatar.twin;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/visitor/index.md b/visitor/index.md
index 5f32edbbd..c1e24a624 100644
--- a/visitor/index.md
+++ b/visitor/index.md
@@ -6,26 +6,28 @@ permalink: /patterns/visitor/
categories: Behavioral
tags:
- Java
- - Difficulty-Expert
+ - Difficulty-Intermediate
- Gang Of Four
---
-**Intent:** Represent an operation to be performed on the elements of an object
+## Intent
+Represent an operation to be performed on the elements of an object
structure. Visitor lets you define a new operation without changing the classes
of the elements on which it operates.

-**Applicability:** Use the Visitor pattern when
+## Applicability
+Use the Visitor pattern when
* an object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes
* many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them
* the classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes
-**Real world examples:**
+## Real world examples
* [Apache Wicket](https://github.com/apache/wicket) component tree, see [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java)
-**Credits**
+## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
diff --git a/visitor/pom.xml b/visitor/pom.xml
index c51b4a7fe..a53e2bcc5 100644
--- a/visitor/pom.xml
+++ b/visitor/pom.xml
@@ -5,7 +5,7 @@
com.iluwatarjava-design-patterns
- 1.9.0-SNAPSHOT
+ 1.10.0-SNAPSHOTvisitor
@@ -14,5 +14,10 @@
junittest
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/visitor/src/main/java/com/iluwatar/visitor/Unit.java b/visitor/src/main/java/com/iluwatar/visitor/Unit.java
index 9fb52f6e0..300a6299b 100644
--- a/visitor/src/main/java/com/iluwatar/visitor/Unit.java
+++ b/visitor/src/main/java/com/iluwatar/visitor/Unit.java
@@ -13,6 +13,9 @@ public abstract class Unit {
this.children = children;
}
+ /**
+ * Accept visitor
+ */
public void accept(UnitVisitor visitor) {
for (Unit child : children) {
child.accept(visitor);
diff --git a/visitor/src/test/java/com/iluwatar/visitor/AppTest.java b/visitor/src/test/java/com/iluwatar/visitor/AppTest.java
index 912f1a228..573a11532 100644
--- a/visitor/src/test/java/com/iluwatar/visitor/AppTest.java
+++ b/visitor/src/test/java/com/iluwatar/visitor/AppTest.java
@@ -2,8 +2,6 @@ package com.iluwatar.visitor;
import org.junit.Test;
-import com.iluwatar.visitor.App;
-
/**
*
* Application test
diff --git a/visitor/src/test/java/com/iluwatar/visitor/CommanderTest.java b/visitor/src/test/java/com/iluwatar/visitor/CommanderTest.java
new file mode 100644
index 000000000..bbf6c7963
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/CommanderTest.java
@@ -0,0 +1,25 @@
+package com.iluwatar.visitor;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Date: 12/30/15 - 19:45 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CommanderTest extends UnitTest {
+
+ /**
+ * Create a new test instance for the given {@link Commander}
+ */
+ public CommanderTest() {
+ super(Commander::new);
+ }
+
+ @Override
+ void verifyVisit(Commander unit, UnitVisitor mockedVisitor) {
+ verify(mockedVisitor).visitCommander(eq(unit));
+ }
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/CommanderVisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/CommanderVisitorTest.java
new file mode 100644
index 000000000..ac296c332
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/CommanderVisitorTest.java
@@ -0,0 +1,24 @@
+package com.iluwatar.visitor;
+
+import java.util.Optional;
+
+/**
+ * Date: 12/30/15 - 18:43 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class CommanderVisitorTest extends VisitorTest {
+
+ /**
+ * Create a new test instance for the given visitor
+ */
+ public CommanderVisitorTest() {
+ super(
+ new CommanderVisitor(),
+ Optional.of("Good to see you commander"),
+ Optional.empty(),
+ Optional.empty()
+ );
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SergeantTest.java b/visitor/src/test/java/com/iluwatar/visitor/SergeantTest.java
new file mode 100644
index 000000000..d0e6d3db2
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SergeantTest.java
@@ -0,0 +1,25 @@
+package com.iluwatar.visitor;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Date: 12/30/15 - 19:45 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SergeantTest extends UnitTest {
+
+ /**
+ * Create a new test instance for the given {@link Sergeant}
+ */
+ public SergeantTest() {
+ super(Sergeant::new);
+ }
+
+ @Override
+ void verifyVisit(Sergeant unit, UnitVisitor mockedVisitor) {
+ verify(mockedVisitor).visitSergeant(eq(unit));
+ }
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SergeantVisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/SergeantVisitorTest.java
new file mode 100644
index 000000000..54e274bc7
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SergeantVisitorTest.java
@@ -0,0 +1,24 @@
+package com.iluwatar.visitor;
+
+import java.util.Optional;
+
+/**
+ * Date: 12/30/15 - 18:36 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SergeantVisitorTest extends VisitorTest {
+
+ /**
+ * Create a new test instance for the given visitor
+ */
+ public SergeantVisitorTest() {
+ super(
+ new SergeantVisitor(),
+ Optional.empty(),
+ Optional.of("Hello sergeant"),
+ Optional.empty()
+ );
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SoldierTest.java b/visitor/src/test/java/com/iluwatar/visitor/SoldierTest.java
new file mode 100644
index 000000000..e9aa54608
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SoldierTest.java
@@ -0,0 +1,25 @@
+package com.iluwatar.visitor;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Date: 12/30/15 - 19:45 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SoldierTest extends UnitTest {
+
+ /**
+ * Create a new test instance for the given {@link Soldier}
+ */
+ public SoldierTest() {
+ super(Soldier::new);
+ }
+
+ @Override
+ void verifyVisit(Soldier unit, UnitVisitor mockedVisitor) {
+ verify(mockedVisitor).visitSoldier(eq(unit));
+ }
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/SoldierVisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/SoldierVisitorTest.java
new file mode 100644
index 000000000..a5f16e9e3
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/SoldierVisitorTest.java
@@ -0,0 +1,24 @@
+package com.iluwatar.visitor;
+
+import java.util.Optional;
+
+/**
+ * Date: 12/30/15 - 18:59 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public class SoldierVisitorTest extends VisitorTest {
+
+ /**
+ * Create a new test instance for the given visitor
+ */
+ public SoldierVisitorTest() {
+ super(
+ new SoldierVisitor(),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.of("Greetings soldier")
+ );
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java b/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java
new file mode 100644
index 000000000..2c54994bb
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/StdOutTest.java
@@ -0,0 +1,53 @@
+package com.iluwatar.visitor;
+
+import org.junit.After;
+import org.junit.Before;
+
+import java.io.PrintStream;
+
+import static org.mockito.Mockito.mock;
+
+/**
+ * Date: 12/10/15 - 8:37 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class StdOutTest {
+
+ /**
+ * The mocked standard out {@link PrintStream}, required since some actions don't have any
+ * influence on accessible objects, except for writing to std-out using {@link System#out}
+ */
+ private final PrintStream stdOutMock = mock(PrintStream.class);
+
+ /**
+ * Keep the original std-out so it can be restored after the test
+ */
+ private final PrintStream stdOutOrig = System.out;
+
+ /**
+ * Inject the mocked std-out {@link PrintStream} into the {@link System} class before each test
+ */
+ @Before
+ public void setUp() {
+ System.setOut(this.stdOutMock);
+ }
+
+ /**
+ * Removed the mocked std-out {@link PrintStream} again from the {@link System} class
+ */
+ @After
+ public void tearDown() {
+ System.setOut(this.stdOutOrig);
+ }
+
+ /**
+ * Get the mocked stdOut {@link PrintStream}
+ *
+ * @return The stdOut print stream mock, renewed before each test
+ */
+ final PrintStream getStdOutMock() {
+ return this.stdOutMock;
+ }
+
+}
diff --git a/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java b/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java
new file mode 100644
index 000000000..291ab544a
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/UnitTest.java
@@ -0,0 +1,60 @@
+package com.iluwatar.visitor;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.function.Function;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/30/15 - 18:59 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class UnitTest {
+
+ /**
+ * Factory to create new instances of the tested unit
+ */
+ private final Function factory;
+
+ /**
+ * Create a new test instance for the given unit type {@link U}
+ *
+ * @param factory Factory to create new instances of the tested unit
+ */
+ public UnitTest(final Function factory) {
+ this.factory = factory;
+ }
+
+ @Test
+ public void testAccept() throws Exception {
+ final Unit[] children = new Unit[5];
+ Arrays.setAll(children, (i) -> mock(Unit.class));
+
+ final U unit = this.factory.apply(children);
+ final UnitVisitor visitor = mock(UnitVisitor.class);
+ unit.accept(visitor);
+ verifyVisit(unit, visitor);
+
+ for (final Unit child : children) {
+ verify(child).accept(eq(visitor));
+ }
+
+ verifyNoMoreInteractions(children);
+ verifyNoMoreInteractions(visitor);
+ }
+
+ /**
+ * Verify if the correct visit method is called on the mock, depending on the tested instance
+ *
+ * @param unit The tested unit instance
+ * @param mockedVisitor The mocked {@link UnitVisitor} who should have gotten a visit by the unit
+ */
+ abstract void verifyVisit(final U unit, final UnitVisitor mockedVisitor);
+
+}
\ No newline at end of file
diff --git a/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java
new file mode 100644
index 000000000..7bd9f03c0
--- /dev/null
+++ b/visitor/src/test/java/com/iluwatar/visitor/VisitorTest.java
@@ -0,0 +1,80 @@
+package com.iluwatar.visitor;
+
+import org.junit.Test;
+
+import java.util.Optional;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+/**
+ * Date: 12/30/15 - 18:59 PM
+ *
+ * @author Jeroen Meulemeester
+ */
+public abstract class VisitorTest extends StdOutTest {
+
+ /**
+ * The tested visitor instance
+ */
+ private final V visitor;
+
+ /**
+ * The optional expected response when being visited by a commander
+ */
+ private final Optional commanderResponse;
+
+ /**
+ * The optional expected response when being visited by a sergeant
+ */
+ private final Optional sergeantResponse;
+
+ /**
+ * The optional expected response when being visited by a soldier
+ */
+ private final Optional soldierResponse;
+
+ /**
+ * Create a new test instance for the given visitor
+ *
+ * @param commanderResponse The optional expected response when being visited by a commander
+ * @param sergeantResponse The optional expected response when being visited by a sergeant
+ * @param soldierResponse The optional expected response when being visited by a soldier
+ */
+ public VisitorTest(final V visitor, final Optional commanderResponse,
+ final Optional sergeantResponse, final Optional soldierResponse) {
+
+ this.visitor = visitor;
+ this.commanderResponse = commanderResponse;
+ this.sergeantResponse = sergeantResponse;
+ this.soldierResponse = soldierResponse;
+ }
+
+ @Test
+ public void testVisitCommander() {
+ this.visitor.visitCommander(new Commander());
+ if (this.commanderResponse.isPresent()) {
+ verify(getStdOutMock()).println(this.commanderResponse.get());
+ }
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+ @Test
+ public void testVisitSergeant() {
+ this.visitor.visitSergeant(new Sergeant());
+ if (this.sergeantResponse.isPresent()) {
+ verify(getStdOutMock()).println(this.sergeantResponse.get());
+ }
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+ @Test
+ public void testVisitSoldier() {
+ this.visitor.visitSoldier(new Soldier());
+ if (this.soldierResponse.isPresent()) {
+ verify(getStdOutMock()).println(this.soldierResponse.get());
+ }
+ verifyNoMoreInteractions(getStdOutMock());
+ }
+
+}