Work on #74, Merged from master

This commit is contained in:
Narendra Pathai 2015-09-12 15:03:02 +05:30
commit aebd69efb4
18 changed files with 1208 additions and 87 deletions

View File

@ -3,12 +3,18 @@ language: java
jdk:
- oraclejdk8
env:
global:
- GH_REF: github.com/iluwatar/java-design-patterns.git
- secure: "LxTDuNS/rBWIvKkaEqr79ImZAe48mCdoYCF41coxNXgNoippo4GIBArknqtv+XvdkiuRZ1yGyj6pn8GU33c/yn+krddTUkVCwTbVatbalW5jhQjDbHYym/JcxaK9ZS/3JTeGcWrBgiPqHEEDhCf26vPZsXoMSeVCEORVKTp1BSg="
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
after_success:
- mvn clean test jacoco:report coveralls:report
- bash update-ghpages.sh
# Migration to container-based infrastructure
sudo: false

View File

@ -4,25 +4,12 @@
# Design pattern samples in Java
[![Build status](https://travis-ci.org/iluwatar/java-design-patterns.svg?branch=master)](https://travis-ci.org/iluwatar/java-design-patterns)
[![Coverage Status](https://coveralls.io/repos/iluwatar/java-design-patterns/badge.svg?branch=master)](https://coveralls.io/r/iluwatar/java-design-patterns?branch=master)
[![Coverity Scan Build Status](https://scan.coverity.com/projects/5634/badge.svg)](https://scan.coverity.com/projects/5634)
[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build status](https://travis-ci.org/iluwatar/java-design-patterns.svg?branch=master)](https://travis-ci.org/iluwatar/java-design-patterns) [![Coverage Status](https://coveralls.io/repos/iluwatar/java-design-patterns/badge.svg?branch=master)](https://coveralls.io/r/iluwatar/java-design-patterns?branch=master) <a href="https://scan.coverity.com/projects/5634">
<img alt="Coverity Scan Build Status"
src="https://scan.coverity.com/projects/5634/badge.svg"/>
</a>
<a name="top"/>
# <a name="toc">Table of Contents</a>
- <a href="#introduction">Introduction</a>
- <a href="#contribute">How to contribute</a>
- <a href="#faq">Frequently Asked Questions</a>
- <a href="#credits">Credits</a>
- <a href="#license">License</a>
# <a name="introduction">Introduction</a> [&#8593;](#top)
# Introduction
Design patterns are formalized best practices that the programmer can use to
solve common problems when designing an application or system.
@ -34,72 +21,22 @@ Reusing design patterns helps to prevent subtle issues that can cause major
problems, and it also improves code readability for coders and architects who
are familiar with the patterns.
# Getting started
# <a name="contribute">How to contribute</a> [&#8593;](#top)
Before you dive into the material, you should be familiar with various
[Programming/Software Design Principles](http://webpro.github.io/programming-principles/).
Once you are familiar with these concepts you can start drilling down into patterns by any of the following approaches
- Using difficulty tags, `Difficulty-Beginner`, `Difficulty-Intermediate` & `Difficulty-Expert`.
- Using pattern categories, `Creational`, `Behavioral` and others.
- Search for a specific pattern. Can't find one? Please report a new pattern [here](https://github.com/iluwatar/java-design-patterns/issues).
# 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).
# <a name="faq">Frequently asked questions</a> [&#8593;](#top)
**<a id="Q1">Q: What is the difference between State and Strategy patterns?</a>**
While the implementation is similar they solve different problems. The State
pattern deals with what state an object is in - it encapsulates state-dependent
behavior.
The Strategy pattern deals with how an object performs a certain task - it
encapsulates an algorithm.
**<a id="Q2">Q: What is the difference between Strategy and Template Method patterns?</a>**
In Template Method the algorithm is chosen at compile time via inheritance.
With Strategy pattern the algorithm is chosen at runtime via composition.
**<a id="Q3">Q: What is the difference between Proxy and Decorator patterns?</a>**
The difference is the intent of the patterns. While Proxy controls access to
the object Decorator is used to add responsibilities to the object.
**<a id="Q4">Q: What is the difference between Chain of Responsibility and Intercepting Filter patterns?</a>**
While the implementations look similar there are differences. The Chain of
Responsibility forms a chain of request processors and the processors are then
executed one by one until the correct processor is found. In Intercepting
Filter the chain is constructed from filters and the whole chain is always
executed.
**<a id="Q5">Q: What is the difference between Visitor and Double Dispatch patterns?</a>**
The Visitor pattern is a means of adding a new operation to existing classes.
Double dispatch is a means of dispatching function calls with respect to two
polymorphic types, rather than a single polymorphic type, which is what
languages like C++ and Java _do not_ support directly.
**<a id="Q6">Q: What are the differences between Flyweight and Object Pool patterns?</a>**
They differ in the way they are used.
Pooled objects can simultaneously be used by a single "client" only. For that,
a pooled object must be checked out from the pool, then it can be used by a
client, and then the client must return the object back to the pool. Multiple
instances of identical objects may exist, up to the maximal capacity of the
pool.
In contrast, a Flyweight object is singleton, and it can be used simultaneously
by multiple clients.
As for concurrent access, pooled objects can be mutable and they usually don't
need to be thread safe, as typically, only one thread is going to use a
specific instance at the same time. Flyweight must either be immutable (the
best option), or implement thread safety.
As for performance and scalability, pools can become bottlenecks, if all the
pooled objects are in use and more clients need them, threads will become
blocked waiting for available object from the pool. This is not the case with
Flyweight.
# <a name="credits">Credits</a> [&#8593;](#top)
# Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
* [Effective Java (2nd Edition)](http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683)
@ -113,7 +50,6 @@ Flyweight.
* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2)
* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697)
# <a name="license">License</a> [&#8593;](#top)
# License
This project is licensed under the terms of the MIT license.

208
checkstyle.xml Normal file
View File

@ -0,0 +1,208 @@
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<!--
Source = https://github.com/checkstyle/checkstyle/tree/master/src/main/resources
Checkstyle configurartion that checks the Google coding conventions from:
- Google Java Style
https://google-styleguide.googlecode.com/svn-history/r130/trunk/javaguide.html
Checkstyle is very configurable. Be sure to read the documentation at
http://checkstyle.sf.net (or in your downloaded distribution).
Most Checks are configurable, be sure to consult the documentation.
To completely disable a check, just comment it out or delete it from the file.
Authors: Max Vetrenko, Ruslan Diachenko, Roman Ivanov.
-->
<module name="Checker">
<property name="charset" value="UTF-8"/>
<property name="severity" value="warning"/>
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="FileTabCharacter">
<property name="eachLine" value="true"/>
</module>
<module name="TreeWalker">
<module name="OuterTypeFilename"/>
<module name="IllegalTokenText">
<property name="tokens" value="STRING_LITERAL, CHAR_LITERAL"/>
<property name="format"
value="\\u00(08|09|0(a|A)|0(c|C)|0(d|D)|22|27|5(C|c))|\\(0(10|11|12|14|15|42|47)|134)"/>
<property name="message" value="Avoid using corresponding octal or Unicode escape."/>
</module>
<module name="AvoidEscapedUnicodeCharacters">
<property name="allowEscapesForControlCharacters" value="true"/>
<property name="allowByTailComment" value="true"/>
<property name="allowNonPrintableEscapes" value="true"/>
</module>
<module name="LineLength">
<property name="max" value="100"/>
<property name="ignorePattern" value="^package.*|^import.*|a href|href|http://|https://|ftp://"/>
</module>
<module name="AvoidStarImport"/>
<module name="OneTopLevelClass"/>
<module name="NoLineWrap"/>
<module name="EmptyBlock">
<property name="option" value="TEXT"/>
<property name="tokens"
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
</module>
<module name="NeedBraces"/>
<module name="LeftCurly">
<property name="maxLineLength" value="100"/>
</module>
<module name="RightCurly"/>
<module name="RightCurly">
<property name="option" value="alone"/>
<property name="tokens"
value="CLASS_DEF, METHOD_DEF, CTOR_DEF, LITERAL_FOR, LITERAL_WHILE, LITERAL_DO, STATIC_INIT, INSTANCE_INIT"/>
</module>
<module name="WhitespaceAround">
<property name="allowEmptyConstructors" value="true"/>
<property name="allowEmptyMethods" value="true"/>
<property name="allowEmptyTypes" value="true"/>
<property name="allowEmptyLoops" value="true"/>
<message key="ws.notFollowed"
value="WhitespaceAround: ''{0}'' is not followed by whitespace."/>
<message key="ws.notPreceded"
value="WhitespaceAround: ''{0}'' is not preceded with whitespace."/>
</module>
<module name="OneStatementPerLine"/>
<module name="MultipleVariableDeclarations"/>
<module name="ArrayTypeStyle"/>
<module name="MissingSwitchDefault"/>
<module name="FallThrough"/>
<module name="UpperEll"/>
<module name="ModifierOrder"/>
<module name="EmptyLineSeparator">
<property name="allowNoEmptyLineBetweenFields" value="true"/>
</module>
<module name="SeparatorWrap">
<property name="tokens" value="DOT"/>
<property name="option" value="nl"/>
</module>
<module name="SeparatorWrap">
<property name="tokens" value="COMMA"/>
<property name="option" value="EOL"/>
</module>
<module name="PackageName">
<property name="format" value="^[a-z]+(\.[a-z][a-z0-9]*)*$"/>
<message key="name.invalidPattern"
value="Package name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="TypeName">
<message key="name.invalidPattern"
value="Type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MemberName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Member name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ParameterName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<message key="name.invalidPattern"
value="Parameter name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="LocalVariableName">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9]*$"/>
<property name="allowOneCharVarInForLoop" value="true"/>
<message key="name.invalidPattern"
value="Local variable name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="ClassTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Class type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="MethodTypeParameterName">
<property name="format" value="(^[A-Z][0-9]?)$|([A-Z][a-zA-Z0-9]*[T]$)"/>
<message key="name.invalidPattern"
value="Method type name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="NoFinalizer"/>
<module name="GenericWhitespace">
<message key="ws.followed"
value="GenericWhitespace ''{0}'' is followed by whitespace."/>
<message key="ws.preceded"
value="GenericWhitespace ''{0}'' is preceded with whitespace."/>
<message key="ws.illegalFollow"
value="GenericWhitespace ''{0}'' should followed by whitespace."/>
<message key="ws.notPreceded"
value="GenericWhitespace ''{0}'' is not preceded with whitespace."/>
</module>
<module name="Indentation">
<property name="basicOffset" value="2"/>
<property name="braceAdjustment" value="0"/>
<property name="caseIndent" value="2"/>
<property name="throwsIndent" value="4"/>
<property name="lineWrappingIndentation" value="4"/>
<property name="arrayInitIndent" value="2"/>
</module>
<module name="AbbreviationAsWordInName">
<property name="ignoreFinal" value="false"/>
<property name="allowedAbbreviationLength" value="1"/>
</module>
<module name="OverloadMethodsDeclarationOrder"/>
<module name="VariableDeclarationUsageDistance"/>
<module name="CustomImportOrder">
<property name="thirdPartyPackageRegExp" value=".*"/>
<property name="specialImportsRegExp" value="com.google"/>
<property name="sortImportsInGroupAlphabetically" value="true"/>
<property name="customImportOrderRules"
value="STATIC###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE###STANDARD_JAVA_PACKAGE"/>
</module>
<module name="MethodParamPad"/>
<module name="OperatorWrap">
<property name="option" value="NL"/>
<property name="tokens"
value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR "/>
</module>
<module name="AnnotationLocation">
<property name="tokens" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF"/>
</module>
<module name="AnnotationLocation">
<property name="tokens" value="VARIABLE_DEF"/>
<property name="allowSamelineMultipleAnnotations" value="true"/>
</module>
<module name="NonEmptyAtclauseDescription"/>
<module name="JavadocTagContinuationIndentation"/>
<module name="SummaryJavadocCheck">
<property name="forbiddenSummaryFragments"
value="^@return the *|^This method returns |^A [{]@code [a-zA-Z0-9]+[}]( is a )"/>
</module>
<module name="JavadocParagraph"/>
<module name="AtclauseOrder">
<property name="tagOrder" value="@param, @return, @throws, @deprecated"/>
<property name="target" value="CLASS_DEF, INTERFACE_DEF, ENUM_DEF, METHOD_DEF, CTOR_DEF, VARIABLE_DEF"/>
</module>
<module name="JavadocMethod">
<property name="scope" value="public"/>
<property name="allowMissingParamTags" value="true"/>
<property name="allowMissingThrowsTags" value="true"/>
<property name="allowMissingReturnTag" value="true"/>
<property name="minLineCount" value="2"/>
<property name="allowedAnnotations" value="Override, Test"/>
<property name="allowThrowsTagsForSubclasses" value="true"/>
</module>
<module name="MethodName">
<property name="format" value="^[a-z][a-z0-9][a-zA-Z0-9_]*$"/>
<message key="name.invalidPattern"
value="Method name ''{0}'' must match pattern ''{1}''."/>
</module>
<module name="SingleLineJavadoc"/>
</module>
</module>

View File

@ -4,7 +4,9 @@ title: Factory Method
folder: factory-method
permalink: /patterns/factory-method/
categories: Creational
tags: Java
tags:
- Java
- Difficulty-Beginner
---
**Intent:** Define an interface for creating an object, but let subclasses

67
faq.md Normal file
View File

@ -0,0 +1,67 @@
---
layout: page
title: FAQ
permalink: /faq/
icon: fa-question
page-index: 2
---
### Q1: What is the difference between State and Strategy patterns? {#Q1}
While the implementation is similar they solve different problems. The State
pattern deals with what state an object is in - it encapsulates state-dependent
behavior.
The Strategy pattern deals with how an object performs a certain task - it
encapsulates an algorithm.
### Q2: What is the difference between Strategy and Template Method patterns? {#Q2}
In Template Method the algorithm is chosen at compile time via inheritance.
With Strategy pattern the algorithm is chosen at runtime via composition.
### Q3: What is the difference between Proxy and Decorator patterns? {#Q3}
The difference is the intent of the patterns. While Proxy controls access to
the object Decorator is used to add responsibilities to the object.
### Q4: What is the difference between Chain of Responsibility and Intercepting Filter patterns? {#Q4}
While the implementations look similar there are differences. The Chain of
Responsibility forms a chain of request processors and the processors are then
executed one by one until the correct processor is found. In Intercepting
Filter the chain is constructed from filters and the whole chain is always
executed.
### Q5: What is the difference between Visitor and Double Dispatch patterns? {#Q5}
The Visitor pattern is a means of adding a new operation to existing classes.
Double dispatch is a means of dispatching function calls with respect to two
polymorphic types, rather than a single polymorphic type, which is what
languages like C++ and Java _do not_ support directly.
### Q6: What are the differences between Flyweight and Object Pool patterns? {#Q6}
They differ in the way they are used.
Pooled objects can simultaneously be used by a single "client" only. For that,
a pooled object must be checked out from the pool, then it can be used by a
client, and then the client must return the object back to the pool. Multiple
instances of identical objects may exist, up to the maximal capacity of the
pool.
In contrast, a Flyweight object is singleton, and it can be used simultaneously
by multiple clients.
As for concurrent access, pooled objects can be mutable and they usually don't
need to be thread safe, as typically, only one thread is going to use a
specific instance at the same time. Flyweight must either be immutable (the
best option), or implement thread safety.
As for performance and scalability, pools can become bottlenecks, if all the
pooled objects are in use and more clients need them, threads will become
blocked waiting for available object from the pool. This is not the case with
Flyweight.
### Q7: What are the differences between FluentInterface and Builder patterns? {#Q7}
Fluent interfaces are sometimes confused with the Builder pattern, because they share method chaining and a fluent usage. However, fluent interfaces are not primarily used to create shared (mutable) objects, but to configure complex objects without having to respecify the target object on every property change.

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<class-diagram version="1.1.8" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
realizations="true" associations="true" dependencies="false" nesting-relationships="true">
<class id="1" language="java" name="com.iluwatar.fluentinterface.App" project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/App.java" binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="289" y="-8"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="false" protected="false" private="false" static="false"/>
<operations public="true" package="true" protected="true" private="false" static="true"/>
</display>
</class>
<class id="2" language="java" name="com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="450" y="430"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<class id="3" language="java" name="com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="860" y="391"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="4" language="java" name="com.iluwatar.fluentinterface.fluentiterable.FluentIterable"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java" binary="false"
corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="794" y="55"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<class id="5" language="java" name="com.iluwatar.fluentinterface.fluentiterable.lazy.DecoratingIterator"
project="fluentinterface"
file="/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java"
binary="false" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="1245" y="391"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</class>
<interface id="6" language="java" name="java.lang.Iterable" project="fluentinterface"
file="/opt/Softwares/Eclipses/MARS/eclipse/jre/lib/rt.jar" binary="true" corner="BOTTOM_RIGHT">
<position height="-1" width="-1" x="793" y="-163"/>
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</display>
</interface>
<dependency id="7">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="2"/>
</dependency>
<realization id="8">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="4"/>
</realization>
<dependency id="9">
<end type="SOURCE" refId="3"/>
<end type="TARGET" refId="5"/>
</dependency>
<generalization id="10">
<end type="SOURCE" refId="4"/>
<end type="TARGET" refId="6"/>
</generalization>
<dependency id="11">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="3"/>
</dependency>
<dependency id="12">
<end type="SOURCE" refId="1"/>
<end type="TARGET" refId="4"/>
</dependency>
<realization id="13">
<end type="SOURCE" refId="2"/>
<end type="TARGET" refId="4"/>
</realization>
<classifier-display autosize="true" stereotype="true" package="true" initial-value="true" signature="true"
sort-features="false" accessors="true" visibility="true">
<attributes public="true" package="true" protected="true" private="true" static="true"/>
<operations public="true" package="true" protected="true" private="true" static="true"/>
</classifier-display>
<association-display labels="true" multiplicity="true"/>
</class-diagram>

42
fluentinterface/index.md Normal file
View File

@ -0,0 +1,42 @@
---
layout: pattern
title: Fluent Interface
folder: fluentinterface
permalink: /patterns/fluentinterface/
categories: Other
tags:
- Java
- Difficulty-Intermediate
---
**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:**
A fluent interface can be implemented using any of
* Method Chaining - calling a method returns some object on which further methods can be called.
* Static Factory Methods and Imports
* Named parameters - can be simulated in Java using static factory methods.
![Fluent Interface](./etc/fluentinterface.png "Fluent Interface")
**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:**
* [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)
* [JOOQ](http://www.jooq.org/doc/3.0/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/)
* [Mockito](http://mockito.org/)
* [Java Hamcrest](http://code.google.com/p/hamcrest/wiki/Tutorial)
**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/)
* [Internal DSL](http://www.infoq.com/articles/internal-dsls-java)

20
fluentinterface/pom.xml Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>java-design-patterns</artifactId>
<groupId>com.iluwatar</groupId>
<version>1.6.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fluentinterface</artifactId>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,103 @@
package com.iluwatar.fluentinterface;
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;
/**
* 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
* languages.
* <p>
* In this example two implementations of a {@link FluentIterable} interface are given. The
* SimpleFluentIterable evaluates eagerly and would be too costly for real world applications. The
* LazyFluentIterable is evaluated on termination. Their usage is demonstrated with a simple number
* list that is filtered, transformed and collected. The result is printed afterwards.
* <p>
*/
public class App {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>();
integerList.addAll(Arrays.asList(
1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97,
45, 23, 2, -68, 45
));
prettyPrint("The initial list contains: ", integerList);
List<Integer> firstFiveNegatives =
SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).first(3).asList();
prettyPrint("The first three negative values are: ", firstFiveNegatives);
List<Integer> lastTwoPositives =
SimpleFluentIterable.fromCopyOf(integerList).filter(positives()).last(2).asList();
prettyPrint("The last two positive values are: ", lastTwoPositives);
SimpleFluentIterable
.fromCopyOf(integerList)
.filter(number -> number % 2 == 0)
.first()
.ifPresent(
evenNumber -> System.out.println(String.format("The first even number is: %d",
evenNumber)));
List<String> transformedList =
SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).map(transformToString())
.asList();
prettyPrint("A string-mapped list of negative numbers contains: ", transformedList);
List<String> lastTwoOfFirstFourStringMapped =
LazyFluentIterable.from(integerList).filter(positives()).first(4).last(2)
.map(number -> "String[" + String.valueOf(number) + "]").asList();
prettyPrint(
"The lazy list contains the last two of the first four positive numbers mapped to Strings: ",
lastTwoOfFirstFourStringMapped);
LazyFluentIterable
.from(integerList)
.filter(negatives())
.first(2)
.last()
.ifPresent(
lastOfFirstTwo -> System.out.println(String.format(
"The last of the first two negatives is: %d", lastOfFirstTwo)));
}
private static Function<Integer, String> transformToString() {
return integer -> "String[" + valueOf(integer) + "]";
}
private static Predicate<? super Integer> negatives() {
return integer -> (integer < 0);
}
private static Predicate<? super Integer> positives() {
return integer -> (integer > 0);
}
private static <TYPE> void prettyPrint(String prefix, Iterable<TYPE> iterable) {
prettyPrint(", ", prefix, ".", iterable);
}
private static <TYPE> void prettyPrint(String delimiter, String prefix, String suffix,
Iterable<TYPE> iterable) {
StringJoiner joiner = new StringJoiner(delimiter, prefix, ".");
Iterator<TYPE> iterator = iterable.iterator();
while (iterator.hasNext()) {
joiner.add(iterator.next().toString());
}
System.out.println(joiner);
}
}

View File

@ -0,0 +1,89 @@
package com.iluwatar.fluentinterface.fluentiterable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* The FluentIterable is a more convenient implementation of the common iterable interface based on
* the fluent interface design pattern. This interface defines common operations, but doesn't aim to
* be complete. It was inspired by Guava's com.google.common.collect.FluentIterable.
*
* @param <TYPE> is the class of objects the iterable contains
*/
public interface FluentIterable<TYPE> extends Iterable<TYPE> {
/**
* Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
* the predicate.
*
* @param predicate the condition to test with for the filtering. If the test is negative, the
* tested object is removed by the iterator.
* @return a filtered FluentIterable
*/
FluentIterable<TYPE> filter(Predicate<? super TYPE> predicate);
/**
* Returns an Optional containing the first element of this iterable if present, else returns
* Optional.empty().
*
* @return the first element after the iteration is evaluated
*/
Optional<TYPE> first();
/**
* Evaluates the iteration and leaves only the count first elements.
*
* @return the first count elements as an Iterable
*/
FluentIterable<TYPE> first(int count);
/**
* Evaluates the iteration and returns the last element. This is a terminating operation.
*
* @return the last element after the iteration is evaluated
*/
Optional<TYPE> last();
/**
* Evaluates the iteration and leaves only the count last elements.
*
* @return the last counts elements as an Iterable
*/
FluentIterable<TYPE> last(int count);
/**
* Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE.
*
* @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE
* @param <NEW_TYPE> the target type of the transformation
* @return a new FluentIterable of the new type
*/
<NEW_TYPE> FluentIterable<NEW_TYPE> map(Function<? super TYPE, NEW_TYPE> function);
/**
* Returns the contents of this Iterable as a List.
*
* @return a List representation of this Iterable
*/
List<TYPE> asList();
/**
* Utility method that iterates over iterable and adds the contents to a list.
*
* @param iterable the iterable to collect
* @param <TYPE> the type of the objects to iterate
* @return a list with all objects of the given iterator
*/
static <TYPE> List<TYPE> copyToList(Iterable<TYPE> iterable) {
ArrayList<TYPE> copy = new ArrayList<>();
Iterator<TYPE> iterator = iterable.iterator();
while (iterator.hasNext()) {
copy.add(iterator.next());
}
return copy;
}
}

View File

@ -0,0 +1,60 @@
package com.iluwatar.fluentinterface.fluentiterable.lazy;
import java.util.Iterator;
/**
* This class is used to realize LazyFluentIterables. It decorates a given iterator. Does not
* support consecutive hasNext() calls.
*
* @param <TYPE>
*/
public abstract class DecoratingIterator<TYPE> implements Iterator<TYPE> {
protected final Iterator<TYPE> fromIterator;
private TYPE next = null;
/**
* Creates an iterator that decorates the given iterator.
*
* @param fromIterator
*/
public DecoratingIterator(Iterator<TYPE> fromIterator) {
this.fromIterator = fromIterator;
}
/**
* Precomputes and saves the next element of the Iterable. null is considered as end of data.
*
* @return true if a next element is available
*/
@Override
public final boolean hasNext() {
next = computeNext();
return next != null;
}
/**
* Returns the next element of the Iterable.
*
* @return the next element of the Iterable, or null if not present.
*/
@Override
public final TYPE next() {
if (next == null) {
return fromIterator.next();
} else {
final TYPE result = next;
next = null;
return result;
}
}
/**
* Computes the next object of the Iterable. Can be implemented to realize custom behaviour for an
* iteration process. null is considered as end of data.
*
* @return the next element of the Iterable.
*/
public abstract TYPE computeNext();
}

View File

@ -0,0 +1,230 @@
package com.iluwatar.fluentinterface.fluentiterable.lazy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
/**
* This is a lazy implementation of the FluentIterable interface. It evaluates all chained
* operations when a terminating operation is applied.
*
* @param <TYPE> the type of the objects the iteration is about
*/
public class LazyFluentIterable<TYPE> implements FluentIterable<TYPE> {
private final Iterable<TYPE> iterable;
/**
* This constructor creates a new LazyFluentIterable. It wraps the given iterable.
*
* @param iterable the iterable this FluentIterable works on.
*/
protected LazyFluentIterable(Iterable<TYPE> iterable) {
this.iterable = iterable;
}
/**
* This constructor can be used to implement anonymous subclasses of the LazyFluentIterable.
*/
protected LazyFluentIterable() {
iterable = this;
}
/**
* Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
* the predicate.
*
* @param predicate the condition to test with for the filtering. If the test is negative, the
* tested object is removed by the iterator.
* @return a new FluentIterable object that decorates the source iterable
*/
@Override
public FluentIterable<TYPE> filter(Predicate<? super TYPE> predicate) {
return new LazyFluentIterable<TYPE>() {
@Override
public Iterator<TYPE> iterator() {
return new DecoratingIterator<TYPE>(iterable.iterator()) {
@Override
public TYPE computeNext() {
while (fromIterator.hasNext()) {
TYPE candidate = fromIterator.next();
if (!predicate.test(candidate)) {
continue;
}
return candidate;
}
return null;
}
};
}
};
}
/**
* Can be used to collect objects from the iteration. Is a terminating operation.
*
* @return an Optional containing the first object of this Iterable
*/
@Override
public Optional<TYPE> first() {
Iterator<TYPE> resultIterator = first(1).iterator();
return resultIterator.hasNext() ? Optional.of(resultIterator.next()) : Optional.empty();
}
/**
* Can be used to collect objects from the iteration.
*
* @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' first
* objects.
*/
@Override
public FluentIterable<TYPE> first(int count) {
return new LazyFluentIterable<TYPE>() {
@Override
public Iterator<TYPE> iterator() {
return new DecoratingIterator<TYPE>(iterable.iterator()) {
int currentIndex = 0;
@Override
public TYPE computeNext() {
if (currentIndex < count) {
if (fromIterator.hasNext()) {
TYPE candidate = fromIterator.next();
currentIndex++;
return candidate;
}
}
return null;
}
};
}
};
}
/**
* Can be used to collect objects from the iteration. Is a terminating operation.
*
* @return an Optional containing the last object of this Iterable
*/
@Override
public Optional<TYPE> last() {
Iterator<TYPE> resultIterator = last(1).iterator();
return resultIterator.hasNext() ? Optional.of(resultIterator.next()) : Optional.empty();
}
/**
* Can be used to collect objects from the Iterable. Is a terminating operation. This operation is
* memory intensive, because the contents of this Iterable are collected into a List, when the
* next object is requested.
*
* @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' last
* objects
*/
@Override
public FluentIterable<TYPE> last(int count) {
return new LazyFluentIterable<TYPE>() {
@Override
public Iterator<TYPE> iterator() {
return new DecoratingIterator<TYPE>(iterable.iterator()) {
private int stopIndex;
private int totalElementsCount;
private List<TYPE> list;
private int currentIndex = 0;
@Override
public TYPE computeNext() {
initialize();
TYPE candidate = null;
while (currentIndex < stopIndex && fromIterator.hasNext()) {
currentIndex++;
fromIterator.next();
}
if (currentIndex >= stopIndex && fromIterator.hasNext()) {
candidate = fromIterator.next();
}
return candidate;
}
private void initialize() {
if (list == null) {
list = new ArrayList<>();
Iterator<TYPE> newIterator = iterable.iterator();
while (newIterator.hasNext()) {
list.add(newIterator.next());
}
totalElementsCount = list.size();
stopIndex = totalElementsCount - count;
}
}
};
}
};
}
/**
* Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE.
*
* @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE
* @param <NEW_TYPE> the target type of the transformation
* @return a new FluentIterable of the new type
*/
@Override
public <NEW_TYPE> FluentIterable<NEW_TYPE> map(Function<? super TYPE, NEW_TYPE> function) {
return new LazyFluentIterable<NEW_TYPE>() {
@Override
public Iterator<NEW_TYPE> iterator() {
return new DecoratingIterator<NEW_TYPE>(null) {
Iterator<TYPE> oldTypeIterator = iterable.iterator();
@Override
public NEW_TYPE computeNext() {
while (oldTypeIterator.hasNext()) {
TYPE candidate = oldTypeIterator.next();
return function.apply(candidate);
}
return null;
}
};
}
};
}
/**
* Collects all remaining objects of this iteration into a list.
*
* @return a list with all remaining objects of this iteration
*/
@Override
public List<TYPE> asList() {
List<TYPE> copy = FluentIterable.copyToList(iterable);
return copy;
}
@Override
public Iterator<TYPE> iterator() {
return new DecoratingIterator<TYPE>(iterable.iterator()) {
@Override
public TYPE computeNext() {
return fromIterator.next();
}
};
}
/**
* @return a FluentIterable from a given iterable. Calls the LazyFluentIterable constructor.
*/
public static final <TYPE> FluentIterable<TYPE> from(Iterable<TYPE> iterable) {
return new LazyFluentIterable<>(iterable);
}
}

View File

@ -0,0 +1,198 @@
package com.iluwatar.fluentinterface.fluentiterable.simple;
import com.iluwatar.fluentinterface.fluentiterable.FluentIterable;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* 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.
*
* @param <TYPE> the type of the objects the iteration is about
*/
public class SimpleFluentIterable<TYPE> implements FluentIterable<TYPE> {
private final Iterable<TYPE> iterable;
/**
* This constructor creates a copy of a given iterable's contents.
*
* @param iterable the iterable this interface copies to work on.
*/
protected SimpleFluentIterable(Iterable<TYPE> iterable) {
this.iterable = iterable;
}
/**
* Filters the contents of Iterable using the given predicate, leaving only the ones which satisfy
* the predicate.
*
* @param predicate the condition to test with for the filtering. If the test is negative, the
* tested object is removed by the iterator.
* @return the same FluentIterable with a filtered collection
*/
@Override
public final FluentIterable<TYPE> filter(Predicate<? super TYPE> predicate) {
Iterator<TYPE> iterator = iterator();
while (iterator.hasNext()) {
TYPE nextElement = iterator.next();
if (!predicate.test(nextElement)) {
iterator.remove();
}
}
return this;
}
/**
* Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @return an option of the first object of the Iterable
*/
@Override
public final Optional<TYPE> first() {
Iterator<TYPE> resultIterator = first(1).iterator();
return resultIterator.hasNext() ? Optional.of(resultIterator.next()) : Optional.empty();
}
/**
* Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' first
* objects.
*/
@Override
public final FluentIterable<TYPE> first(int count) {
Iterator<TYPE> iterator = iterator();
int currentCount = 0;
while (iterator.hasNext()) {
iterator.next();
if (currentCount >= count) {
iterator.remove();
}
currentCount++;
}
return this;
}
/**
* Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @return an option of the last object of the Iterable
*/
@Override
public final Optional<TYPE> last() {
List<TYPE> list = last(1).asList();
if (list.isEmpty()) {
return Optional.empty();
}
return Optional.of(list.get(0));
}
/**
* Can be used to collect objects from the Iterable. Is a terminating operation.
*
* @param count defines the number of objects to return
* @return the same FluentIterable with a collection decimated to a maximum of 'count' last
* objects
*/
@Override
public final FluentIterable<TYPE> last(int count) {
int remainingElementsCount = getRemainingElementsCount();
Iterator<TYPE> iterator = iterator();
int currentIndex = 0;
while (iterator.hasNext()) {
iterator.next();
if (currentIndex < remainingElementsCount - count) {
iterator.remove();
}
currentIndex++;
}
return this;
}
/**
* Transforms this FluentIterable into a new one containing objects of the type NEW_TYPE.
*
* @param function a function that transforms an instance of TYPE into an instance of NEW_TYPE
* @param <NEW_TYPE> the target type of the transformation
* @return a new FluentIterable of the new type
*/
@Override
public final <NEW_TYPE> FluentIterable<NEW_TYPE> map(Function<? super TYPE, NEW_TYPE> function) {
List<NEW_TYPE> temporaryList = new ArrayList<>();
Iterator<TYPE> iterator = iterator();
while (iterator.hasNext()) {
temporaryList.add(function.apply(iterator.next()));
}
return from(temporaryList);
}
/**
* Collects all remaining objects of this Iterable into a list.
*
* @return a list with all remaining objects of this Iterable
*/
@Override
public List<TYPE> asList() {
return toList(iterable.iterator());
}
/**
* @return a FluentIterable from a given iterable. Calls the SimpleFluentIterable constructor.
*/
public static final <TYPE> FluentIterable<TYPE> from(Iterable<TYPE> iterable) {
return new SimpleFluentIterable<>(iterable);
}
public static final <TYPE> FluentIterable<TYPE> fromCopyOf(Iterable<TYPE> iterable) {
List<TYPE> copy = FluentIterable.copyToList(iterable);
return new SimpleFluentIterable<>(copy);
}
@Override
public Iterator<TYPE> iterator() {
return iterable.iterator();
}
@Override
public void forEach(Consumer<? super TYPE> action) {
iterable.forEach(action);
}
@Override
public Spliterator<TYPE> spliterator() {
return iterable.spliterator();
}
/**
* @return the count of remaining objects of the current Iterable
*/
public final int getRemainingElementsCount() {
int counter = 0;
Iterator<TYPE> iterator = iterator();
while (iterator.hasNext()) {
iterator.next();
counter++;
}
return counter;
}
/**
* Collects the remaining objects of the given iterator into a List.
*
* @return a new List with the remaining objects.
*/
public static <TYPE> List<TYPE> toList(Iterator<TYPE> iterator) {
List<TYPE> copy = new ArrayList<>();
while (iterator.hasNext()) {
copy.add(iterator.next());
}
return copy;
}
}

View File

@ -0,0 +1,12 @@
package com.iluwatar.fluentinterface;
import org.junit.Test;
public class AppTest {
@Test
public void test() {
String[] args = {};
App.main(args);
}
}

View File

@ -27,7 +27,7 @@
</prerequisites>
<properties>
<isis.version>1.9.0-SNAPSHOT</isis.version>
<isis.version>1.9.0</isis.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

34
pom.xml
View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.iluwatar</groupId>
@ -9,8 +10,8 @@
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<hibernate.version>5.0.0.Final</hibernate.version>
<spring-data.version>1.8.2.RELEASE</spring-data.version>
<hibernate.version>5.0.1.Final</hibernate.version>
<spring-data.version>1.9.0.RELEASE</spring-data.version>
<h2.version>1.4.188</h2.version>
<junit.version>4.12</junit.version>
<compiler.version>3.0</compiler.version>
@ -77,8 +78,9 @@
<module>step-builder</module>
<module>layers</module>
<module>message-channel</module>
<module>fluentinterface</module>
<module>reactor</module>
</modules>
</modules>
<dependencyManagement>
<dependencies>
@ -206,6 +208,30 @@
</execution>
</executions>
</plugin>
<!--checkstyle plug-in. checking against googles styles
see config at checkstyle.xml
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>2.15</version>
<executions>
<execution>
<id>validate</id>
<goals>
<goal>check</goal>
</goals>
<phase>validate</phase>
<configuration>
<configLocation>checkstyle.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>false</consoleOutput>
<failsOnError>false</failsOnError>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

22
update-ghpages.sh Normal file
View File

@ -0,0 +1,22 @@
#!/bin/bash
# Clone gh-pages
git clone -b gh-pages "https://${GH_REF}" ghpagesclone
cd ghpagesclone
# Init and update submodule to latest
git submodule update --init --recursive
git submodule update --remote
# Setup Git
git config user.name "Travis-CI"
git config user.email "travis@no.reply"
# If there is a new version of the master branch
if git status | grep patterns > /dev/null 2>&1
then
# it should be committed
git add .
git commit -m ":sparkles: :up: Automagic Update via Travis-CI"
git push --quiet "https://${GH_TOKEN}:x-oauth-basic@${GH_REF}" gh-pages > /dev/null 2>&1
fi