Resolves checkstyle errors for ambassador, async-method-invocation, balking, bridge, builder (#1058)
* Decreases checkstyle errors for ambassador pattern * Reduces checkstyle errors in async-method-invocation * Reduces checkstyle errors in balking * Reduces checkstyle errors in bridge * Reduces checkstyle errors in builder
This commit is contained in:
parent
1fa8a604eb
commit
6d1c0b1563
@ -24,27 +24,26 @@
|
|||||||
package com.iluwatar.ambassador;
|
package com.iluwatar.ambassador;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* The ambassador pattern creates a helper service that sends network requests on behalf of a
|
* The ambassador pattern creates a helper service that sends network requests on behalf of a
|
||||||
* client. It is often used in cloud-based applications to offload features of a remote service.
|
* client. It is often used in cloud-based applications to offload features of a remote service.
|
||||||
*
|
*
|
||||||
* An ambassador service can be thought of as an out-of-process proxy that is co-located with
|
* <p>An ambassador service can be thought of as an out-of-process proxy that is co-located with
|
||||||
* the client. Similar to the proxy design pattern, the ambassador service provides an interface
|
* the client. Similar to the proxy design pattern, the ambassador service provides an interface for
|
||||||
* for another remote service. In addition to the interface, the ambassador provides extra
|
* another remote service. In addition to the interface, the ambassador provides extra functionality
|
||||||
* functionality and features, specifically offloaded common connectivity tasks. This usually
|
* and features, specifically offloaded common connectivity tasks. This usually consists of
|
||||||
* consists of monitoring, logging, routing, security etc. This is extremely useful in
|
* monitoring, logging, routing, security etc. This is extremely useful in legacy applications where
|
||||||
* legacy applications where the codebase is difficult to modify and allows for improvements
|
* the codebase is difficult to modify and allows for improvements in the application's networking
|
||||||
* in the application's networking capabilities.
|
* capabilities.
|
||||||
*
|
*
|
||||||
* In this example, we will the ({@link ServiceAmbassador}) class represents the ambassador while the
|
* <p>In this example, we will the ({@link ServiceAmbassador}) class represents the ambassador while
|
||||||
|
* the
|
||||||
* ({@link RemoteService}) class represents a remote application.
|
* ({@link RemoteService}) class represents a remote application.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entry point
|
* Entry point.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
Client host1 = new Client();
|
Client host1 = new Client();
|
||||||
Client host2 = new Client();
|
Client host2 = new Client();
|
||||||
|
@ -23,12 +23,11 @@
|
|||||||
|
|
||||||
package com.iluwatar.ambassador;
|
package com.iluwatar.ambassador;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple Client
|
* A simple Client.
|
||||||
*/
|
*/
|
||||||
public class Client {
|
public class Client {
|
||||||
|
|
||||||
|
@ -23,12 +23,12 @@
|
|||||||
|
|
||||||
package com.iluwatar.ambassador;
|
package com.iluwatar.ambassador;
|
||||||
|
|
||||||
|
import static java.lang.Thread.sleep;
|
||||||
|
|
||||||
import com.iluwatar.ambassador.util.RandomProvider;
|
import com.iluwatar.ambassador.util.RandomProvider;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static java.lang.Thread.sleep;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A remote legacy application represented by a Singleton implementation.
|
* A remote legacy application represented by a Singleton implementation.
|
||||||
*/
|
*/
|
||||||
@ -55,9 +55,11 @@ public class RemoteService implements RemoteServiceInterface {
|
|||||||
RemoteService(RandomProvider randomProvider) {
|
RemoteService(RandomProvider randomProvider) {
|
||||||
this.randomProvider = randomProvider;
|
this.randomProvider = randomProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remote function takes a value and multiplies it by 10 taking a random amount of time.
|
* Remote function takes a value and multiplies it by 10 taking a random amount of time. Will
|
||||||
* Will sometimes return -1. This imitates connectivity issues a client might have to account for.
|
* sometimes return -1. This imitates connectivity issues a client might have to account for.
|
||||||
|
*
|
||||||
* @param value integer value to be multiplied.
|
* @param value integer value to be multiplied.
|
||||||
* @return if waitTime is less than {@link RemoteService#THRESHOLD}, it returns value * 10,
|
* @return if waitTime is less than {@link RemoteService#THRESHOLD}, it returns value * 10,
|
||||||
* otherwise {@link RemoteServiceInterface#FAILURE}.
|
* otherwise {@link RemoteServiceInterface#FAILURE}.
|
||||||
|
@ -23,17 +23,15 @@
|
|||||||
|
|
||||||
package com.iluwatar.ambassador;
|
package com.iluwatar.ambassador;
|
||||||
|
|
||||||
|
import static java.lang.Thread.sleep;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static java.lang.Thread.sleep;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* ServiceAmbassador provides an interface for a ({@link Client}) to access ({@link RemoteService}).
|
* ServiceAmbassador provides an interface for a ({@link Client}) to access ({@link RemoteService}).
|
||||||
* The interface adds logging, latency testing and usage of the service in a safe way that will not
|
* The interface adds logging, latency testing and usage of the service in a safe way that will not
|
||||||
* add stress to the remote service when connectivity issues occur.
|
* add stress to the remote service when connectivity issues occur.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ServiceAmbassador implements RemoteServiceInterface {
|
public class ServiceAmbassador implements RemoteServiceInterface {
|
||||||
|
|
||||||
@ -41,7 +39,8 @@ public class ServiceAmbassador implements RemoteServiceInterface {
|
|||||||
private static final int RETRIES = 3;
|
private static final int RETRIES = 3;
|
||||||
private static final int DELAY_MS = 3000;
|
private static final int DELAY_MS = 3000;
|
||||||
|
|
||||||
ServiceAmbassador() {}
|
ServiceAmbassador() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long doRemoteFunction(int value) {
|
public long doRemoteFunction(int value) {
|
||||||
|
@ -23,35 +23,34 @@
|
|||||||
|
|
||||||
package com.iluwatar.async.method.invocation;
|
package com.iluwatar.async.method.invocation;
|
||||||
|
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This application demonstrates the async method invocation pattern. Key parts of the pattern are
|
* This application demonstrates the async method invocation pattern. Key parts of the pattern are
|
||||||
* <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated value,
|
* <code>AsyncResult</code> which is an intermediate container for an asynchronously evaluated
|
||||||
* <code>AsyncCallback</code> which can be provided to be executed on task completion and <code>AsyncExecutor</code>
|
* value, <code>AsyncCallback</code> which can be provided to be executed on task completion and
|
||||||
* that manages the execution of the async tasks.
|
* <code>AsyncExecutor</code> that manages the execution of the async tasks.
|
||||||
* <p>
|
*
|
||||||
* The main method shows example flow of async invocations. The main thread starts multiple tasks with variable
|
* <p>The main method shows example flow of async invocations. The main thread starts multiple
|
||||||
* durations and then continues its own work. When the main thread has done it's job it collects the results of the
|
* tasks with variable durations and then continues its own work. When the main thread has done it's
|
||||||
* async tasks. Two of the tasks are handled with callbacks, meaning the callbacks are executed immediately when the
|
* job it collects the results of the async tasks. Two of the tasks are handled with callbacks,
|
||||||
* tasks complete.
|
* meaning the callbacks are executed immediately when the tasks complete.
|
||||||
* <p>
|
*
|
||||||
* Noteworthy difference of thread usage between the async results and callbacks is that the async results are collected
|
* <p>Noteworthy difference of thread usage between the async results and callbacks is that the
|
||||||
* in the main thread but the callbacks are executed within the worker threads. This should be noted when working with
|
* async results are collected in the main thread but the callbacks are executed within the worker
|
||||||
* thread pools.
|
* threads. This should be noted when working with thread pools.
|
||||||
* <p>
|
*
|
||||||
* Java provides its own implementations of async method invocation pattern. FutureTask, CompletableFuture and
|
* <p>Java provides its own implementations of async method invocation pattern. FutureTask,
|
||||||
* ExecutorService are the real world implementations of this pattern. But due to the nature of parallel programming,
|
* CompletableFuture and ExecutorService are the real world implementations of this pattern. But due
|
||||||
* the implementations are not trivial. This example does not take all possible scenarios into account but rather
|
* to the nature of parallel programming, the implementations are not trivial. This example does not
|
||||||
* provides a simple version that helps to understand the pattern.
|
* take all possible scenarios into account but rather provides a simple version that helps to
|
||||||
|
* understand the pattern.
|
||||||
*
|
*
|
||||||
* @see AsyncResult
|
* @see AsyncResult
|
||||||
* @see AsyncCallback
|
* @see AsyncCallback
|
||||||
* @see AsyncExecutor
|
* @see AsyncExecutor
|
||||||
*
|
|
||||||
* @see java.util.concurrent.FutureTask
|
* @see java.util.concurrent.FutureTask
|
||||||
* @see java.util.concurrent.CompletableFuture
|
* @see java.util.concurrent.CompletableFuture
|
||||||
* @see java.util.concurrent.ExecutorService
|
* @see java.util.concurrent.ExecutorService
|
||||||
@ -61,27 +60,29 @@ public class App {
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point
|
* Program entry point.
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
// construct a new executor that will run async tasks
|
// construct a new executor that will run async tasks
|
||||||
AsyncExecutor executor = new ThreadAsyncExecutor();
|
AsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
|
||||||
// start few async tasks with varying processing times, two last with callback handlers
|
// start few async tasks with varying processing times, two last with callback handlers
|
||||||
AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
|
final AsyncResult<Integer> asyncResult1 = executor.startProcess(lazyval(10, 500));
|
||||||
AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
|
final AsyncResult<String> asyncResult2 = executor.startProcess(lazyval("test", 300));
|
||||||
AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
final AsyncResult<Long> asyncResult3 = executor.startProcess(lazyval(50L, 700));
|
||||||
AsyncResult<Integer> asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
|
final AsyncResult<Integer> asyncResult4 =
|
||||||
AsyncResult<String> asyncResult5 = executor.startProcess(lazyval("callback", 600), callback("Callback result 5"));
|
executor.startProcess(lazyval(20, 400), callback("Callback result 4"));
|
||||||
|
final AsyncResult<String> 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
|
// 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
|
Thread.sleep(350); // Oh boy I'm working hard here
|
||||||
log("Some hard work done");
|
log("Some hard work done");
|
||||||
|
|
||||||
// wait for completion of the tasks
|
// wait for completion of the tasks
|
||||||
Integer result1 = executor.endProcess(asyncResult1);
|
final Integer result1 = executor.endProcess(asyncResult1);
|
||||||
String result2 = executor.endProcess(asyncResult2);
|
final String result2 = executor.endProcess(asyncResult2);
|
||||||
Long result3 = executor.endProcess(asyncResult3);
|
final Long result3 = executor.endProcess(asyncResult3);
|
||||||
asyncResult4.await();
|
asyncResult4.await();
|
||||||
asyncResult5.await();
|
asyncResult5.await();
|
||||||
|
|
||||||
@ -94,10 +95,8 @@ public class App {
|
|||||||
/**
|
/**
|
||||||
* Creates a callable that lazily evaluates to given value with artificial delay.
|
* Creates a callable that lazily evaluates to given value with artificial delay.
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value value to evaluate
|
||||||
* value to evaluate
|
* @param delayMillis artificial delay in milliseconds
|
||||||
* @param delayMillis
|
|
||||||
* artificial delay in milliseconds
|
|
||||||
* @return new callable for lazy evaluation
|
* @return new callable for lazy evaluation
|
||||||
*/
|
*/
|
||||||
private static <T> Callable<T> lazyval(T value, long delayMillis) {
|
private static <T> Callable<T> lazyval(T value, long delayMillis) {
|
||||||
@ -111,8 +110,7 @@ public class App {
|
|||||||
/**
|
/**
|
||||||
* Creates a simple callback that logs the complete status of the async result.
|
* Creates a simple callback that logs the complete status of the async result.
|
||||||
*
|
*
|
||||||
* @param name
|
* @param name callback name
|
||||||
* callback name
|
|
||||||
* @return new async callback
|
* @return new async callback
|
||||||
*/
|
*/
|
||||||
private static <T> AsyncCallback<T> callback(String name) {
|
private static <T> AsyncCallback<T> callback(String name) {
|
||||||
|
@ -26,11 +26,9 @@ package com.iluwatar.async.method.invocation;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* AsyncCallback interface.
|
||||||
* AsyncCallback interface
|
|
||||||
*
|
*
|
||||||
* @param <T>
|
* @param <T> Type of Result
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface AsyncCallback<T> {
|
public interface AsyncCallback<T> {
|
||||||
|
|
||||||
@ -38,7 +36,7 @@ public interface AsyncCallback<T> {
|
|||||||
* Complete handler which is executed when async task is completed or fails execution.
|
* Complete handler which is executed when async task is completed or fails execution.
|
||||||
*
|
*
|
||||||
* @param value the evaluated value from async task, undefined when execution fails
|
* @param value the evaluated value from async task, undefined when execution fails
|
||||||
* @param ex empty value if execution succeeds, some exception if executions fails
|
* @param ex empty value if execution succeeds, some exception if executions fails
|
||||||
*/
|
*/
|
||||||
void onComplete(T value, Optional<Exception> ex);
|
void onComplete(T value, Optional<Exception> ex);
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,7 @@ import java.util.concurrent.Callable;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* AsyncExecutor interface.
|
||||||
* AsyncExecutor interface
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface AsyncExecutor {
|
public interface AsyncExecutor {
|
||||||
|
|
||||||
@ -45,7 +43,7 @@ public interface AsyncExecutor {
|
|||||||
* Starts processing of an async task. Returns immediately with async result. Executes callback
|
* Starts processing of an async task. Returns immediately with async result. Executes callback
|
||||||
* when the task is completed.
|
* when the task is completed.
|
||||||
*
|
*
|
||||||
* @param task task to be executed asynchronously
|
* @param task task to be executed asynchronously
|
||||||
* @param callback callback to be executed on task completion
|
* @param callback callback to be executed on task completion
|
||||||
* @return async result for the task
|
* @return async result for the task
|
||||||
*/
|
*/
|
||||||
@ -57,7 +55,7 @@ public interface AsyncExecutor {
|
|||||||
*
|
*
|
||||||
* @param asyncResult async result of a task
|
* @param asyncResult async result of a task
|
||||||
* @return evaluated value of the completed task
|
* @return evaluated value of the completed task
|
||||||
* @throws ExecutionException if execution has failed, containing the root cause
|
* @throws ExecutionException if execution has failed, containing the root cause
|
||||||
* @throws InterruptedException if the execution is interrupted
|
* @throws InterruptedException if the execution is interrupted
|
||||||
*/
|
*/
|
||||||
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
|
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
|
||||||
|
@ -26,7 +26,8 @@ package com.iluwatar.async.method.invocation;
|
|||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AsyncResult interface
|
* AsyncResult interface.
|
||||||
|
*
|
||||||
* @param <T> parameter returned when getValue is invoked
|
* @param <T> parameter returned when getValue is invoked
|
||||||
*/
|
*/
|
||||||
public interface AsyncResult<T> {
|
public interface AsyncResult<T> {
|
||||||
@ -42,7 +43,7 @@ public interface AsyncResult<T> {
|
|||||||
* Gets the value of completed async task.
|
* Gets the value of completed async task.
|
||||||
*
|
*
|
||||||
* @return evaluated value or throws ExecutionException if execution has failed
|
* @return evaluated value or throws ExecutionException if execution has failed
|
||||||
* @throws ExecutionException if execution has failed, containing the root cause
|
* @throws ExecutionException if execution has failed, containing the root cause
|
||||||
* @throws IllegalStateException if execution is not completed
|
* @throws IllegalStateException if execution is not completed
|
||||||
*/
|
*/
|
||||||
T getValue() throws ExecutionException;
|
T getValue() throws ExecutionException;
|
||||||
|
@ -29,13 +29,13 @@ import java.util.concurrent.ExecutionException;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Implementation of async executor that creates a new thread for every task.
|
* Implementation of async executor that creates a new thread for every task.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ThreadAsyncExecutor implements AsyncExecutor {
|
public class ThreadAsyncExecutor implements AsyncExecutor {
|
||||||
|
|
||||||
/** Index for thread naming */
|
/**
|
||||||
|
* Index for thread naming.
|
||||||
|
*/
|
||||||
private final AtomicInteger idx = new AtomicInteger(0);
|
private final AtomicInteger idx = new AtomicInteger(0);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -52,12 +52,13 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
|||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
result.setException(ex);
|
result.setException(ex);
|
||||||
}
|
}
|
||||||
} , "executor-" + idx.incrementAndGet()).start();
|
}, "executor-" + idx.incrementAndGet()).start();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException {
|
public <T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException,
|
||||||
|
InterruptedException {
|
||||||
if (!asyncResult.isCompleted()) {
|
if (!asyncResult.isCompleted()) {
|
||||||
asyncResult.await();
|
asyncResult.await();
|
||||||
}
|
}
|
||||||
@ -65,8 +66,9 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple implementation of async result that allows completing it successfully with a value or exceptionally with an
|
* Simple implementation of async result that allows completing it successfully with a value or
|
||||||
* exception. A really simplified version from its real life cousins FutureTask and CompletableFuture.
|
* 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.FutureTask
|
||||||
* @see java.util.concurrent.CompletableFuture
|
* @see java.util.concurrent.CompletableFuture
|
||||||
@ -90,11 +92,10 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the value from successful execution and executes callback if available. Notifies any thread waiting for
|
* Sets the value from successful execution and executes callback if available. Notifies any
|
||||||
* completion.
|
* thread waiting for completion.
|
||||||
*
|
*
|
||||||
* @param value
|
* @param value value of the evaluated task
|
||||||
* value of the evaluated task
|
|
||||||
*/
|
*/
|
||||||
void setValue(T value) {
|
void setValue(T value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
@ -106,11 +107,10 @@ public class ThreadAsyncExecutor implements AsyncExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the exception from failed execution and executes callback if available. Notifies any thread waiting for
|
* Sets the exception from failed execution and executes callback if available. Notifies any
|
||||||
* completion.
|
* thread waiting for completion.
|
||||||
*
|
*
|
||||||
* @param exception
|
* @param exception exception of the failed task
|
||||||
* exception of the failed task
|
|
||||||
*/
|
*/
|
||||||
void setException(Exception exception) {
|
void setException(Exception exception) {
|
||||||
this.exception = exception;
|
this.exception = exception;
|
||||||
|
@ -26,9 +26,7 @@ package com.iluwatar.async.method.invocation;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Application test
|
* Application test
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class AppTest {
|
public class AppTest {
|
||||||
|
|
||||||
|
@ -23,30 +23,18 @@
|
|||||||
|
|
||||||
package com.iluwatar.async.method.invocation;
|
package com.iluwatar.async.method.invocation;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import static java.time.Duration.ofMillis;
|
||||||
import org.mockito.ArgumentCaptor;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import org.mockito.Matchers;
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import static java.time.Duration.ofMillis;
|
import org.mockito.ArgumentCaptor;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import org.mockito.Matchers;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTimeout;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
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.internal.verification.VerificationModeFactory.times;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date: 12/6/15 - 10:49 AM
|
* Date: 12/6/15 - 10:49 AM
|
||||||
@ -82,7 +70,8 @@ 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
|
@Test
|
||||||
public void testSuccessfulTaskWithCallback() throws Exception {
|
public void testSuccessfulTaskWithCallback() throws Exception {
|
||||||
@ -104,7 +93,8 @@ public class ThreadAsyncExecutorTest {
|
|||||||
verify(task, times(1)).call();
|
verify(task, times(1)).call();
|
||||||
|
|
||||||
// ... same for the callback, we expect our object
|
// ... same for the callback, we expect our object
|
||||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
|
||||||
|
ArgumentCaptor.forClass((Class) Optional.class);
|
||||||
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
|
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||||
|
|
||||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||||
@ -117,8 +107,8 @@ public class ThreadAsyncExecutorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a
|
||||||
* to execute
|
* task takes a while to execute
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testLongRunningTaskWithoutCallback() throws Exception {
|
public void testLongRunningTaskWithoutCallback() throws Exception {
|
||||||
@ -158,8 +148,8 @@ public class ThreadAsyncExecutorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable,
|
||||||
* takes a while to execute
|
* AsyncCallback)} when a task takes a while to execute
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testLongRunningTaskWithCallback() throws Exception {
|
public void testLongRunningTaskWithCallback() throws Exception {
|
||||||
@ -191,7 +181,8 @@ public class ThreadAsyncExecutorTest {
|
|||||||
// Our task should only execute once, but it can take a while ...
|
// Our task should only execute once, but it can take a while ...
|
||||||
verify(task, timeout(3000).times(1)).call();
|
verify(task, timeout(3000).times(1)).call();
|
||||||
|
|
||||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
|
||||||
|
ArgumentCaptor.forClass((Class) Optional.class);
|
||||||
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
|
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||||
|
|
||||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||||
@ -209,8 +200,9 @@ public class ThreadAsyncExecutorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a
|
||||||
* to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
|
* task takes a while to execute, while waiting on the result using {@link
|
||||||
|
* ThreadAsyncExecutor#endProcess(AsyncResult)}
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testEndProcess() throws Exception {
|
public void testEndProcess() throws Exception {
|
||||||
@ -247,7 +239,8 @@ 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
|
@Test
|
||||||
public void testNullTask() throws Exception {
|
public void testNullTask() throws Exception {
|
||||||
@ -273,8 +266,8 @@ public class ThreadAsyncExecutorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the
|
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable,
|
||||||
* callable is 'null', but the asynchronous callback is provided
|
* AsyncCallback)} when the callable is 'null', but the asynchronous callback is provided
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testNullTaskWithCallback() throws Exception {
|
public void testNullTaskWithCallback() throws Exception {
|
||||||
@ -288,7 +281,8 @@ public class ThreadAsyncExecutorTest {
|
|||||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||||
assertTrue(asyncResult.isCompleted());
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
|
||||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
final ArgumentCaptor<Optional<Exception>> optionalCaptor =
|
||||||
|
ArgumentCaptor.forClass((Class) Optional.class);
|
||||||
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
|
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
|
||||||
|
|
||||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||||
@ -312,8 +306,8 @@ public class ThreadAsyncExecutorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both
|
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable,
|
||||||
* the callable and the asynchronous callback are 'null'
|
* AsyncCallback)} when both the callable and the asynchronous callback are 'null'
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testNullTaskWithNullCallback() throws Exception {
|
public void testNullTaskWithNullCallback() throws Exception {
|
||||||
|
@ -23,23 +23,22 @@
|
|||||||
|
|
||||||
package com.iluwatar.balking;
|
package com.iluwatar.balking;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In Balking Design Pattern if an object’s method is invoked when it is in an inappropriate state,
|
* In Balking Design Pattern if an object’s method is invoked when it is in an inappropriate state,
|
||||||
* then the method will return without doing anything. Objects that use this pattern are generally only in a
|
* then the method will return without doing anything. Objects that use this pattern are generally
|
||||||
* state that is prone to balking temporarily but for an unknown amount of time
|
* only in a state that is prone to balking temporarily but for an unknown amount of time
|
||||||
*
|
*
|
||||||
* In this example implementation WashingMachine is an object that has two states
|
* <p>In this example implementation WashingMachine is an object that has two states in which it
|
||||||
* in which it can be: ENABLED and WASHING. If the machine is ENABLED
|
* can be: ENABLED and WASHING. If the machine is ENABLED the state is changed into WASHING that any
|
||||||
* the state is changed into WASHING that any other thread can't invoke this action on this and then do the job.
|
* other thread can't invoke this action on this and then do the job. On the other hand if it have
|
||||||
* On the other hand if it have been already washing and any other thread execute wash()
|
* been already washing and any other thread execute wash() it can't do that once again and returns
|
||||||
* it can't do that once again and returns doing nothing.
|
* doing nothing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class App {
|
public class App {
|
||||||
@ -47,6 +46,8 @@ public class App {
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Entry Point.
|
||||||
|
*
|
||||||
* @param args the command line arguments - not used
|
* @param args the command line arguments - not used
|
||||||
*/
|
*/
|
||||||
public static void main(String... args) {
|
public static void main(String... args) {
|
||||||
|
@ -23,13 +23,12 @@
|
|||||||
|
|
||||||
package com.iluwatar.balking;
|
package com.iluwatar.balking;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Washing machine class
|
* Washing machine class.
|
||||||
*/
|
*/
|
||||||
public class WashingMachine {
|
public class WashingMachine {
|
||||||
|
|
||||||
@ -38,7 +37,7 @@ public class WashingMachine {
|
|||||||
private WashingMachineState washingMachineState;
|
private WashingMachineState washingMachineState;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of WashingMachine
|
* Creates a new instance of WashingMachine.
|
||||||
*/
|
*/
|
||||||
public WashingMachine() {
|
public WashingMachine() {
|
||||||
this((interval, timeUnit, task) -> {
|
this((interval, timeUnit, task) -> {
|
||||||
@ -52,8 +51,8 @@ public class WashingMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance of WashingMachine using provided delayProvider. This constructor is used only for
|
* Creates a new instance of WashingMachine using provided delayProvider. This constructor is used
|
||||||
* unit testing purposes.
|
* only for unit testing purposes.
|
||||||
*/
|
*/
|
||||||
public WashingMachine(DelayProvider delayProvider) {
|
public WashingMachine(DelayProvider delayProvider) {
|
||||||
this.delayProvider = delayProvider;
|
this.delayProvider = delayProvider;
|
||||||
@ -65,17 +64,17 @@ public class WashingMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method responsible for washing
|
* Method responsible for washing if the object is in appropriate state.
|
||||||
* if the object is in appropriate state
|
|
||||||
*/
|
*/
|
||||||
public void wash() {
|
public void wash() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), getWashingMachineState());
|
WashingMachineState machineState = getWashingMachineState();
|
||||||
if (washingMachineState == WashingMachineState.WASHING) {
|
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
|
||||||
|
if (this.washingMachineState == WashingMachineState.WASHING) {
|
||||||
LOGGER.error("ERROR: Cannot wash if the machine has been already washing!");
|
LOGGER.error("ERROR: Cannot wash if the machine has been already washing!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
washingMachineState = WashingMachineState.WASHING;
|
this.washingMachineState = WashingMachineState.WASHING;
|
||||||
}
|
}
|
||||||
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
|
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
|
||||||
|
|
||||||
@ -83,8 +82,7 @@ public class WashingMachine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method responsible of ending the washing
|
* Method responsible of ending the washing by changing machine state.
|
||||||
* by changing machine state
|
|
||||||
*/
|
*/
|
||||||
public synchronized void endOfWashing() {
|
public synchronized void endOfWashing() {
|
||||||
washingMachineState = WashingMachineState.ENABLED;
|
washingMachineState = WashingMachineState.ENABLED;
|
||||||
|
@ -24,10 +24,9 @@
|
|||||||
package com.iluwatar.balking;
|
package com.iluwatar.balking;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WashingMachineState enum describes in which state machine is,
|
* WashingMachineState enum describes in which state machine is, it can be enabled and ready to work
|
||||||
* it can be enabled and ready to work as well as during washing
|
* as well as during washing.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public enum WashingMachineState {
|
public enum WashingMachineState {
|
||||||
ENABLED, WASHING
|
ENABLED, WASHING
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,10 @@
|
|||||||
|
|
||||||
package com.iluwatar.balking;
|
package com.iluwatar.balking;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link WashingMachine}
|
* Tests for {@link WashingMachine}
|
||||||
|
@ -27,25 +27,25 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Composition over inheritance. The Bridge pattern can also be thought of as two layers of
|
||||||
* Composition over inheritance. The Bridge pattern can also be thought of as two layers of abstraction.
|
* abstraction. With Bridge, you can decouple an abstraction from its implementation so that the two
|
||||||
* With Bridge, you can decouple an abstraction from its implementation so that the two can vary independently.
|
* can vary independently.
|
||||||
* <p>
|
*
|
||||||
* In Bridge pattern both abstraction ({@link Weapon}) and implementation (
|
* <p>In Bridge pattern both abstraction ({@link Weapon}) and implementation ( {@link Enchantment})
|
||||||
* {@link Enchantment}) have their own class hierarchies. The interface of the implementations
|
* have their own class hierarchies. The interface of the implementations can be changed without
|
||||||
* can be changed without affecting the clients.
|
* affecting the clients.
|
||||||
* <p>
|
*
|
||||||
* In this example we have two class hierarchies. One of weapons and another one of enchantments. We can easily
|
* <p>In this example we have two class hierarchies. One of weapons and another one of
|
||||||
* combine any weapon with any enchantment using composition instead of creating deep class hierarchy.
|
* enchantments. We can easily combine any weapon with any enchantment using composition instead of
|
||||||
*
|
* creating deep class hierarchy.
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point
|
* Program entry point.
|
||||||
*
|
*
|
||||||
* @param args command line args
|
* @param args command line args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.bridge;
|
package com.iluwatar.bridge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Enchantment.
|
||||||
* Enchantment
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface Enchantment {
|
public interface Enchantment {
|
||||||
|
|
||||||
|
@ -27,9 +27,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* FlyingEnchantment.
|
||||||
* FlyingEnchantment
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class FlyingEnchantment implements Enchantment {
|
public class FlyingEnchantment implements Enchantment {
|
||||||
|
|
||||||
|
@ -27,9 +27,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Hammer.
|
||||||
* Hammer
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class Hammer implements Weapon {
|
public class Hammer implements Weapon {
|
||||||
|
|
||||||
|
@ -27,9 +27,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* SoulEatingEnchantment.
|
||||||
* SoulEatingEnchantment
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class SoulEatingEnchantment implements Enchantment {
|
public class SoulEatingEnchantment implements Enchantment {
|
||||||
|
|
||||||
|
@ -27,9 +27,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Sword.
|
||||||
* Sword
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class Sword implements Weapon {
|
public class Sword implements Weapon {
|
||||||
|
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.bridge;
|
package com.iluwatar.bridge;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Weapon.
|
||||||
* Weapon
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public interface Weapon {
|
public interface Weapon {
|
||||||
|
|
||||||
|
@ -28,36 +28,33 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* The intention of the Builder pattern is to find a solution to the telescoping constructor
|
* The intention of the Builder pattern is to find a solution to the telescoping constructor
|
||||||
* anti-pattern. The telescoping constructor anti-pattern occurs when the increase of object
|
* anti-pattern. The telescoping constructor anti-pattern occurs when the increase of object
|
||||||
* constructor parameter combination leads to an exponential list of constructors. Instead of using
|
* constructor parameter combination leads to an exponential list of constructors. Instead of using
|
||||||
* numerous constructors, the builder pattern uses another object, a builder, that receives each
|
* numerous constructors, the builder pattern uses another object, a builder, that receives each
|
||||||
* initialization parameter step by step and then returns the resulting constructed object at once.
|
* initialization parameter step by step and then returns the resulting constructed object at once.
|
||||||
* <p>
|
*
|
||||||
* The Builder pattern has another benefit. It can be used for objects that contain flat data (html
|
* <p>The Builder pattern has another benefit. It can be used for objects that contain flat data
|
||||||
* code, SQL query, X.509 certificate...), that is to say, data that can't be easily edited. This
|
* (html code, SQL query, X.509 certificate...), that is to say, data that can't be easily edited.
|
||||||
* type of data cannot be edited step by step and must be edited at once. The best way to construct
|
* This type of data cannot be edited step by step and must be edited at once. The best way to
|
||||||
* such an object is to use a builder class.
|
* construct such an object is to use a builder class.
|
||||||
* <p>
|
*
|
||||||
* In this example we have the Builder pattern variation as described by Joshua Bloch in Effective
|
* <p>In this example we have the Builder pattern variation as described by Joshua Bloch in
|
||||||
* Java 2nd Edition.
|
* Effective Java 2nd Edition.
|
||||||
* <p>
|
*
|
||||||
* We want to build {@link Hero} objects, but its construction is complex because of the many
|
* <p>We want to build {@link Hero} objects, but its construction is complex because of the many
|
||||||
* parameters needed. To aid the user we introduce {@link Builder} class. {@link Hero.Builder}
|
* parameters needed. To aid the user we introduce {@link Builder} class. {@link Hero.Builder} takes
|
||||||
* takes the minimum parameters to build {@link Hero} object in its constructor. After that
|
* the minimum parameters to build {@link Hero} object in its constructor. After that additional
|
||||||
* additional configuration for the {@link Hero} object can be done using the fluent
|
* configuration for the {@link Hero} object can be done using the fluent {@link Builder} interface.
|
||||||
* {@link Builder} interface. When configuration is ready the build method is called to receive
|
* When configuration is ready the build method is called to receive the final {@link Hero} object.
|
||||||
* the final {@link Hero} object.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class App {
|
public class App {
|
||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point
|
* Program entry point.
|
||||||
*
|
*
|
||||||
* @param args command line args
|
* @param args command line args
|
||||||
*/
|
*/
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Armor enumeration.
|
||||||
* Armor enumeration
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum Armor {
|
public enum Armor {
|
||||||
|
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* HairColor enumeration.
|
||||||
* HairColor enumeration
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum HairColor {
|
public enum HairColor {
|
||||||
|
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* HairType enumeration.
|
||||||
* HairType enumeration
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum HairType {
|
public enum HairType {
|
||||||
|
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* Hero, the class with many parameters.
|
* Hero, the class with many parameters.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public final class Hero {
|
public final class Hero {
|
||||||
|
|
||||||
@ -75,9 +73,9 @@ public final class Hero {
|
|||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("This is a ")
|
sb.append("This is a ")
|
||||||
.append(profession)
|
.append(profession)
|
||||||
.append(" named ")
|
.append(" named ")
|
||||||
.append(name);
|
.append(name);
|
||||||
if (hairColor != null || hairType != null) {
|
if (hairColor != null || hairType != null) {
|
||||||
sb.append(" with ");
|
sb.append(" with ");
|
||||||
if (hairColor != null) {
|
if (hairColor != null) {
|
||||||
@ -99,9 +97,7 @@ public final class Hero {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* The builder class.
|
* The builder class.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
|
|
||||||
@ -113,7 +109,7 @@ public final class Hero {
|
|||||||
private Weapon weapon;
|
private Weapon weapon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor.
|
||||||
*/
|
*/
|
||||||
public Builder(Profession profession, String name) {
|
public Builder(Profession profession, String name) {
|
||||||
if (profession == null || name == null) {
|
if (profession == null || name == null) {
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Profession enumeration.
|
||||||
* Profession enumeration
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum Profession {
|
public enum Profession {
|
||||||
|
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Weapon enumeration.
|
||||||
* Weapon enumeration
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public enum Weapon {
|
public enum Weapon {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user