diff --git a/.travis.yml b/.travis.yml index af275508b..60693c5cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,18 @@ language: java - jdk: - - oraclejdk8 +- oraclejdk8 -before_install: - - "export DISPLAY=:99.0" - - "sh -e /etc/init.d/xvfb start" +env: + global: + - GH_REF: github.com/iluwatar/java-design-patterns.git + - secure: LxTDuNS/rBWIvKkaEqr79ImZAe48mCdoYCF41coxNXgNoippo4GIBArknqtv+XvdkiuRZ1yGyj6pn8GU33c/yn+krddTUkVCwTbVatbalW5jhQjDbHYym/JcxaK9ZS/3JTeGcWrBgiPqHEEDhCf26vPZsXoMSeVCEORVKTp1BSg= -after_success: - - mvn clean test jacoco:report coveralls:report +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 diff --git a/README.md b/README.md index a4ec970c9..255fca0f2 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,23 @@ 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 + +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). # 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) * [Java Generics and Collections](http://www.amazon.com/Java-Generics-Collections-Maurice-Naftalin/dp/0596527756/) * [Let's Modify the Objects-First Approach into Design-Patterns-First](http://edu.pecinovsky.cz/papers/2006_ITiCSE_Design_Patterns_First.pdf) @@ -37,7 +47,6 @@ If you are willing to contribute to the project you will find the relevant infor * [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420) * [Spring Data](http://www.amazon.com/Spring-Data-Mark-Pollack/dp/1449323952/ref=sr_1_1) * [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) # License diff --git a/abstract-factory/index.md b/abstract-factory/index.md index cb229f4ab..7db699a99 100644 --- a/abstract-factory/index.md +++ b/abstract-factory/index.md @@ -4,7 +4,9 @@ title: Abstract Factory folder: abstract-factory permalink: /patterns/abstract-factory/ categories: Creational -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Provide an interface for creating families of related or dependent @@ -22,3 +24,7 @@ objects without specifying their concrete classes. **Real world examples:** * [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/abstract-factory/pom.xml b/abstract-factory/pom.xml index ddb7e7b9d..bb9df6bc9 100644 --- a/abstract-factory/pom.xml +++ b/abstract-factory/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 abstract-factory diff --git a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java index 29e9272f6..618b98c52 100644 --- a/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java +++ b/abstract-factory/src/main/java/com/iluwatar/abstractfactory/App.java @@ -3,12 +3,21 @@ package com.iluwatar.abstractfactory; /** * + * The Abstract Factory pattern provides a way to encapsulate a group of individual + * factories that have a common theme without specifying their concrete classes. In + * normal usage, the client software creates a concrete implementation of the abstract + * factory and then uses the generic interface of the factory to create the concrete + * objects that are part of the theme. The client does not know (or care) which + * concrete objects it gets from each of these internal factories, since it uses only + * the generic interfaces of their products. This pattern separates the details of + * implementation of a set of objects from their general usage and relies on object + * composition, as object creation is implemented in methods exposed in the factory + * interface. + *

* The essence of the Abstract Factory pattern is a factory interface * ({@link KingdomFactory}) and its implementations ({@link ElfKingdomFactory}, - * {@link OrcKingdomFactory}). - *

- * The example uses both concrete implementations to create a king, a castle and - * an army. + * {@link OrcKingdomFactory}). The example uses both concrete implementations to + * create a king, a castle and an army. * */ public class App { diff --git a/adapter/index.md b/adapter/index.md index 23aaeadcc..be9a87228 100644 --- a/adapter/index.md +++ b/adapter/index.md @@ -4,7 +4,9 @@ title: Adapter folder: adapter permalink: /patterns/adapter/ categories: Structural -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Convert the interface of a class into another interface the clients @@ -22,3 +24,7 @@ incompatible interfaces. **Real world examples:** * [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/adapter/pom.xml b/adapter/pom.xml index 74a58de92..d07d26b94 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 adapter diff --git a/adapter/src/main/java/com/iluwatar/adapter/App.java b/adapter/src/main/java/com/iluwatar/adapter/App.java index 3d10a4d41..ed036b391 100644 --- a/adapter/src/main/java/com/iluwatar/adapter/App.java +++ b/adapter/src/main/java/com/iluwatar/adapter/App.java @@ -1,7 +1,13 @@ package com.iluwatar.adapter; /** - * + * + * An adapter helps two incompatible interfaces to work together. This is the real + * world definition for an adapter. Interfaces may be incompatible but the inner + * functionality should suit the need. The Adapter design pattern allows otherwise + * incompatible classes to work together by converting the interface of one class + * into an interface expected by the clients. + *

* There are two variations of the Adapter pattern: The class adapter implements * the adaptee's interface whereas the object adapter uses composition to * contain the adaptee in the adapter object. This example uses the object diff --git a/async-method-invocation/pom.xml b/async-method-invocation/pom.xml index 2a5010b74..d5e0e2b3e 100644 --- a/async-method-invocation/pom.xml +++ b/async-method-invocation/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 async-method-invocation diff --git a/bridge/index.md b/bridge/index.md index 6ef1c6519..1ad969183 100644 --- a/bridge/index.md +++ b/bridge/index.md @@ -4,7 +4,9 @@ title: Bridge folder: bridge permalink: /patterns/bridge/ categories: Structural -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Decouple an abstraction from its implementation so that the two can @@ -20,3 +22,7 @@ vary independently. * changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled. * you have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies * you want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation. + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/bridge/pom.xml b/bridge/pom.xml index 947fa2c60..533074d72 100644 --- a/bridge/pom.xml +++ b/bridge/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 bridge diff --git a/bridge/src/main/java/com/iluwatar/bridge/App.java b/bridge/src/main/java/com/iluwatar/bridge/App.java index e8774caea..972f49b2f 100644 --- a/bridge/src/main/java/com/iluwatar/bridge/App.java +++ b/bridge/src/main/java/com/iluwatar/bridge/App.java @@ -2,6 +2,9 @@ package com.iluwatar.bridge; /** * + * The Bridge pattern can also be thought of as two layers of abstraction. With Bridge, + * you can decouple an abstraction from its implementation so that the two can vary independently. + *

* In Bridge pattern both abstraction ({@link MagicWeapon}) and implementation * ({@link MagicWeaponImpl}) have their own class hierarchies. The interface of the * implementations can be changed without affecting the clients. diff --git a/builder/index.md b/builder/index.md index aa5c86201..f350638d2 100644 --- a/builder/index.md +++ b/builder/index.md @@ -4,7 +4,9 @@ title: Builder folder: builder permalink: /patterns/builder/ categories: Creational -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Separate the construction of a complex object from its @@ -22,3 +24,7 @@ representations. * [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html) * [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/builder/pom.xml b/builder/pom.xml index 65997c9e6..effc18f0c 100644 --- a/builder/pom.xml +++ b/builder/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 builder diff --git a/builder/src/main/java/com/iluwatar/builder/App.java b/builder/src/main/java/com/iluwatar/builder/App.java index bcdbb8821..b6131c3ab 100644 --- a/builder/src/main/java/com/iluwatar/builder/App.java +++ b/builder/src/main/java/com/iluwatar/builder/App.java @@ -4,7 +4,20 @@ import com.iluwatar. builder.Hero.HeroBuilder; /** * - * This is the Builder pattern variation as described by Joshua Bloch in + * 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 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 initialization parameter step by step + * and then returns the resulting constructed object at once. + *

+ * The Builder pattern has another benefit. It can be used for objects that contain + * flat data (html code, SQL query, X.509 certificate...), that is to say, data that + * can't be easily edited. This type of data cannot be edited step by step and must + * be edited at once. The best way to construct such an object is to use a builder + * class. + *

+ * In this example we have the Builder pattern variation as described by Joshua Bloch in * Effective Java 2nd Edition. *

* We want to build {@link Hero} objects, but its construction is complex because of the diff --git a/business-delegate/pom.xml b/business-delegate/pom.xml index 482d59fab..84ae64a17 100644 --- a/business-delegate/pom.xml +++ b/business-delegate/pom.xml @@ -6,7 +6,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 business-delegate diff --git a/callback/pom.xml b/callback/pom.xml index f8cf6babf..7e66f6e2b 100644 --- a/callback/pom.xml +++ b/callback/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 callback diff --git a/chain/index.md b/chain/index.md index 25e14bf06..9be376324 100644 --- a/chain/index.md +++ b/chain/index.md @@ -4,7 +4,9 @@ title: Chain of responsibility folder: chain permalink: /patterns/chain/ categories: Behavioral -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Avoid coupling the sender of a request to its receiver by giving @@ -23,3 +25,7 @@ objects and pass the request along the chain until an object handles it. * [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29) * [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/chain/pom.xml b/chain/pom.xml index ebae620d6..80591a477 100644 --- a/chain/pom.xml +++ b/chain/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 chain diff --git a/chain/src/main/java/com/iluwatar/chain/App.java b/chain/src/main/java/com/iluwatar/chain/App.java index 5f98b2478..4d3ca69db 100644 --- a/chain/src/main/java/com/iluwatar/chain/App.java +++ b/chain/src/main/java/com/iluwatar/chain/App.java @@ -2,10 +2,16 @@ package com.iluwatar.chain; /** * - * Chain of Responsibility organizes request handlers ({@link RequestHandler}) into a - * chain where each handler has a chance to act on the request on its turn. In - * this example the king ({@link OrcKing}) makes requests and the military orcs - * ({@link OrcCommander}, {@link OrcOfficer}, {@link OrcSoldier}) form the handler chain. + * The Chain of Responsibility pattern is a design pattern consisting of command + * objects and a series of processing objects. Each processing object contains + * logic that defines the types of command objects that it can handle; the rest are + * passed to the next processing object in the chain. A mechanism also exists for + * adding new processing objects to the end of this chain. + *

+ * In this example we organize the request handlers ({@link RequestHandler}) into a + * chain where each handler has a chance to act on the request on its turn. Here + * the king ({@link OrcKing}) makes requests and the military orcs ({@link OrcCommander}, + * {@link OrcOfficer}, {@link OrcSoldier}) form the handler chain. * */ public class App { diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 000000000..0ff943d95 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/command/index.md b/command/index.md index 23582406e..c9790819f 100644 --- a/command/index.md +++ b/command/index.md @@ -4,7 +4,9 @@ title: Command folder: command permalink: /patterns/command/ categories: Behavioral -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Encapsulate a request as an object, thereby letting you @@ -30,3 +32,7 @@ support undoable operations. **Real world examples:** * [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/command/pom.xml b/command/pom.xml index 401acba32..22f1c256b 100644 --- a/command/pom.xml +++ b/command/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 command diff --git a/command/src/main/java/com/iluwatar/command/App.java b/command/src/main/java/com/iluwatar/command/App.java index fc05afa66..b421b683b 100644 --- a/command/src/main/java/com/iluwatar/command/App.java +++ b/command/src/main/java/com/iluwatar/command/App.java @@ -2,7 +2,9 @@ package com.iluwatar.command; /** * - * In Command pattern actions are objects that can be executed and undone. + * The Command pattern is a behavioral design pattern in which an object is used to encapsulate all information + * needed to perform an action or trigger an event at a later time. This information includes the method name, + * the object that owns the method and values for the method parameters. *

* Four terms always associated with the command pattern are command, receiver, invoker and client. A command * object (spell) knows about the receiver (target) and invokes a method of the receiver. Values for parameters of diff --git a/composite/index.md b/composite/index.md index 374e1d5aa..4a31a1b33 100644 --- a/composite/index.md +++ b/composite/index.md @@ -4,7 +4,9 @@ title: Composite folder: composite permalink: /patterns/composite/ categories: Structural -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Compose objects into tree structures to represent part-whole @@ -22,3 +24,7 @@ of objects uniformly. * [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) and [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html) * [Apache Wicket](https://github.com/apache/wicket) component tree, see [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) and [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/composite/pom.xml b/composite/pom.xml index ca4daaaad..2b8298647 100644 --- a/composite/pom.xml +++ b/composite/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 composite diff --git a/composite/src/main/java/com/iluwatar/composite/App.java b/composite/src/main/java/com/iluwatar/composite/App.java index 7dfd15443..7bd0e4d01 100644 --- a/composite/src/main/java/com/iluwatar/composite/App.java +++ b/composite/src/main/java/com/iluwatar/composite/App.java @@ -1,10 +1,14 @@ package com.iluwatar.composite; /** - * - * With Composite we can treat tree hierarchies of objects with uniform - * interface ({@link LetterComposite}). In this example we have sentences composed of - * words composed of letters. + * The Composite pattern is a partitioning design pattern. The Composite pattern + * describes that a group of objects is to be treated in the same way as a single + * instance of an object. The intent of a composite is to "compose" objects into + * tree structures to represent part-whole hierarchies. Implementing the Composite + * pattern lets clients treat individual objects and compositions uniformly. + *

+ * In this example we have sentences composed of words composed of letters. All of + * the objects can be treated through the same interface ({@link LetterComposite}). * */ public class App { diff --git a/dao/index.md b/dao/index.md index 7fd936c12..cf9f43a68 100644 --- a/dao/index.md +++ b/dao/index.md @@ -4,7 +4,9 @@ title: Data Access Object folder: dao permalink: /patterns/dao/ categories: Architectural -tags: Java +tags: + - Java + - Difficulty-Beginner --- **Intent:** Object provides an abstract interface to some type of database or @@ -16,3 +18,7 @@ other persistence mechanism. * when you want to consolidate how the data layer is accessed * when you want to avoid writing multiple data retrieval/persistence layers + +**Credits:** + +* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2) diff --git a/dao/pom.xml b/dao/pom.xml index a7a5c74ca..0361f3c9b 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 dao diff --git a/dao/src/main/java/com/iluwatar/dao/App.java b/dao/src/main/java/com/iluwatar/dao/App.java index ac6794973..851153f22 100644 --- a/dao/src/main/java/com/iluwatar/dao/App.java +++ b/dao/src/main/java/com/iluwatar/dao/App.java @@ -5,8 +5,14 @@ import java.util.List; /** * + * Data Access Object (DAO) is an object that provides an abstract interface to some type of database or other + * persistence mechanism. By mapping application calls to the persistence layer, DAO provide some specific data + * operations without exposing details of the database. This isolation supports the Single responsibility principle. + * It separates what data accesses the application needs, in terms of domain-specific objects and data types + * (the public interface of the DAO), from how these needs can be satisfied with a specific DBMS. + *

* With the DAO pattern, we can use various method calls to retrieve/add/delete/update data without directly - * interacting with the data. The below example demonstrates basic operations(CRUD): select, add, update, and delete. + * interacting with the data. The below example demonstrates basic CRUD operations: select, add, update, and delete. * */ public class App { diff --git a/decorator/index.md b/decorator/index.md index 02f129258..55849fce6 100644 --- a/decorator/index.md +++ b/decorator/index.md @@ -4,7 +4,9 @@ title: Decorator folder: decorator permalink: /patterns/decorator/ categories: Structural -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Attach additional responsibilities to an object dynamically. @@ -18,3 +20,7 @@ functionality. * to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects * for responsibilities that can be withdrawn * when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/decorator/pom.xml b/decorator/pom.xml index 57946b711..92142f184 100644 --- a/decorator/pom.xml +++ b/decorator/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 decorator diff --git a/decorator/src/main/java/com/iluwatar/decorator/App.java b/decorator/src/main/java/com/iluwatar/decorator/App.java index 88e1c7103..bd697d4a4 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/App.java +++ b/decorator/src/main/java/com/iluwatar/decorator/App.java @@ -2,12 +2,15 @@ package com.iluwatar.decorator; /** * - * Decorator pattern is a more flexible alternative to subclassing. The decorator + * The Decorator pattern is a more flexible alternative to subclassing. The Decorator * class implements the same interface as the target and uses composition to - * "decorate" calls to the target. + * "decorate" calls to the target. Using the Decorator pattern it is possible to + * change the behavior of the class during runtime. *

- * Using decorator pattern it is possible to change class behavior during - * runtime, as the example shows. + * In this example we show how the simple {@link Troll} first attacks and then + * flees the battle. Then we decorate the {@link Troll} with a {@link SmartTroll} + * and perform the attack again. You can see how the behavior changes after the + * decoration. * */ public class App { @@ -23,11 +26,13 @@ public class App { Hostile troll = new Troll(); troll.attack(); troll.fleeBattle(); + System.out.printf("Simple troll power %d.\n", troll.getAttackPower()); // change the behavior of the simple troll by adding a decorator System.out.println("\nA smart looking troll surprises you."); Hostile smart = new SmartTroll(troll); smart.attack(); smart.fleeBattle(); + System.out.printf("Smart troll power %d.\n", smart.getAttackPower()); } } diff --git a/decorator/src/main/java/com/iluwatar/decorator/Hostile.java b/decorator/src/main/java/com/iluwatar/decorator/Hostile.java index 4df751cca..709072501 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/Hostile.java +++ b/decorator/src/main/java/com/iluwatar/decorator/Hostile.java @@ -9,6 +9,8 @@ public interface Hostile { void attack(); + int getAttackPower(); + void fleeBattle(); } diff --git a/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java b/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java index 22ba88dc8..909f94c95 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java +++ b/decorator/src/main/java/com/iluwatar/decorator/SmartTroll.java @@ -21,6 +21,12 @@ public class SmartTroll implements Hostile { decorated.attack(); } + @Override + public int getAttackPower() { + // decorated troll power + 20 because it is smart + return decorated.getAttackPower() + 20; + } + @Override public void fleeBattle() { System.out.println("The troll calls for help!"); diff --git a/decorator/src/main/java/com/iluwatar/decorator/Troll.java b/decorator/src/main/java/com/iluwatar/decorator/Troll.java index 11e9b9d1a..85d873dbe 100644 --- a/decorator/src/main/java/com/iluwatar/decorator/Troll.java +++ b/decorator/src/main/java/com/iluwatar/decorator/Troll.java @@ -11,6 +11,11 @@ public class Troll implements Hostile { System.out.println("The troll swings at you with a club!"); } + @Override + public int getAttackPower() { + return 10; + } + public void fleeBattle() { System.out.println("The troll shrieks in horror and runs away!"); } diff --git a/dependency-injection/pom.xml b/dependency-injection/pom.xml index a6780cb20..9a28933f8 100644 --- a/dependency-injection/pom.xml +++ b/dependency-injection/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 dependency-injection diff --git a/double-checked-locking/pom.xml b/double-checked-locking/pom.xml index 46d4a70f0..6f1fe93eb 100644 --- a/double-checked-locking/pom.xml +++ b/double-checked-locking/pom.xml @@ -3,7 +3,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 double-checked-locking diff --git a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java index 2a5c65813..80806e9eb 100644 --- a/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java +++ b/double-checked-locking/src/main/java/com/iluwatar/doublechecked/locking/App.java @@ -5,6 +5,11 @@ import java.util.concurrent.Executors; /** * + * Double Checked Locking is a concurrency design pattern used to reduce the overhead + * of acquiring a lock by first testing the locking criterion (the "lock hint") without + * actually acquiring the lock. Only if the locking criterion check indicates that + * locking is required does the actual locking logic proceed. + *

* In {@link Inventory} we store the items with a given size. However, we do not store * more items than the inventory size. To address concurrent access problems we * use double checked locking to add item to inventory. In this method, the diff --git a/double-dispatch/pom.xml b/double-dispatch/pom.xml index 5f16635f6..057d75e8e 100644 --- a/double-dispatch/pom.xml +++ b/double-dispatch/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 double-dispatch diff --git a/event-aggregator/pom.xml b/event-aggregator/pom.xml index 1c9a3b626..4e7f1b55b 100644 --- a/event-aggregator/pom.xml +++ b/event-aggregator/pom.xml @@ -4,7 +4,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 event-aggregator diff --git a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/App.java b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/App.java index 029489077..b69d8ceaa 100644 --- a/event-aggregator/src/main/java/com/iluwatar/event/aggregator/App.java +++ b/event-aggregator/src/main/java/com/iluwatar/event/aggregator/App.java @@ -5,8 +5,12 @@ import java.util.List; /** * - * The Event Aggregator pattern channels events from multiple objects - * into a single object to simplify registration for clients. + * A system with lots of objects can lead to complexities when a client wants to subscribe + * to events. The client has to find and register for each object individually, if each + * object has multiple events then each event requires a separate subscription. + *

+ * An Event Aggregator acts as a single source of events for many objects. It registers + * for all the events of the many objects allowing clients to register with just the aggregator. *

* In the example {@link LordBaelish}, {@link LordVarys} and {@link Scout} deliver events to * {@link KingsHand}. {@link KingsHand}, the event aggregator, then delivers the events diff --git a/execute-around/pom.xml b/execute-around/pom.xml index 7d806337b..c6a7785aa 100644 --- a/execute-around/pom.xml +++ b/execute-around/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 execute-around diff --git a/facade/index.md b/facade/index.md index 0f6e2fbb1..59ff888b2 100644 --- a/facade/index.md +++ b/facade/index.md @@ -4,7 +4,9 @@ title: Facade folder: facade permalink: /patterns/facade/ categories: Structural -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Provide a unified interface to a set of interfaces in a subsystem. @@ -17,3 +19,7 @@ Facade defines a higher-level interface that makes the subsystem easier to use. * you want to provide a simple interface to a complex subsystem. Subsystems often get more complex as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the subsystem more reusable and easier to customize, but it also becomes harder to use for clients that don't need to customize it. A facade can provide a simple default view of the subsystem that is good enough for most clients. Only clients needing more customizability will need to look beyond the facade. * there are many dependencies between clients and the implementation classes of an abstraction. Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting subsystem independence and portability. * you want to layer your subsystems. Use a facade to define an entry point to each subsystem level. If subsystems are dependent, the you can simplify the dependencies between them by making them communicate with each other solely through their facades + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/facade/pom.xml b/facade/pom.xml index 17d3d707c..cea5bf0c3 100644 --- a/facade/pom.xml +++ b/facade/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 facade diff --git a/facade/src/main/java/com/iluwatar/facade/App.java b/facade/src/main/java/com/iluwatar/facade/App.java index 0d8eccd4b..37cda0281 100644 --- a/facade/src/main/java/com/iluwatar/facade/App.java +++ b/facade/src/main/java/com/iluwatar/facade/App.java @@ -2,9 +2,15 @@ package com.iluwatar.facade; /** * - * Facade ({@link DwarvenGoldmineFacade}) provides simpler interface to subsystem. + * The Facade design pattern is often used when a system is very complex or difficult + * to understand because the system has a large number of interdependent classes or + * its source code is unavailable. This pattern hides the complexities of the larger + * system and provides a simpler interface to the client. It typically involves a single + * wrapper class which contains a set of members required by client. These members access + * the system on behalf of the facade client and hide the implementation details. *

- * http://en.wikipedia.org/wiki/Facade_pattern + * In this example the Facade is ({@link DwarvenGoldmineFacade}) and it provides a simpler + * interface to the goldmine subsystem. * */ public class App { diff --git a/factory-method/index.md b/factory-method/index.md index fa30a4349..fee6b6e83 100644 --- a/factory-method/index.md +++ b/factory-method/index.md @@ -4,7 +4,10 @@ title: Factory Method folder: factory-method permalink: /patterns/factory-method/ categories: Creational -tags: Java +tags: + - Java + - Difficulty-Beginner + - Gang Of Four --- **Intent:** Define an interface for creating an object, but let subclasses @@ -18,3 +21,7 @@ instantiation to subclasses. * a class can't anticipate the class of objects it must create * a class wants its subclasses to specify the objects it creates * classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/factory-method/pom.xml b/factory-method/pom.xml index 81072a4f9..39e0b7b4e 100644 --- a/factory-method/pom.xml +++ b/factory-method/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 factory-method diff --git a/factory-method/src/main/java/com/iluwatar/factory/method/App.java b/factory-method/src/main/java/com/iluwatar/factory/method/App.java index 69bda3489..118413564 100644 --- a/factory-method/src/main/java/com/iluwatar/factory/method/App.java +++ b/factory-method/src/main/java/com/iluwatar/factory/method/App.java @@ -2,7 +2,14 @@ package com.iluwatar.factory.method; /** * - * In Factory Method we have an interface ({@link Blacksmith}) with a method for + * The Factory Method is a creational design pattern which uses factory methods to deal + * with the problem of creating objects without specifying the exact class of object + * that will be created. This is done by creating objects via calling a factory + * method either specified in an interface and implemented by child classes, or implemented + * in a base class and optionally overridden by derived classes—rather than by calling a + * constructor. + *

+ * In this Factory Method example we have an interface ({@link Blacksmith}) with a method for * creating objects ({@link Blacksmith#manufactureWeapon}). The concrete subclasses * ({@link OrcBlacksmith}, {@link ElfBlacksmith}) then override the method to produce * objects of their liking. diff --git a/faq.md b/faq.md index 5633a693d..b98bc7589 100644 --- a/faq.md +++ b/faq.md @@ -61,3 +61,7 @@ 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. \ No newline at end of file diff --git a/fluentinterface/etc/fluentinterface.png b/fluentinterface/etc/fluentinterface.png new file mode 100644 index 000000000..611fec7c6 Binary files /dev/null and b/fluentinterface/etc/fluentinterface.png differ diff --git a/fluentinterface/etc/fluentinterface.ucls b/fluentinterface/etc/fluentinterface.ucls new file mode 100644 index 000000000..e30c45bb2 --- /dev/null +++ b/fluentinterface/etc/fluentinterface.ucls @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fluentinterface/index.md b/fluentinterface/index.md new file mode 100644 index 000000000..27a4d1a26 --- /dev/null +++ b/fluentinterface/index.md @@ -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) diff --git a/fluentinterface/pom.xml b/fluentinterface/pom.xml new file mode 100644 index 000000000..16e237bd5 --- /dev/null +++ b/fluentinterface/pom.xml @@ -0,0 +1,20 @@ + + + + java-design-patterns + com.iluwatar + 1.7.0 + + 4.0.0 + + fluentinterface + + + junit + junit + test + + + \ No newline at end of file diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java new file mode 100644 index 000000000..7733df37d --- /dev/null +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/app/App.java @@ -0,0 +1,102 @@ +package com.iluwatar.fluentinterface.app; + +import com.iluwatar.fluentinterface.fluentiterable.FluentIterable; +import com.iluwatar.fluentinterface.fluentiterable.lazy.LazyFluentIterable; +import com.iluwatar.fluentinterface.fluentiterable.simple.SimpleFluentIterable; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; + +import static java.lang.String.valueOf; + +/** + * The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those + * interfaces tend to mimic domain specific languages, so they can nearly be read as human languages. + *

+ * In this example two implementations of a {@link FluentIterable} interface are given. The + * {@link SimpleFluentIterable} evaluates eagerly and would be too costly for real world applications. + * The {@link 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. + * + */ +public class App { + + public static void main(String[] args) { + + List 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 firstFiveNegatives = + SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).first(3).asList(); + prettyPrint("The first three negative values are: ", firstFiveNegatives); + + + List 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 transformedList = + SimpleFluentIterable.fromCopyOf(integerList).filter(negatives()).map(transformToString()) + .asList(); + prettyPrint("A string-mapped list of negative numbers contains: ", transformedList); + + + List 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 transformToString() { + return integer -> "String[" + valueOf(integer) + "]"; + } + + private static Predicate negatives() { + return integer -> (integer < 0); + } + + private static Predicate positives() { + return integer -> (integer > 0); + } + + private static void prettyPrint(String prefix, Iterable iterable) { + prettyPrint(", ", prefix, ".", iterable); + } + + private static void prettyPrint(String delimiter, String prefix, String suffix, + Iterable iterable) { + StringJoiner joiner = new StringJoiner(delimiter, prefix, "."); + Iterator iterator = iterable.iterator(); + while (iterator.hasNext()) { + joiner.add(iterator.next().toString()); + } + + System.out.println(joiner); + } +} diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java new file mode 100644 index 000000000..5c4df0391 --- /dev/null +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/FluentIterable.java @@ -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 is the class of objects the iterable contains + */ +public interface FluentIterable extends 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 a filtered FluentIterable + */ + FluentIterable filter(Predicate 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 first(); + + /** + * Evaluates the iteration and leaves only the count first elements. + * + * @return the first count elements as an Iterable + */ + FluentIterable 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 last(); + + /** + * Evaluates the iteration and leaves only the count last elements. + * + * @return the last counts elements as an Iterable + */ + FluentIterable 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 the target type of the transformation + * @return a new FluentIterable of the new type + */ + FluentIterable map(Function function); + + /** + * Returns the contents of this Iterable as a List. + * + * @return a List representation of this Iterable + */ + List asList(); + + /** + * Utility method that iterates over iterable and adds the contents to a list. + * + * @param iterable the iterable to collect + * @param the type of the objects to iterate + * @return a list with all objects of the given iterator + */ + static List copyToList(Iterable iterable) { + ArrayList copy = new ArrayList<>(); + Iterator iterator = iterable.iterator(); + while (iterator.hasNext()) { + copy.add(iterator.next()); + } + return copy; + } +} diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java new file mode 100644 index 000000000..e80356d8e --- /dev/null +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/DecoratingIterator.java @@ -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 + */ +public abstract class DecoratingIterator implements Iterator { + + protected final Iterator fromIterator; + + private TYPE next = null; + + /** + * Creates an iterator that decorates the given iterator. + * + * @param fromIterator + */ + public DecoratingIterator(Iterator 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(); +} diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java new file mode 100644 index 000000000..560b10189 --- /dev/null +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/lazy/LazyFluentIterable.java @@ -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 the type of the objects the iteration is about + */ +public class LazyFluentIterable implements FluentIterable { + + private final Iterable iterable; + + /** + * This constructor creates a new LazyFluentIterable. It wraps the given iterable. + * + * @param iterable the iterable this FluentIterable works on. + */ + protected LazyFluentIterable(Iterable 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 filter(Predicate predicate) { + return new LazyFluentIterable() { + @Override + public Iterator iterator() { + return new DecoratingIterator(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 first() { + Iterator 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 first(int count) { + return new LazyFluentIterable() { + @Override + public Iterator iterator() { + return new DecoratingIterator(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 last() { + Iterator 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 last(int count) { + return new LazyFluentIterable() { + @Override + public Iterator iterator() { + return new DecoratingIterator(iterable.iterator()) { + private int stopIndex; + private int totalElementsCount; + private List 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 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 the target type of the transformation + * @return a new FluentIterable of the new type + */ + @Override + public FluentIterable map(Function function) { + return new LazyFluentIterable() { + @Override + public Iterator iterator() { + return new DecoratingIterator(null) { + Iterator 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 asList() { + List copy = FluentIterable.copyToList(iterable); + return copy; + } + + @Override + public Iterator iterator() { + return new DecoratingIterator(iterable.iterator()) { + @Override + public TYPE computeNext() { + return fromIterator.next(); + } + }; + } + + /** + * @return a FluentIterable from a given iterable. Calls the LazyFluentIterable constructor. + */ + public static final FluentIterable from(Iterable iterable) { + return new LazyFluentIterable<>(iterable); + } + +} diff --git a/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java new file mode 100644 index 000000000..19283152e --- /dev/null +++ b/fluentinterface/src/main/java/com/iluwatar/fluentinterface/fluentiterable/simple/SimpleFluentIterable.java @@ -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 the type of the objects the iteration is about + */ +public class SimpleFluentIterable implements FluentIterable { + + private final Iterable 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 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 filter(Predicate predicate) { + Iterator 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 first() { + Iterator 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 first(int count) { + Iterator 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 last() { + List 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 last(int count) { + int remainingElementsCount = getRemainingElementsCount(); + Iterator 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 the target type of the transformation + * @return a new FluentIterable of the new type + */ + @Override + public final FluentIterable map(Function function) { + List temporaryList = new ArrayList<>(); + Iterator 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 asList() { + return toList(iterable.iterator()); + } + + /** + * @return a FluentIterable from a given iterable. Calls the SimpleFluentIterable constructor. + */ + public static final FluentIterable from(Iterable iterable) { + return new SimpleFluentIterable<>(iterable); + } + + public static final FluentIterable fromCopyOf(Iterable iterable) { + List copy = FluentIterable.copyToList(iterable); + return new SimpleFluentIterable<>(copy); + } + + @Override + public Iterator iterator() { + return iterable.iterator(); + } + + @Override + public void forEach(Consumer action) { + iterable.forEach(action); + } + + + @Override + public Spliterator spliterator() { + return iterable.spliterator(); + } + + /** + * @return the count of remaining objects of the current Iterable + */ + public final int getRemainingElementsCount() { + int counter = 0; + Iterator 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 List toList(Iterator iterator) { + List copy = new ArrayList<>(); + while (iterator.hasNext()) { + copy.add(iterator.next()); + } + return copy; + } +} diff --git a/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java new file mode 100644 index 000000000..29ad885c0 --- /dev/null +++ b/fluentinterface/src/test/java/com/iluwatar/fluentinterface/app/AppTest.java @@ -0,0 +1,14 @@ +package com.iluwatar.fluentinterface.app; + +import org.junit.Test; + +import com.iluwatar.fluentinterface.app.App; + +public class AppTest { + + @Test + public void test() { + String[] args = {}; + App.main(args); + } +} diff --git a/flux/pom.xml b/flux/pom.xml index 3efccbfa4..f706b49ed 100644 --- a/flux/pom.xml +++ b/flux/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 flux diff --git a/flyweight/index.md b/flyweight/index.md index 85fa54ad1..e2273c197 100644 --- a/flyweight/index.md +++ b/flyweight/index.md @@ -4,7 +4,9 @@ title: Flyweight folder: flyweight permalink: /patterns/flyweight/ categories: Structural -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Use sharing to support large numbers of fine-grained objects @@ -25,3 +27,7 @@ true **Real world examples:** * [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/flyweight/pom.xml b/flyweight/pom.xml index 54ca5bef2..7c0f3e2b0 100644 --- a/flyweight/pom.xml +++ b/flyweight/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 flyweight diff --git a/front-controller/index.md b/front-controller/index.md index dd83bc396..ba593a157 100644 --- a/front-controller/index.md +++ b/front-controller/index.md @@ -22,3 +22,9 @@ internationalization, routing and logging in a single place. **Real world examples:** * [Apache Struts](https://struts.apache.org/) + +**Credits:** + +* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2) +* [Presentation Tier Patterns](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns) +* [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420) diff --git a/front-controller/pom.xml b/front-controller/pom.xml index a554186f3..c80121df2 100644 --- a/front-controller/pom.xml +++ b/front-controller/pom.xml @@ -6,7 +6,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 front-controller diff --git a/half-sync-half-async/index.md b/half-sync-half-async/index.md index 0ea0254b8..dc1930e3b 100644 --- a/half-sync-half-async/index.md +++ b/half-sync-half-async/index.md @@ -30,3 +30,4 @@ degrading execution efficiency. **Credits:** * [Douglas C. Schmidt and Charles D. Cranor - Half Sync/Half Async](http://www.cs.wustl.edu/~schmidt/PDF/PLoP-95.pdf) +* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697) diff --git a/half-sync-half-async/pom.xml b/half-sync-half-async/pom.xml index 94c12d797..e7436d29f 100644 --- a/half-sync-half-async/pom.xml +++ b/half-sync-half-async/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 half-sync-half-async diff --git a/intercepting-filter/index.md b/intercepting-filter/index.md index 9625e445d..41825745b 100644 --- a/intercepting-filter/index.md +++ b/intercepting-filter/index.md @@ -18,6 +18,11 @@ post-processing to requests from a client to a target * a system should do the authentication/ authorization/ logging or tracking of request and then pass the requests to corresponding handlers * you want a modular approach to configuring pre-processing and post-processing schemes +**Real world examples:** + +* [Struts 2 - Interceptors](https://struts.apache.org/docs/interceptors.html) + **Credits:** * [TutorialsPoint - Intercepting Filter](http://www.tutorialspoint.com/design_pattern/intercepting_filter_pattern.htm) +* [Presentation Tier Patterns](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns) diff --git a/intercepting-filter/pom.xml b/intercepting-filter/pom.xml index 35ebd9f59..230f76ca3 100644 --- a/intercepting-filter/pom.xml +++ b/intercepting-filter/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 intercepting-filter diff --git a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java index 7cdb17fb8..c913da66c 100644 --- a/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java +++ b/intercepting-filter/src/main/java/com/iluwatar/intercepting/filter/App.java @@ -1,9 +1,33 @@ package com.iluwatar.intercepting.filter; /** - * - * This is an app that checks whether the order request is valid through pre-processing done via {@link Filter}. - * Each field has its own corresponding {@link Filter} + * + * When a request enters a Web application, it often must pass several entrance + * tests prior to the main processing stage. For example, + * - Has the client been authenticated? + * - Does the client have a valid session? + * - Is the client's IP address from a trusted network? + * - Does the request path violate any constraints? + * - What encoding does the client use to send the data? + * - Do we support the browser type of the client? + * Some of these checks are tests, resulting in a yes or no answer that determines + * whether processing will continue. Other checks manipulate the incoming data + * stream into a form suitable for processing. + *

+ * The classic solution consists of a series of conditional checks, with any failed + * check aborting the request. Nested if/else statements are a standard strategy, + * but this solution leads to code fragility and a copy-and-paste style of programming, + * because the flow of the filtering and the action of the filters is compiled into + * the application. + *

+ * The key to solving this problem in a flexible and unobtrusive manner is to have a + * simple mechanism for adding and removing processing components, in which each + * component completes a specific filtering action. This is the Intercepting Filter + * pattern in action. + *

+ * In this example we check whether the order request is valid through pre-processing + * done via {@link Filter}. Each field has its own corresponding {@link Filter} + *

* @author joshzambales * */ diff --git a/interpreter/index.md b/interpreter/index.md index c7c4539d5..57b117e06 100644 --- a/interpreter/index.md +++ b/interpreter/index.md @@ -4,7 +4,9 @@ title: Interpreter folder: interpreter permalink: /patterns/interpreter/ categories: Behavioral -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Given a language, define a representation for its grammar along @@ -19,3 +21,7 @@ trees. The Interpreter pattern works best when * the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time * efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/interpreter/pom.xml b/interpreter/pom.xml index 8583464d3..8a536748c 100644 --- a/interpreter/pom.xml +++ b/interpreter/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 interpreter diff --git a/interpreter/src/main/java/com/iluwatar/interpreter/App.java b/interpreter/src/main/java/com/iluwatar/interpreter/App.java index 2273b386b..955563915 100644 --- a/interpreter/src/main/java/com/iluwatar/interpreter/App.java +++ b/interpreter/src/main/java/com/iluwatar/interpreter/App.java @@ -4,8 +4,14 @@ import java.util.Stack; /** * - * Interpreter pattern breaks sentences into expressions ({@link Expression}) that can - * be evaluated and as a whole form the result. + * The Interpreter pattern is a design pattern that specifies how to evaluate sentences + * in a language. The basic idea is to have a class for each symbol (terminal or nonterminal) + * in a specialized computer language. The syntax tree of a sentence in the language is an + * instance of the composite pattern and is used to evaluate (interpret) the sentence for a + * client. + *

+ * In this example we use the Interpreter pattern to break sentences into expressions + * ({@link Expression}) that can be evaluated and as a whole form the result. * */ public class App { diff --git a/iterator/index.md b/iterator/index.md index 63bdaf516..ecfdb1b2a 100644 --- a/iterator/index.md +++ b/iterator/index.md @@ -4,7 +4,10 @@ title: Iterator folder: iterator permalink: /patterns/iterator/ categories: Behavioral -tags: Java +tags: + - Java + - Difficulty-Beginner + - Gang Of Four --- **Intent:** Provide a way to access the elements of an aggregate object @@ -21,3 +24,7 @@ sequentially without exposing its underlying representation. **Real world examples:** * [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/iterator/pom.xml b/iterator/pom.xml index da5040dce..22e574ba5 100644 --- a/iterator/pom.xml +++ b/iterator/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 iterator diff --git a/iterator/src/main/java/com/iluwatar/iterator/App.java b/iterator/src/main/java/com/iluwatar/iterator/App.java index 5b59cbcbc..b8ecfa42c 100644 --- a/iterator/src/main/java/com/iluwatar/iterator/App.java +++ b/iterator/src/main/java/com/iluwatar/iterator/App.java @@ -2,9 +2,13 @@ package com.iluwatar.iterator; /** * - * Iterator ({@link ItemIterator}) adds abstraction layer on top of a collection - * ({@link TreasureChest}). This way the collection can change its internal - * implementation without affecting its clients. + * The Iterator pattern is a design pattern in which an iterator is used to + * traverse a container and access the container's elements. The Iterator pattern + * decouples algorithms from containers. + *

+ * In this example the Iterator ({@link ItemIterator}) adds abstraction layer on + * top of a collection ({@link TreasureChest}). This way the collection can change + * its internal implementation without affecting its clients. * */ public class App { diff --git a/layers/index.md b/layers/index.md index 1d12d3b4e..37089a19c 100644 --- a/layers/index.md +++ b/layers/index.md @@ -17,3 +17,8 @@ tags: Java * you want clearly divide software responsibilities into differents parts of the program * you want to prevent a change from propagating throughout the application * you want to make your application more maintainable and testable + +**Credits:** + +* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697) + diff --git a/layers/pom.xml b/layers/pom.xml index de672a3df..5d3fd778c 100644 --- a/layers/pom.xml +++ b/layers/pom.xml @@ -6,7 +6,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 com.iluwatar.layers layers diff --git a/lazy-loading/pom.xml b/lazy-loading/pom.xml index b795abf87..61da2f3b5 100644 --- a/lazy-loading/pom.xml +++ b/lazy-loading/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 lazy-loading diff --git a/mediator/index.md b/mediator/index.md index e67218a53..cb4ce7fb1 100644 --- a/mediator/index.md +++ b/mediator/index.md @@ -4,7 +4,10 @@ title: Mediator folder: mediator permalink: /patterns/mediator/ categories: Behavioral -tags: Java +tags: + - Java + - Gang Of Four + - Difficulty-Intermediate --- **Intent:** Define an object that encapsulates how a set of objects interact. @@ -18,3 +21,7 @@ other explicitly, and it lets you vary their interaction independently. * a set of objects communicate in well-defined but complex ways. The resulting interdependencies are unstructured and difficult to understand * reusing an object is difficult because it refers to and communicates with many other objects * a behavior that's distributed between several classes should be customizable without a lot of subclassing + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/mediator/pom.xml b/mediator/pom.xml index 5a9c00042..1e325bb8f 100644 --- a/mediator/pom.xml +++ b/mediator/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 mediator diff --git a/mediator/src/main/java/com/iluwatar/mediator/App.java b/mediator/src/main/java/com/iluwatar/mediator/App.java index a7df7d39f..9648ac608 100644 --- a/mediator/src/main/java/com/iluwatar/mediator/App.java +++ b/mediator/src/main/java/com/iluwatar/mediator/App.java @@ -2,8 +2,26 @@ package com.iluwatar.mediator; /** * - * Mediator encapsulates how a set of objects ({@link PartyMember}) interact. Instead of - * referring to each other directly they use a mediator ({@link Party}) interface. + * The Mediator pattern defines an object that encapsulates how a set of objects + * interact. This pattern is considered to be a behavioral pattern due to the way + * it can alter the program's running behavior. + *

+ * Usually a program is made up of a large number of classes. So the logic and + * computation is distributed among these classes. However, as more classes are + * developed in a program, especially during maintenance and/or refactoring, + * the problem of communication between these classes may become more complex. + * This makes the program harder to read and maintain. Furthermore, it can become + * difficult to change the program, since any change may affect code in several + * other classes. + *

+ * With the Mediator pattern, communication between objects is encapsulated with + * a mediator object. Objects no longer communicate directly with each other, but + * instead communicate through the mediator. This reduces the dependencies between + * communicating objects, thereby lowering the coupling. + *

+ * In this example the mediator encapsulates how a set of objects ({@link PartyMember}) + * interact. Instead of referring to each other directly they use the mediator + * ({@link Party}) interface. * */ public class App { diff --git a/memento/index.md b/memento/index.md index b91e34739..056af8b26 100644 --- a/memento/index.md +++ b/memento/index.md @@ -4,7 +4,9 @@ title: Memento folder: memento permalink: /patterns/memento/ categories: Behavioral -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Without violating encapsulation, capture and externalize an @@ -20,3 +22,7 @@ object's internal state so that the object can be restored to this state later. **Real world examples:** * [java.util.Date](http://docs.oracle.com/javase/8/docs/api/java/util/Date.html) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/memento/pom.xml b/memento/pom.xml index 182a46204..98d1d4a9f 100644 --- a/memento/pom.xml +++ b/memento/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 memento diff --git a/memento/src/main/java/com/iluwatar/memento/App.java b/memento/src/main/java/com/iluwatar/memento/App.java index 623ffb00e..71d0ed466 100644 --- a/memento/src/main/java/com/iluwatar/memento/App.java +++ b/memento/src/main/java/com/iluwatar/memento/App.java @@ -4,7 +4,20 @@ import java.util.Stack; /** * - * Memento pattern is for storing and restoring object state. The object ({@link Star}) + * The Memento pattern is a software design pattern that provides the ability to restore + * an object to its previous state (undo via rollback). + *

+ * The Memento pattern is implemented with three objects: the originator, a caretaker and + * a memento. The originator is some object that has an internal state. The caretaker is + * going to do something to the originator, but wants to be able to undo the change. The + * caretaker first asks the originator for a memento object. Then it does whatever operation + * (or sequence of operations) it was going to do. To roll back to the state before the + * operations, it returns the memento object to the originator. The memento object itself + * is an opaque object (one which the caretaker cannot, or should not, change). When using + * this pattern, care should be taken if the originator may change other objects or + * resources - the memento pattern operates on a single object. + *

+ * In this example the object ({@link Star}) * gives out a "memento" ({@link StarMemento}) that contains the state of the object. * Later on the memento can be set back to the object restoring the state. * diff --git a/message-channel/pom.xml b/message-channel/pom.xml index ef66f2401..ee7d54c95 100644 --- a/message-channel/pom.xml +++ b/message-channel/pom.xml @@ -6,7 +6,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 message-channel diff --git a/model-view-controller/index.md b/model-view-controller/index.md index f96daf243..1ba1089c0 100644 --- a/model-view-controller/index.md +++ b/model-view-controller/index.md @@ -21,3 +21,5 @@ display. **Credits:** * [Trygve Reenskaug - Model-view-controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) +* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2) +* [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420) diff --git a/model-view-controller/pom.xml b/model-view-controller/pom.xml index 7162c71d9..8c9c07809 100644 --- a/model-view-controller/pom.xml +++ b/model-view-controller/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 model-view-controller diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/App.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/App.java deleted file mode 100644 index 0b74f4b5a..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/App.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -/** - * - * In this second example the model-view relationship is different. This time we use the Observer pattern to notify - * the {@link GiantView} each time the {@link GiantModel} is changed. This way the {@link GiantController} responsibilities - * are narrowed and it only needs to modify the {@link GiantModel} according to the user input. - * - */ -public class App { - - /** - * Program entry point - * @param args command line args - */ - public static void main( String[] args ) { - // create model, view and controller - GiantModel giant = new GiantModel(Health.HEALTHY, Fatigue.ALERT, Nourishment.SATURATED); - GiantView view = new GiantView(); - GiantController controller = new GiantController(giant, view); - // initial display - controller.updateView(); - // controller receives some interactions that affect the giant - // model modifications trigger the view rendering automatically - controller.setHealth(Health.WOUNDED); - controller.setNourishment(Nourishment.HUNGRY); - controller.setFatigue(Fatigue.TIRED); - } -} diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Fatigue.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Fatigue.java deleted file mode 100644 index 301a579fb..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Fatigue.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -/** - * - * Fatigue enumeration - * - */ -public enum Fatigue { - - ALERT("alert"), TIRED("tired"), SLEEPING("sleeping"); - - private String title; - - Fatigue(String title) { - this.title = title; - } - - @Override - public String toString() { - return title; - } -} diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantController.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantController.java deleted file mode 100644 index e892b2946..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantController.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -/** - * - * GiantController updates the giant model. - * - */ -public class GiantController { - - private GiantModel giant; - private GiantView view; - - public GiantController(GiantModel giant, GiantView view) { - this.giant = giant; - this.view = view; - this.giant.registerObserver(this.view); - } - - public Health getHealth() { - return giant.getHealth(); - } - - public void setHealth(Health health) { - this.giant.setHealth(health); - } - - public Fatigue getFatigue() { - return giant.getFatigue(); - } - - public void setFatigue(Fatigue fatigue) { - this.giant.setFatigue(fatigue); - } - - public Nourishment getNourishment() { - return giant.getNourishment(); - } - - public void setNourishment(Nourishment nourishment) { - this.giant.setNourishment(nourishment); - } - - public void updateView() { - this.view.displayGiant(giant); - } -} diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantModel.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantModel.java deleted file mode 100644 index 84b32a50a..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantModel.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -import java.util.ArrayList; -import java.util.List; - -/** - * - * GiantModel contains the giant data. - * - */ -public class GiantModel { - - private Health health; - private Fatigue fatigue; - private Nourishment nourishment; - private List observers = new ArrayList<>(); - - GiantModel(Health health, Fatigue fatigue, Nourishment nourishment) { - this.health = health; - this.fatigue = fatigue; - this.nourishment = nourishment; - } - - public Health getHealth() { - return health; - } - - public void setHealth(Health health) { - this.health = health; - notifyObservers(); - } - - public Fatigue getFatigue() { - return fatigue; - } - - public void setFatigue(Fatigue fatigue) { - this.fatigue = fatigue; - notifyObservers(); - } - - public Nourishment getNourishment() { - return nourishment; - } - - public void setNourishment(Nourishment nourishment) { - this.nourishment = nourishment; - notifyObservers(); - } - - @Override - public String toString() { - return String.format("The giant looks %s, %s and %s.", health, fatigue, nourishment); - } - - public void registerObserver(GiantModelObserver observer) { - observers.add(observer); - } - - private void notifyObservers() { - observers.stream().forEach((GiantModelObserver o) -> o.modelChanged(this)); - } -} diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantModelObserver.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantModelObserver.java deleted file mode 100644 index 6363ef4f7..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantModelObserver.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -/** - * - * GiantModelObserver is the interface for delivering update notifications. - * - */ -public interface GiantModelObserver { - - void modelChanged(GiantModel model); - -} diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantView.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantView.java deleted file mode 100644 index f4cebad80..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/GiantView.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -/** - * - * GiantView displays the giant - * - */ -public class GiantView implements GiantModelObserver { - - public void displayGiant(GiantModel giant) { - System.out.println(giant); - } - - @Override - public void modelChanged(GiantModel model) { - displayGiant(model); - } -} diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Health.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Health.java deleted file mode 100644 index e4b8ed9a7..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Health.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -/** - * - * Health enumeration - * - */ -public enum Health { - - HEALTHY("healthy"), WOUNDED("wounded"), DEAD("dead"); - - private String title; - - Health(String title) { - this.title = title; - } - - @Override - public String toString() { - return title; - } -} diff --git a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Nourishment.java b/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Nourishment.java deleted file mode 100644 index c1a8253c3..000000000 --- a/model-view-controller/src/main/java/com/iluwatar/model/view/controller/with/observer/Nourishment.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -/** - * - * Nourishment enumeration - * - */ -public enum Nourishment { - - SATURATED("saturated"), HUNGRY("hungry"), STARVING("starving"); - - private String title; - - Nourishment(String title) { - this.title = title; - } - - @Override - public String toString() { - return title; - } -} diff --git a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/with/observer/AppTest.java b/model-view-controller/src/test/java/com/iluwatar/model/view/controller/with/observer/AppTest.java deleted file mode 100644 index 9a43ce7bc..000000000 --- a/model-view-controller/src/test/java/com/iluwatar/model/view/controller/with/observer/AppTest.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.iluwatar.model.view.controller.with.observer; - -import org.junit.Test; - -import com.iluwatar.model.view.controller.with.observer.App; - -/** - * - * Application test - * - */ -public class AppTest { - - @Test - public void test() { - String[] args = {}; - App.main(args); - } -} diff --git a/model-view-presenter/index.md b/model-view-presenter/index.md index 609c59c13..b51268013 100644 --- a/model-view-presenter/index.md +++ b/model-view-presenter/index.md @@ -17,3 +17,7 @@ situations * when you want to improve the "Separation of Concerns" principle in presentation logic * when a user interface development and testing is necessary. + +**Real world examples:** + +* [MVP4J](https://github.com/amineoualialami/mvp4j) diff --git a/model-view-presenter/pom.xml b/model-view-presenter/pom.xml index 41a2d2013..4f2d320ba 100644 --- a/model-view-presenter/pom.xml +++ b/model-view-presenter/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 model-view-presenter model-view-presenter diff --git a/multiton/pom.xml b/multiton/pom.xml index 6ea1ad2fa..9735bc8ea 100644 --- a/multiton/pom.xml +++ b/multiton/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 multiton diff --git a/naked-objects/dom/pom.xml b/naked-objects/dom/pom.xml index cadf6d82e..b0efdb435 100644 --- a/naked-objects/dom/pom.xml +++ b/naked-objects/dom/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.6.0 + 1.7.0 naked-objects-dom diff --git a/naked-objects/fixture/pom.xml b/naked-objects/fixture/pom.xml index 33cd798f7..bbed2fe1b 100644 --- a/naked-objects/fixture/pom.xml +++ b/naked-objects/fixture/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.6.0 + 1.7.0 naked-objects-fixture diff --git a/naked-objects/integtests/pom.xml b/naked-objects/integtests/pom.xml index 1fd518bb1..221b072e5 100644 --- a/naked-objects/integtests/pom.xml +++ b/naked-objects/integtests/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.6.0 + 1.7.0 naked-objects-integtests diff --git a/naked-objects/pom.xml b/naked-objects/pom.xml index 8cac48a09..067d4a5a8 100644 --- a/naked-objects/pom.xml +++ b/naked-objects/pom.xml @@ -15,7 +15,7 @@ java-design-patterns com.iluwatar - 1.6.0 + 1.7.0 naked-objects @@ -27,7 +27,7 @@ - 1.9.0-SNAPSHOT + 1.9.0 UTF-8 UTF-8 @@ -350,17 +350,17 @@ ${project.groupId} naked-objects-dom - 1.6.0 + 1.7.0 ${project.groupId} naked-objects-fixture - 1.6.0 + 1.7.0 ${project.groupId} naked-objects-webapp - 1.6.0 + 1.7.0 diff --git a/naked-objects/webapp/pom.xml b/naked-objects/webapp/pom.xml index 3e018995a..bc7d7c299 100644 --- a/naked-objects/webapp/pom.xml +++ b/naked-objects/webapp/pom.xml @@ -16,7 +16,7 @@ com.iluwatar naked-objects - 1.6.0 + 1.7.0 naked-objects-webapp diff --git a/null-object/pom.xml b/null-object/pom.xml index eec32fd4d..a372851ed 100644 --- a/null-object/pom.xml +++ b/null-object/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 null-object diff --git a/object-pool/pom.xml b/object-pool/pom.xml index 4a3b237c6..528e3db16 100644 --- a/object-pool/pom.xml +++ b/object-pool/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 object-pool diff --git a/observer/index.md b/observer/index.md index d5b380a30..fedb4cb8c 100644 --- a/observer/index.md +++ b/observer/index.md @@ -4,7 +4,10 @@ title: Observer folder: observer permalink: /patterns/observer/ categories: Behavioral -tags: Java +tags: + - Java + - Difficulty-Beginner + - Gang Of Four --- **Intent:** Define a one-to-many dependency between objects so that when one @@ -26,3 +29,7 @@ automatically. **Real world examples:** * [java.util.Observer](http://docs.oracle.com/javase/8/docs/api/java/util/Observer.html) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/observer/pom.xml b/observer/pom.xml index 19e93421c..023d93bea 100644 --- a/observer/pom.xml +++ b/observer/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 observer diff --git a/observer/src/main/java/com/iluwatar/observer/App.java b/observer/src/main/java/com/iluwatar/observer/App.java index bd99da841..bc4742a14 100644 --- a/observer/src/main/java/com/iluwatar/observer/App.java +++ b/observer/src/main/java/com/iluwatar/observer/App.java @@ -6,8 +6,17 @@ import com.iluwatar.observer.generic.GWeather; /** * - * Observer pattern defines one-to-many relationship between objects. The target - * object sends change notifications to its registered observers. + * The Observer pattern is a software design pattern in which an object, called + * the subject, maintains a list of its dependents, called observers, and notifies + * them automatically of any state changes, usually by calling one of their methods. + * It is mainly used to implement distributed event handling systems. The Observer + * pattern is also a key part in the familiar model–view–controller (MVC) architectural + * pattern. The Observer pattern is implemented in numerous programming libraries and + * systems, including almost all GUI toolkits. + *

+ * In this example {@link Weather} has a state that can be observed. The {@link Orcs} + * and {@link Hobbits} register as observers and receive notifications when the + * {@link Weather} changes. * */ public class App { diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml index 2a0653981..06d9f34de 100644 --- a/poison-pill/pom.xml +++ b/poison-pill/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 poison-pill diff --git a/poison-pill/src/main/java/com/iluwatar/poison/pill/App.java b/poison-pill/src/main/java/com/iluwatar/poison/pill/App.java index 526ca5b86..91d30fddd 100644 --- a/poison-pill/src/main/java/com/iluwatar/poison/pill/App.java +++ b/poison-pill/src/main/java/com/iluwatar/poison/pill/App.java @@ -2,12 +2,12 @@ package com.iluwatar.poison.pill; /** * One of the possible approaches to terminate Producer-Consumer pattern is using the Poison Pill idiom. - * If you use Poison Pill as the termination signal then Producer is responsible to notify Consumer that exchange is over - * and reject any further messages. Consumer receiving Poison Pill will stop reading messages from the queue. - * You must also ensure that the Poison Pill will be the last message that will be read from the queue (if you have - * prioritized queue then this can be tricky). + * If you use Poison Pill as the termination signal then Producer is responsible to notify Consumer that + * the exchange is over and reject any further messages. The Consumer receiving Poison Pill will stop + * reading messages from the queue. You must also ensure that the Poison Pill will be the last message + * that will be read from the queue (if you have prioritized queue then this can be tricky). *

- * In simple cases as Poison Pill can be used just null-reference, but holding unique separate shared + * In simple cases the Poison Pill can be just a null-reference, but holding a unique separate shared * object-marker (with name "Poison" or "Poison Pill") is more clear and self describing. * */ diff --git a/pom.xml b/pom.xml index e36687eb4..317865275 100644 --- a/pom.xml +++ b/pom.xml @@ -1,20 +1,21 @@ - + 4.0.0 com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 pom UTF-8 - 5.0.0.Final - 1.8.2.RELEASE + 5.0.1.Final + 1.9.0.RELEASE 1.4.188 4.12 3.0 - 3.1.0 + 4.0.0 0.7.2.201409121644 1.4 2.15.3 @@ -73,12 +74,12 @@ repository async-method-invocation monostate - business-delegate - half-sync-half-async step-builder layers message-channel - + fluentinterface + reactor + @@ -206,6 +207,30 @@ + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.15 + + + validate + + check + + validate + + checkstyle.xml + UTF-8 + false + false + + + + diff --git a/private-class-data/pom.xml b/private-class-data/pom.xml index 70a716062..274739257 100644 --- a/private-class-data/pom.xml +++ b/private-class-data/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 private-class-data diff --git a/property/pom.xml b/property/pom.xml index 5435f06f5..f32a4008e 100644 --- a/property/pom.xml +++ b/property/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 property diff --git a/property/src/main/java/com/iluwatar/property/App.java b/property/src/main/java/com/iluwatar/property/App.java index 54c140574..ac46f5448 100644 --- a/property/src/main/java/com/iluwatar/property/App.java +++ b/property/src/main/java/com/iluwatar/property/App.java @@ -4,12 +4,14 @@ import com.iluwatar.property.Character.Type; /** * - * Example of {@link Character} instantiation using the Property pattern (also known as Prototype inheritance). + * The Property pattern is also known as Prototype inheritance. *

* In prototype inheritance instead of classes, as opposite to Java class inheritance, * objects are used to create another objects and object hierarchies. Hierarchies are created using prototype chain * through delegation: every object has link to parent object. Any base (parent) object can be amended at runtime * (by adding or removal of some property), and all child objects will be affected as result. + *

+ * In this example we demonstrate {@link Character} instantiation using the Property pattern. * */ public class App { diff --git a/prototype/index.md b/prototype/index.md index cab97f7dc..9d108ff06 100644 --- a/prototype/index.md +++ b/prototype/index.md @@ -4,7 +4,9 @@ title: Prototype folder: prototype permalink: /patterns/prototype/ categories: Creational -tags: Java +tags: + - Java + - Gang Of Four --- **Intent:** Specify the kinds of objects to create using a prototypical @@ -21,3 +23,7 @@ instance, and create new objects by copying this prototype. **Real world examples:** * [java.lang.Object#clone()](http://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone%28%29) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/prototype/pom.xml b/prototype/pom.xml index 0ebba706e..d5772da60 100644 --- a/prototype/pom.xml +++ b/prototype/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 prototype diff --git a/prototype/src/main/java/com/iluwatar/prototype/App.java b/prototype/src/main/java/com/iluwatar/prototype/App.java index 4003862cb..74bb6989d 100644 --- a/prototype/src/main/java/com/iluwatar/prototype/App.java +++ b/prototype/src/main/java/com/iluwatar/prototype/App.java @@ -2,9 +2,14 @@ package com.iluwatar.prototype; /** * - * In Prototype we have a factory class ({@link HeroFactoryImpl}) producing objects by - * cloning the existing ones. In this example the factory's prototype objects are - * given as constructor parameters. + * The Prototype pattern is a creational design pattern in software development. It is + * used when the type of objects to create is determined by a prototypical instance, + * which is cloned to produce new objects. This pattern is used to: + * - avoid subclasses of an object creator in the client application, like the abstract factory pattern does. + * - avoid the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) + *

+ * In this example we have a factory class ({@link HeroFactoryImpl}) producing objects by + * cloning the existing ones. The factory's prototype objects are given as constructor parameters. * */ public class App { diff --git a/proxy/index.md b/proxy/index.md index 96ea40714..f863a96a5 100644 --- a/proxy/index.md +++ b/proxy/index.md @@ -4,7 +4,10 @@ title: Proxy folder: proxy permalink: /patterns/proxy/ categories: Structural -tags: Java +tags: + - Java + - Gang Of Four + - Difficulty-Intermediate --- **Intent:** Provide a surrogate or placeholder for another object to control @@ -32,3 +35,7 @@ are several common situations in which the Proxy pattern is applicable * [java.lang.reflect.Proxy](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Proxy.html) * [Apache Commons Proxy](https://commons.apache.org/proper/commons-proxy/) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/proxy/pom.xml b/proxy/pom.xml index 1f625d736..750c12b84 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 proxy diff --git a/proxy/src/main/java/com/iluwatar/proxy/App.java b/proxy/src/main/java/com/iluwatar/proxy/App.java index fb401ac9f..420ad5c0a 100644 --- a/proxy/src/main/java/com/iluwatar/proxy/App.java +++ b/proxy/src/main/java/com/iluwatar/proxy/App.java @@ -2,7 +2,18 @@ package com.iluwatar.proxy; /** * - * Proxy ({@link WizardTowerProxy}) controls access to the actual object ({@link WizardTower}). + * A proxy, in its most general form, is a class functioning as an interface to something else. + * The proxy could interface to anything: a network connection, a large object in memory, a file, + * or some other resource that is expensive or impossible to duplicate. In short, a proxy is a + * wrapper or agent object that is being called by the client to access the real serving object + * behind the scenes. + *

+ * The Proxy design pattern allows you to provide an interface to other objects by creating a + * wrapper class as the proxy. The wrapper class, which is the proxy, can add additional + * functionality to the object of interest without changing the object's code. + *

+ * In this example the proxy ({@link WizardTowerProxy}) controls access to the actual object + * ({@link WizardTower}). * */ public class App { diff --git a/reactor/etc/reactor.png b/reactor/etc/reactor.png new file mode 100644 index 000000000..abe705682 Binary files /dev/null and b/reactor/etc/reactor.png differ diff --git a/reactor/etc/reactor.ucls b/reactor/etc/reactor.ucls new file mode 100644 index 000000000..90e28cdd7 --- /dev/null +++ b/reactor/etc/reactor.ucls @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/reactor/index.md b/reactor/index.md new file mode 100644 index 000000000..6e20598d2 --- /dev/null +++ b/reactor/index.md @@ -0,0 +1,31 @@ +--- +layout: pattern +title: Reactor +folder: reactor +permalink: /patterns/reactor/ +categories: Architectural +tags: + - Java + - Difficulty-Expert +--- + +**Intent:** The Reactor design pattern handles service requests that are delivered concurrently to an application by one or more clients. The application can register specific handlers for processing which are called by reactor on specific events. Dispatching of event handlers is performed by an initiation dispatcher, which manages the registered event handlers. Demultiplexing of service requests is performed by a synchronous event demultiplexer. + +![Reactor](./etc/reactor.png "Reactor") + +**Applicability:** Use Reactor pattern when + +* a server application needs to handle concurrent service requests from multiple clients. +* a server application needs to be available for receiving requests from new clients even when handling older client requests. +* a server must maximize throughput, minimize latency and use CPU efficiently without blocking. + +**Real world examples:** + +* [Spring Reactor](http://projectreactor.io/) + +**Credits** + +* [Douglas C. Schmidt - Reactor](https://www.dre.vanderbilt.edu/~schmidt/PDF/Reactor.pdf) +* [Pattern Oriented Software Architecture Vol I-V](http://www.amazon.com/Pattern-Oriented-Software-Architecture-Volume-Patterns/dp/0471958697) +* [Doug Lea - Scalable IO in Java](http://gee.cs.oswego.edu/dl/cpjslides/nio.pdf) +* [Netty](http://netty.io/) diff --git a/reactor/pom.xml b/reactor/pom.xml new file mode 100644 index 000000000..516a4b93c --- /dev/null +++ b/reactor/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.7.0 + + reactor + + + junit + junit + test + + + diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/App.java b/reactor/src/main/java/com/iluwatar/reactor/app/App.java new file mode 100644 index 000000000..7bb01ddc8 --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/app/App.java @@ -0,0 +1,140 @@ +package com.iluwatar.reactor.app; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.iluwatar.reactor.framework.AbstractNioChannel; +import com.iluwatar.reactor.framework.ChannelHandler; +import com.iluwatar.reactor.framework.Dispatcher; +import com.iluwatar.reactor.framework.NioDatagramChannel; +import com.iluwatar.reactor.framework.NioReactor; +import com.iluwatar.reactor.framework.NioServerSocketChannel; +import com.iluwatar.reactor.framework.ThreadPoolDispatcher; + +/** + * This application demonstrates Reactor pattern. The example demonstrated is a Distributed Logging + * Service where it listens on multiple TCP or UDP sockets for incoming log requests. + * + *

+ * INTENT
+ * The Reactor design pattern handles service requests that are delivered concurrently to an + * application by one or more clients. The application can register specific handlers for processing + * which are called by reactor on specific events. + * + *

+ * PROBLEM
+ * Server applications in a distributed system must handle multiple clients that send them service + * requests. Following forces need to be resolved: + *

+ * + *

+ * PARTICIPANTS
+ *

+ * + *

+ * The application utilizes single thread to listen for requests on all ports. It does not create a + * separate thread for each client, which provides better scalability under load (number of clients + * increase). + * + *

+ * The example uses Java NIO framework to implement the Reactor. + * + */ +public class App { + + private NioReactor reactor; + private List channels = new ArrayList<>(); + private Dispatcher dispatcher; + + /** + * Creates an instance of App which will use provided dispatcher for dispatching events on reactor. + * @param dispatcher the dispatcher that will be used to dispatch events. + */ + public App(Dispatcher dispatcher) { + this.dispatcher = dispatcher; + } + + /** + * App entry. + * + * @throws IOException + */ + public static void main(String[] args) throws IOException { + new App(new ThreadPoolDispatcher(2)).start(); + } + + /** + * Starts the NIO reactor. + * + * @throws IOException if any channel fails to bind. + */ + public void start() throws IOException { + /* + * The application can customize its event dispatching mechanism. + */ + reactor = new NioReactor(dispatcher); + + /* + * This represents application specific business logic that dispatcher will call on appropriate + * events. These events are read events in our example. + */ + LoggingHandler loggingHandler = new LoggingHandler(); + + /* + * Our application binds to multiple channels and uses same logging handler to handle incoming + * log requests. + */ + reactor.registerChannel(tcpChannel(6666, loggingHandler)).registerChannel(tcpChannel(6667, loggingHandler)) + .registerChannel(udpChannel(6668, loggingHandler)).start(); + } + + /** + * Stops the NIO reactor. This is a blocking call. + * + * @throws InterruptedException if interrupted while stopping the reactor. + * @throws IOException if any I/O error occurs + */ + public void stop() throws InterruptedException, IOException { + reactor.stop(); + dispatcher.stop(); + for (AbstractNioChannel channel : channels) { + channel.getJavaChannel().close(); + } + } + + private AbstractNioChannel tcpChannel(int port, ChannelHandler handler) throws IOException { + NioServerSocketChannel channel = new NioServerSocketChannel(port, handler); + channel.bind(); + channels.add(channel); + return channel; + } + + private AbstractNioChannel udpChannel(int port, ChannelHandler handler) throws IOException { + NioDatagramChannel channel = new NioDatagramChannel(port, handler); + channel.bind(); + channels.add(channel); + return channel; + } +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java new file mode 100644 index 000000000..659f5da21 --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/app/AppClient.java @@ -0,0 +1,163 @@ +package com.iluwatar.reactor.app; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * Represents the clients of Reactor pattern. Multiple clients are run concurrently and send logging + * requests to Reactor. + */ +public class AppClient { + private final ExecutorService service = Executors.newFixedThreadPool(4); + + /** + * App client entry. + * + * @throws IOException if any I/O error occurs. + */ + public static void main(String[] args) throws IOException { + AppClient appClient = new AppClient(); + appClient.start(); + } + + /** + * Starts the logging clients. + * + * @throws IOException if any I/O error occurs. + */ + public void start() throws IOException { + service.execute(new TCPLoggingClient("Client 1", 6666)); + service.execute(new TCPLoggingClient("Client 2", 6667)); + service.execute(new UDPLoggingClient("Client 3", 6668)); + service.execute(new UDPLoggingClient("Client 4", 6668)); + } + + /** + * Stops logging clients. This is a blocking call. + */ + public void stop() { + service.shutdown(); + if (!service.isTerminated()) { + service.shutdownNow(); + try { + service.awaitTermination(1000, TimeUnit.SECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + private static void artificialDelayOf(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + /** + * A logging client that sends requests to Reactor on TCP socket. + */ + static class TCPLoggingClient implements Runnable { + + private final int serverPort; + private final String clientName; + + /** + * Creates a new TCP logging client. + * + * @param clientName the name of the client to be sent in logging requests. + * @param port the port on which client will send logging requests. + */ + public TCPLoggingClient(String clientName, int serverPort) { + this.clientName = clientName; + this.serverPort = serverPort; + } + + public void run() { + try (Socket socket = new Socket(InetAddress.getLocalHost(), serverPort)) { + OutputStream outputStream = socket.getOutputStream(); + PrintWriter writer = new PrintWriter(outputStream); + sendLogRequests(writer, socket.getInputStream()); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + private void sendLogRequests(PrintWriter writer, InputStream inputStream) throws IOException { + for (int i = 0; i < 4; i++) { + writer.println(clientName + " - Log request: " + i); + writer.flush(); + + byte[] data = new byte[1024]; + int read = inputStream.read(data, 0, data.length); + if (read == 0) { + System.out.println("Read zero bytes"); + } else { + System.out.println(new String(data, 0, read)); + } + + artificialDelayOf(100); + } + } + + } + + /** + * A logging client that sends requests to Reactor on UDP socket. + */ + static class UDPLoggingClient implements Runnable { + private final String clientName; + private final InetSocketAddress remoteAddress; + + /** + * Creates a new UDP logging client. + * + * @param clientName the name of the client to be sent in logging requests. + * @param port the port on which client will send logging requests. + * @throws UnknownHostException if localhost is unknown + */ + public UDPLoggingClient(String clientName, int port) throws UnknownHostException { + this.clientName = clientName; + this.remoteAddress = new InetSocketAddress(InetAddress.getLocalHost(), port); + } + + @Override + public void run() { + try (DatagramSocket socket = new DatagramSocket()) { + for (int i = 0; i < 4; i++) { + + String message = clientName + " - Log request: " + i; + DatagramPacket request = new DatagramPacket(message.getBytes(), message.getBytes().length, remoteAddress); + + socket.send(request); + + byte[] data = new byte[1024]; + DatagramPacket reply = new DatagramPacket(data, data.length); + socket.receive(reply); + if (reply.getLength() == 0) { + System.out.println("Read zero bytes"); + } else { + System.out.println(new String(reply.getData(), 0, reply.getLength())); + } + + artificialDelayOf(100); + } + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java b/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java new file mode 100644 index 000000000..0845303df --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/app/LoggingHandler.java @@ -0,0 +1,59 @@ +package com.iluwatar.reactor.app; + +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; + +import com.iluwatar.reactor.framework.AbstractNioChannel; +import com.iluwatar.reactor.framework.ChannelHandler; +import com.iluwatar.reactor.framework.NioDatagramChannel.DatagramPacket; + +/** + * Logging server application logic. It logs the incoming requests on standard console and returns a + * canned acknowledgement back to the remote peer. + */ +public class LoggingHandler implements ChannelHandler { + + private static final byte[] ACK = "Data logged successfully".getBytes(); + + /** + * Decodes the received data and logs it on standard console. + */ + @Override + public void handleChannelRead(AbstractNioChannel channel, Object readObject, SelectionKey key) { + /* + * As this handler is attached with both TCP and UDP channels we need to check whether the data + * received is a ByteBuffer (from TCP channel) or a DatagramPacket (from UDP channel). + */ + if (readObject instanceof ByteBuffer) { + doLogging(((ByteBuffer) readObject)); + sendReply(channel, key); + } else if (readObject instanceof DatagramPacket) { + DatagramPacket datagram = (DatagramPacket) readObject; + doLogging(datagram.getData()); + sendReply(channel, datagram, key); + } else { + throw new IllegalStateException("Unknown data received"); + } + } + + private void sendReply(AbstractNioChannel channel, DatagramPacket incomingPacket, SelectionKey key) { + /* + * Create a reply acknowledgement datagram packet setting the receiver to the sender of incoming + * message. + */ + DatagramPacket replyPacket = new DatagramPacket(ByteBuffer.wrap(ACK)); + replyPacket.setReceiver(incomingPacket.getSender()); + + channel.write(replyPacket, key); + } + + private void sendReply(AbstractNioChannel channel, SelectionKey key) { + ByteBuffer buffer = ByteBuffer.wrap(ACK); + channel.write(buffer, key); + } + + private void doLogging(ByteBuffer data) { + // assuming UTF-8 :( + System.out.println(new String(data.array(), 0, data.limit())); + } +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java new file mode 100644 index 000000000..9f2f8a95c --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/AbstractNioChannel.java @@ -0,0 +1,151 @@ +package com.iluwatar.reactor.framework; + +import java.io.IOException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * This represents the Handle of Reactor pattern. These are resources managed by OS which can + * be submitted to {@link NioReactor}. + * + *

+ * This class serves has the responsibility of reading the data when a read event occurs and writing + * the data back when the channel is writable. It leaves the reading and writing of data on the + * concrete implementation. It provides a block writing mechanism wherein when any + * {@link ChannelHandler} wants to write data back, it queues the data in pending write queue and + * clears it in block manner. This provides better throughput. + */ +public abstract class AbstractNioChannel { + + private final SelectableChannel channel; + private final ChannelHandler handler; + private final Map> channelToPendingWrites = new ConcurrentHashMap<>(); + private NioReactor reactor; + + /** + * Creates a new channel. + * + * @param handler which will handle events occurring on this channel. + * @param channel a NIO channel to be wrapped. + */ + public AbstractNioChannel(ChannelHandler handler, SelectableChannel channel) { + this.handler = handler; + this.channel = channel; + } + + /** + * Injects the reactor in this channel. + */ + void setReactor(NioReactor reactor) { + this.reactor = reactor; + } + + /** + * @return the wrapped NIO channel. + */ + public SelectableChannel getJavaChannel() { + return channel; + } + + /** + * The operation in which the channel is interested, this operation is provided to + * {@link Selector}. + * + * @return interested operation. + * @see SelectionKey + */ + public abstract int getInterestedOps(); + + /** + * Binds the channel on provided port. + * + * @throws IOException if any I/O error occurs. + */ + public abstract void bind() throws IOException; + + /** + * Reads the data using the key and returns the read data. The underlying channel should be + * fetched using {@link SelectionKey#channel()}. + * + * @param key the key on which read event occurred. + * @return data read. + * @throws IOException if any I/O error occurs. + */ + public abstract Object read(SelectionKey key) throws IOException; + + /** + * @return the handler associated with this channel. + */ + public ChannelHandler getHandler() { + return handler; + } + + /* + * Called from the context of reactor thread when the key becomes writable. The channel writes the + * whole pending block of data at once. + */ + void flush(SelectionKey key) throws IOException { + Queue pendingWrites = channelToPendingWrites.get(key.channel()); + while (true) { + Object pendingWrite = pendingWrites.poll(); + if (pendingWrite == null) { + // We don't have anything more to write so channel is interested in reading more data + reactor.changeOps(key, SelectionKey.OP_READ); + break; + } + + // ask the concrete channel to make sense of data and write it to java channel + doWrite(pendingWrite, key); + } + } + + /** + * Writes the data to the channel. + * + * @param pendingWrite the data to be written on channel. + * @param key the key which is writable. + * @throws IOException if any I/O error occurs. + */ + protected abstract void doWrite(Object pendingWrite, SelectionKey key) throws IOException; + + /** + * Queues the data for writing. The data is not guaranteed to be written on underlying channel + * when this method returns. It will be written when the channel is flushed. + * + *

+ * This method is used by the {@link ChannelHandler} to send reply back to the client.
+ * Example: + * + *

+   * 
+   * {@literal @}Override
+   * public void handleChannelRead(AbstractNioChannel channel, Object readObject, SelectionKey key) {
+   *   byte[] data = ((ByteBuffer)readObject).array();
+   *   ByteBuffer buffer = ByteBuffer.wrap("Server reply".getBytes());
+   *   channel.write(buffer, key);
+   * }
+   * 
+   * 
+   * @param data the data to be written on underlying channel.
+   * @param key the key which is writable.
+   */
+  public void write(Object data, SelectionKey key) {
+    Queue pendingWrites = this.channelToPendingWrites.get(key.channel());
+    if (pendingWrites == null) {
+      synchronized (this.channelToPendingWrites) {
+        pendingWrites = this.channelToPendingWrites.get(key.channel());
+        if (pendingWrites == null) {
+          pendingWrites = new ConcurrentLinkedQueue<>();
+          this.channelToPendingWrites.put(key.channel(), pendingWrites);
+        }
+      }
+    }
+    pendingWrites.add(data);
+    reactor.changeOps(key, SelectionKey.OP_WRITE);
+  }
+}
diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/ChannelHandler.java b/reactor/src/main/java/com/iluwatar/reactor/framework/ChannelHandler.java
new file mode 100644
index 000000000..381738ecd
--- /dev/null
+++ b/reactor/src/main/java/com/iluwatar/reactor/framework/ChannelHandler.java
@@ -0,0 +1,23 @@
+package com.iluwatar.reactor.framework;
+
+import java.nio.channels.SelectionKey;
+
+/**
+ * Represents the EventHandler of Reactor pattern. It handles the incoming events dispatched
+ * to it by the {@link Dispatcher}. This is where the application logic resides.
+ * 
+ * 

+ * A {@link ChannelHandler} can be associated with one or many {@link AbstractNioChannel}s, and + * whenever an event occurs on any of the associated channels, the handler is notified of the event. + */ +public interface ChannelHandler { + + /** + * Called when the {@code channel} receives some data from remote peer. + * + * @param channel the channel from which the data was received. + * @param readObject the data read. + * @param key the key on which read event occurred. + */ + void handleChannelRead(AbstractNioChannel channel, Object readObject, SelectionKey key); +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/Dispatcher.java b/reactor/src/main/java/com/iluwatar/reactor/framework/Dispatcher.java new file mode 100644 index 000000000..78aeb84df --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/Dispatcher.java @@ -0,0 +1,41 @@ +package com.iluwatar.reactor.framework; + +import java.nio.channels.SelectionKey; + +/** + * Represents the event dispatching strategy. When {@link NioReactor} senses any event on the + * registered {@link AbstractNioChannel}s then it de-multiplexes the event type, read or write or + * connect, and then calls the {@link Dispatcher} to dispatch the read events. This decouples the + * I/O processing from application specific processing.
+ * Dispatcher should call the {@link ChannelHandler} associated with the channel on which event + * occurred. + * + *

+ * The application can customize the way in which event is dispatched such as using the reactor + * thread to dispatch event to channels or use a worker pool to do the non I/O processing. + * + * @see SameThreadDispatcher + * @see ThreadPoolDispatcher + */ +public interface Dispatcher { + /** + * This hook method is called when read event occurs on particular channel. The data read is + * provided in readObject. The implementation should dispatch this read event to the + * associated {@link ChannelHandler} of channel. + * + *

+ * The type of readObject depends on the channel on which data was received. + * + * @param channel on which read event occurred + * @param readObject object read by channel + * @param key on which event occurred + */ + void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key); + + /** + * Stops dispatching events and cleans up any acquired resources such as threads. + * + * @throws InterruptedException if interrupted while stopping dispatcher. + */ + void stop() throws InterruptedException; +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java new file mode 100644 index 000000000..a2ff3d3d8 --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioDatagramChannel.java @@ -0,0 +1,159 @@ +package com.iluwatar.reactor.framework; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.DatagramChannel; +import java.nio.channels.SelectionKey; + +/** + * A wrapper over {@link DatagramChannel} which can read and write data on a DatagramChannel. + */ +public class NioDatagramChannel extends AbstractNioChannel { + + private final int port; + + /** + * Creates a {@link DatagramChannel} which will bind at provided port and use handler + * to handle incoming events on this channel. + *

+ * Note the constructor does not bind the socket, {@link #bind()} method should be called for + * binding the socket. + * + * @param port the port to be bound to listen for incoming datagram requests. + * @param handler the handler to be used for handling incoming requests on this channel. + * @throws IOException if any I/O error occurs. + */ + public NioDatagramChannel(int port, ChannelHandler handler) throws IOException { + super(handler, DatagramChannel.open()); + this.port = port; + } + + @Override + public int getInterestedOps() { + /* + * there is no need to accept connections in UDP, so the channel shows interest in reading data. + */ + return SelectionKey.OP_READ; + } + + /** + * Reads and returns a {@link DatagramPacket} from the underlying channel. + * + * @return the datagram packet read having the sender address. + */ + @Override + public DatagramPacket read(SelectionKey key) throws IOException { + ByteBuffer buffer = ByteBuffer.allocate(1024); + SocketAddress sender = ((DatagramChannel) key.channel()).receive(buffer); + + /* + * It is required to create a DatagramPacket because we need to preserve which socket address + * acts as destination for sending reply packets. + */ + buffer.flip(); + DatagramPacket packet = new DatagramPacket(buffer); + packet.setSender(sender); + + return packet; + } + + /** + * @return the underlying datagram channel. + */ + @Override + public DatagramChannel getJavaChannel() { + return (DatagramChannel) super.getJavaChannel(); + } + + /** + * Binds UDP socket on the provided port. + * + * @throws IOException if any I/O error occurs. + */ + @Override + public void bind() throws IOException { + getJavaChannel().socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), port)); + getJavaChannel().configureBlocking(false); + System.out.println("Bound UDP socket at port: " + port); + } + + /** + * Writes the pending {@link DatagramPacket} to the underlying channel sending data to the + * intended receiver of the packet. + */ + @Override + protected void doWrite(Object pendingWrite, SelectionKey key) throws IOException { + DatagramPacket pendingPacket = (DatagramPacket) pendingWrite; + getJavaChannel().send(pendingPacket.getData(), pendingPacket.getReceiver()); + } + + /** + * Writes the outgoing {@link DatagramPacket} to the channel. The intended receiver of the + * datagram packet must be set in the data using + * {@link DatagramPacket#setReceiver(SocketAddress)}. + */ + @Override + public void write(Object data, SelectionKey key) { + super.write(data, key); + } + + /** + * Container of data used for {@link NioDatagramChannel} to communicate with remote peer. + */ + public static class DatagramPacket { + private SocketAddress sender; + private ByteBuffer data; + private SocketAddress receiver; + + /** + * Creates a container with underlying data. + * + * @param data the underlying message to be written on channel. + */ + public DatagramPacket(ByteBuffer data) { + this.data = data; + } + + /** + * @return the sender address. + */ + public SocketAddress getSender() { + return sender; + } + + /** + * Sets the sender address of this packet. + * + * @param sender the sender address. + */ + public void setSender(SocketAddress sender) { + this.sender = sender; + } + + /** + * @return the receiver address. + */ + public SocketAddress getReceiver() { + return receiver; + } + + /** + * Sets the intended receiver address. This must be set when writing to the channel. + * + * @param receiver the receiver address. + */ + public void setReceiver(SocketAddress receiver) { + this.receiver = receiver; + } + + /** + * @return the underlying message that will be written on channel. + */ + public ByteBuffer getData() { + return data; + } + } +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java new file mode 100644 index 000000000..16c13e5f9 --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioReactor.java @@ -0,0 +1,234 @@ +package com.iluwatar.reactor.framework; + +import java.io.IOException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.Iterator; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * This class acts as Synchronous Event De-multiplexer and Initiation Dispatcher of Reactor pattern. + * Multiple handles i.e. {@link AbstractNioChannel}s can be registered to the reactor and it blocks + * for events from all these handles. Whenever an event occurs on any of the registered handles, it + * synchronously de-multiplexes the event which can be any of read, write or accept, and dispatches + * the event to the appropriate {@link ChannelHandler} using the {@link Dispatcher}. + * + *

+ * Implementation: A NIO reactor runs in its own thread when it is started using {@link #start()} + * method. {@link NioReactor} uses {@link Selector} for realizing Synchronous Event De-multiplexing. + * + *

+ * NOTE: This is one of the ways to implement NIO reactor and it does not take care of all possible + * edge cases which are required in a real application. This implementation is meant to demonstrate + * the fundamental concepts that lie behind Reactor pattern. + */ +public class NioReactor { + + private final Selector selector; + private final Dispatcher dispatcher; + /** + * All the work of altering the SelectionKey operations and Selector operations are performed in + * the context of main event loop of reactor. So when any channel needs to change its readability + * or writability, a new command is added in the command queue and then the event loop picks up + * the command and executes it in next iteration. + */ + private final Queue pendingCommands = new ConcurrentLinkedQueue<>(); + private final ExecutorService reactorMain = Executors.newSingleThreadExecutor(); + + /** + * Creates a reactor which will use provided {@code dispatcher} to dispatch events. The + * application can provide various implementations of dispatcher which suits its needs. + * + * @param dispatcher a non-null dispatcher used to dispatch events on registered channels. + * @throws IOException if any I/O error occurs. + */ + public NioReactor(Dispatcher dispatcher) throws IOException { + this.dispatcher = dispatcher; + this.selector = Selector.open(); + } + + /** + * Starts the reactor event loop in a new thread. + * + * @throws IOException if any I/O error occurs. + */ + public void start() throws IOException { + reactorMain.execute(() -> { + try { + System.out.println("Reactor started, waiting for events..."); + eventLoop(); + } catch (IOException e) { + e.printStackTrace(); + } + }); + } + + /** + * Stops the reactor and related resources such as dispatcher. + * + * @throws InterruptedException if interrupted while stopping the reactor. + * @throws IOException if any I/O error occurs. + */ + public void stop() throws InterruptedException, IOException { + reactorMain.shutdownNow(); + selector.wakeup(); + reactorMain.awaitTermination(4, TimeUnit.SECONDS); + selector.close(); + } + + /** + * Registers a new channel (handle) with this reactor. Reactor will start waiting for events on + * this channel and notify of any events. While registering the channel the reactor uses + * {@link AbstractNioChannel#getInterestedOps()} to know about the interested operation of this + * channel. + * + * @param channel a new channel on which reactor will wait for events. The channel must be bound + * prior to being registered. + * @return this + * @throws IOException if any I/O error occurs. + */ + public NioReactor registerChannel(AbstractNioChannel channel) throws IOException { + SelectionKey key = channel.getJavaChannel().register(selector, channel.getInterestedOps()); + key.attach(channel); + channel.setReactor(this); + return this; + } + + private void eventLoop() throws IOException { + while (true) { + + // honor interrupt request + if (Thread.interrupted()) { + break; + } + + // honor any pending commands first + processPendingCommands(); + + /* + * Synchronous event de-multiplexing happens here, this is blocking call which returns when it + * is possible to initiate non-blocking operation on any of the registered channels. + */ + selector.select(); + + /* + * Represents the events that have occurred on registered handles. + */ + Set keys = selector.selectedKeys(); + + Iterator iterator = keys.iterator(); + + while (iterator.hasNext()) { + SelectionKey key = iterator.next(); + if (!key.isValid()) { + iterator.remove(); + continue; + } + processKey(key); + } + keys.clear(); + } + } + + private void processPendingCommands() { + Iterator iterator = pendingCommands.iterator(); + while (iterator.hasNext()) { + Runnable command = iterator.next(); + command.run(); + iterator.remove(); + } + } + + /* + * Initiation dispatcher logic, it checks the type of event and notifier application specific + * event handler to handle the event. + */ + private void processKey(SelectionKey key) throws IOException { + if (key.isAcceptable()) { + onChannelAcceptable(key); + } else if (key.isReadable()) { + onChannelReadable(key); + } else if (key.isWritable()) { + onChannelWritable(key); + } + } + + private void onChannelWritable(SelectionKey key) throws IOException { + AbstractNioChannel channel = (AbstractNioChannel) key.attachment(); + channel.flush(key); + } + + private void onChannelReadable(SelectionKey key) { + try { + // reads the incoming data in context of reactor main loop. Can this be improved? + Object readObject = ((AbstractNioChannel) key.attachment()).read(key); + + dispatchReadEvent(key, readObject); + } catch (IOException e) { + try { + key.channel().close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + + /* + * Uses the application provided dispatcher to dispatch events to application handler. + */ + private void dispatchReadEvent(SelectionKey key, Object readObject) { + dispatcher.onChannelReadEvent((AbstractNioChannel) key.attachment(), readObject, key); + } + + private void onChannelAcceptable(SelectionKey key) throws IOException { + ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); + SocketChannel socketChannel = serverSocketChannel.accept(); + socketChannel.configureBlocking(false); + SelectionKey readKey = socketChannel.register(selector, SelectionKey.OP_READ); + readKey.attach(key.attachment()); + } + + /** + * Queues the change of operations request of a channel, which will change the interested + * operations of the channel sometime in future. + *

+ * This is a non-blocking method and does not guarantee that the operations have changed when this + * method returns. + * + * @param key the key for which operations have to be changed. + * @param interestedOps the new interest operations. + */ + public void changeOps(SelectionKey key, int interestedOps) { + pendingCommands.add(new ChangeKeyOpsCommand(key, interestedOps)); + selector.wakeup(); + } + + /** + * A command that changes the interested operations of the key provided. + */ + class ChangeKeyOpsCommand implements Runnable { + private SelectionKey key; + private int interestedOps; + + public ChangeKeyOpsCommand(SelectionKey key, int interestedOps) { + this.key = key; + this.interestedOps = interestedOps; + } + + public void run() { + key.interestOps(interestedOps); + } + + @Override + public String toString() { + return "Change of ops to: " + interestedOps; + } + } +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java b/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java new file mode 100644 index 000000000..c5caaa7ff --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/NioServerSocketChannel.java @@ -0,0 +1,88 @@ +package com.iluwatar.reactor.framework; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; + +/** + * A wrapper over {@link NioServerSocketChannel} which can read and write data on a + * {@link SocketChannel}. + */ +public class NioServerSocketChannel extends AbstractNioChannel { + + private final int port; + + /** + * Creates a {@link ServerSocketChannel} which will bind at provided port and use + * handler to handle incoming events on this channel. + *

+ * Note the constructor does not bind the socket, {@link #bind()} method should be called for + * binding the socket. + * + * @param port the port on which channel will be bound to accept incoming connection requests. + * @param handler the handler that will handle incoming requests on this channel. + * @throws IOException if any I/O error occurs. + */ + public NioServerSocketChannel(int port, ChannelHandler handler) throws IOException { + super(handler, ServerSocketChannel.open()); + this.port = port; + } + + + @Override + public int getInterestedOps() { + // being a server socket channel it is interested in accepting connection from remote peers. + return SelectionKey.OP_ACCEPT; + } + + /** + * @return the underlying {@link ServerSocketChannel}. + */ + @Override + public ServerSocketChannel getJavaChannel() { + return (ServerSocketChannel) super.getJavaChannel(); + } + + /** + * Reads and returns {@link ByteBuffer} from the underlying {@link SocketChannel} represented by + * the key. Due to the fact that there is a dedicated channel for each client + * connection we don't need to store the sender. + */ + @Override + public ByteBuffer read(SelectionKey key) throws IOException { + SocketChannel socketChannel = (SocketChannel) key.channel(); + ByteBuffer buffer = ByteBuffer.allocate(1024); + int read = socketChannel.read(buffer); + buffer.flip(); + if (read == -1) { + throw new IOException("Socket closed"); + } + return buffer; + } + + /** + * Binds TCP socket on the provided port. + * + * @throws IOException if any I/O error occurs. + */ + @Override + public void bind() throws IOException { + ((ServerSocketChannel) getJavaChannel()).socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), port)); + ((ServerSocketChannel) getJavaChannel()).configureBlocking(false); + System.out.println("Bound TCP socket at port: " + port); + } + + /** + * Writes the pending {@link ByteBuffer} to the underlying channel sending data to the intended + * receiver of the packet. + */ + @Override + protected void doWrite(Object pendingWrite, SelectionKey key) throws IOException { + ByteBuffer pendingBuffer = (ByteBuffer) pendingWrite; + ((SocketChannel) key.channel()).write(pendingBuffer); + } +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/SameThreadDispatcher.java b/reactor/src/main/java/com/iluwatar/reactor/framework/SameThreadDispatcher.java new file mode 100644 index 000000000..ae995428e --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/SameThreadDispatcher.java @@ -0,0 +1,38 @@ +package com.iluwatar.reactor.framework; + +import java.nio.channels.SelectionKey; + +/** + * Dispatches the events in the context of caller thread. This implementation is a good fit for + * small applications where there are limited clients. Using this implementation limits the + * scalability because the I/O thread performs the application specific processing. + * + *

+ * For better performance use {@link ThreadPoolDispatcher}. + * + * @see ThreadPoolDispatcher + */ +public class SameThreadDispatcher implements Dispatcher { + + /** + * Dispatches the read event in the context of caller thread.
+ * Note this is a blocking call. It returns only after the associated handler has handled the read + * event. + */ + @Override + public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) { + /* + * Calls the associated handler to notify the read event where application specific code + * resides. + */ + channel.getHandler().handleChannelRead(channel, readObject, key); + } + + /** + * No resources to free. + */ + @Override + public void stop() { + // no-op + } +} diff --git a/reactor/src/main/java/com/iluwatar/reactor/framework/ThreadPoolDispatcher.java b/reactor/src/main/java/com/iluwatar/reactor/framework/ThreadPoolDispatcher.java new file mode 100644 index 000000000..4a240659e --- /dev/null +++ b/reactor/src/main/java/com/iluwatar/reactor/framework/ThreadPoolDispatcher.java @@ -0,0 +1,47 @@ +package com.iluwatar.reactor.framework; + +import java.nio.channels.SelectionKey; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +/** + * An implementation that uses a pool of worker threads to dispatch the events. This provides better + * scalability as the application specific processing is not performed in the context of I/O + * (reactor) thread. + */ +public class ThreadPoolDispatcher implements Dispatcher { + + private final ExecutorService executorService; + + /** + * Creates a pooled dispatcher with tunable pool size. + * + * @param poolSize number of pooled threads + */ + public ThreadPoolDispatcher(int poolSize) { + this.executorService = Executors.newFixedThreadPool(poolSize); + } + + /** + * Submits the work of dispatching the read event to worker pool, where it gets picked up by + * worker threads.
+ * Note that this is a non-blocking call and returns immediately. It is not guaranteed that the + * event has been handled by associated handler. + */ + @Override + public void onChannelReadEvent(AbstractNioChannel channel, Object readObject, SelectionKey key) { + executorService.execute(() -> channel.getHandler().handleChannelRead(channel, readObject, key)); + } + + /** + * Stops the pool of workers. + * + * @throws InterruptedException if interrupted while stopping pool of workers. + */ + @Override + public void stop() throws InterruptedException { + executorService.shutdown(); + executorService.awaitTermination(4, TimeUnit.SECONDS); + } +} diff --git a/reactor/src/test/java/com/iluwatar/reactor/app/AppTest.java b/reactor/src/test/java/com/iluwatar/reactor/app/AppTest.java new file mode 100644 index 000000000..9abb4e690 --- /dev/null +++ b/reactor/src/test/java/com/iluwatar/reactor/app/AppTest.java @@ -0,0 +1,68 @@ +package com.iluwatar.reactor.app; + +import java.io.IOException; + +import org.junit.Test; + +import com.iluwatar.reactor.framework.SameThreadDispatcher; +import com.iluwatar.reactor.framework.ThreadPoolDispatcher; + +/** + * + * This class tests the Distributed Logging service by starting a Reactor and then sending it + * concurrent logging requests using multiple clients. + */ +public class AppTest { + + /** + * Test the application using pooled thread dispatcher. + * + * @throws IOException if any I/O error occurs. + * @throws InterruptedException if interrupted while stopping the application. + */ + @Test + public void testAppUsingThreadPoolDispatcher() throws IOException, InterruptedException { + App app = new App(new ThreadPoolDispatcher(2)); + app.start(); + + AppClient client = new AppClient(); + client.start(); + + // allow clients to send requests. Artificial delay. + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + client.stop(); + + app.stop(); + } + + /** + * Test the application using same thread dispatcher. + * + * @throws IOException if any I/O error occurs. + * @throws InterruptedException if interrupted while stopping the application. + */ + @Test + public void testAppUsingSameThreadDispatcher() throws IOException, InterruptedException { + App app = new App(new SameThreadDispatcher()); + app.start(); + + AppClient client = new AppClient(); + client.start(); + + // allow clients to send requests. Artificial delay. + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + client.stop(); + + app.stop(); + } +} diff --git a/repository/pom.xml b/repository/pom.xml index db0a8af5f..70f2ff6b2 100644 --- a/repository/pom.xml +++ b/repository/pom.xml @@ -6,7 +6,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 repository diff --git a/resource-acquisition-is-initialization/pom.xml b/resource-acquisition-is-initialization/pom.xml index c8382ceb8..a16eae745 100644 --- a/resource-acquisition-is-initialization/pom.xml +++ b/resource-acquisition-is-initialization/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 resource-acquisition-is-initialization diff --git a/servant/pom.xml b/servant/pom.xml index b6497215f..1928f83c9 100644 --- a/servant/pom.xml +++ b/servant/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 servant diff --git a/servant/src/main/java/com/iluwatar/servant/App.java b/servant/src/main/java/com/iluwatar/servant/App.java index 6a0ba6ca4..832d3d52c 100644 --- a/servant/src/main/java/com/iluwatar/servant/App.java +++ b/servant/src/main/java/com/iluwatar/servant/App.java @@ -7,6 +7,8 @@ import java.util.ArrayList; * Servant offers some functionality to a group of classes without defining that functionality in each of them. * A Servant is a class whose instance provides methods that take care of a desired service, * while objects for which the servant does something, are taken as parameters. + *

+ * In this example {@link Servant} is serving {@link King} and {@link Queen}. * */ public class App { diff --git a/service-layer/index.md b/service-layer/index.md index f9e7ac1cb..ea3f3d0ba 100644 --- a/service-layer/index.md +++ b/service-layer/index.md @@ -24,3 +24,4 @@ its business logic. The Service Layer fulfills this role. **Credits:** * [Martin Fowler - Service Layer](http://martinfowler.com/eaaCatalog/serviceLayer.html) +* [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420) diff --git a/service-layer/pom.xml b/service-layer/pom.xml index 8e0ea8322..a42d07c5e 100644 --- a/service-layer/pom.xml +++ b/service-layer/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 service-layer diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java index 2d91b43d9..47eb5231e 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/app/App.java @@ -4,9 +4,9 @@ import java.util.List; import com.iluwatar.servicelayer.magic.MagicService; import com.iluwatar.servicelayer.magic.MagicServiceImpl; -import com.iluwatar.servicelayer.servicelayer.spell.Spell; -import com.iluwatar.servicelayer.servicelayer.spell.SpellDao; -import com.iluwatar.servicelayer.servicelayer.spell.SpellDaoImpl; +import com.iluwatar.servicelayer.spell.Spell; +import com.iluwatar.servicelayer.spell.SpellDao; +import com.iluwatar.servicelayer.spell.SpellDaoImpl; import com.iluwatar.servicelayer.spellbook.Spellbook; import com.iluwatar.servicelayer.spellbook.SpellbookDao; import com.iluwatar.servicelayer.spellbook.SpellbookDaoImpl; diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java b/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java index 70d586c08..61d0f5d5d 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/hibernate/HibernateUtil.java @@ -3,7 +3,7 @@ package com.iluwatar.servicelayer.hibernate; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; -import com.iluwatar.servicelayer.servicelayer.spell.Spell; +import com.iluwatar.servicelayer.spell.Spell; import com.iluwatar.servicelayer.spellbook.Spellbook; import com.iluwatar.servicelayer.wizard.Wizard; diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicService.java b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicService.java index a6046742b..38742c78d 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicService.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicService.java @@ -2,7 +2,7 @@ package com.iluwatar.servicelayer.magic; import java.util.List; -import com.iluwatar.servicelayer.servicelayer.spell.Spell; +import com.iluwatar.servicelayer.spell.Spell; import com.iluwatar.servicelayer.spellbook.Spellbook; import com.iluwatar.servicelayer.wizard.Wizard; diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java index e5599fc4e..37249894a 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/magic/MagicServiceImpl.java @@ -3,8 +3,8 @@ package com.iluwatar.servicelayer.magic; import java.util.ArrayList; import java.util.List; -import com.iluwatar.servicelayer.servicelayer.spell.Spell; -import com.iluwatar.servicelayer.servicelayer.spell.SpellDao; +import com.iluwatar.servicelayer.spell.Spell; +import com.iluwatar.servicelayer.spell.SpellDao; import com.iluwatar.servicelayer.spellbook.Spellbook; import com.iluwatar.servicelayer.spellbook.SpellbookDao; import com.iluwatar.servicelayer.wizard.Wizard; diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/Spell.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/Spell.java similarity index 95% rename from service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/Spell.java rename to service-layer/src/main/java/com/iluwatar/servicelayer/spell/Spell.java index 5dc7a6acc..ed166eccc 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/Spell.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/Spell.java @@ -1,4 +1,4 @@ -package com.iluwatar.servicelayer.servicelayer.spell; +package com.iluwatar.servicelayer.spell; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/SpellDao.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDao.java similarity index 75% rename from service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/SpellDao.java rename to service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDao.java index 079ef39a0..a59307e7f 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/SpellDao.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDao.java @@ -1,4 +1,4 @@ -package com.iluwatar.servicelayer.servicelayer.spell; +package com.iluwatar.servicelayer.spell; import com.iluwatar.servicelayer.common.Dao; diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/SpellDaoImpl.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java similarity index 94% rename from service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/SpellDaoImpl.java rename to service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java index d8655ac3a..d278defe2 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/servicelayer/spell/SpellDaoImpl.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spell/SpellDaoImpl.java @@ -1,4 +1,4 @@ -package com.iluwatar.servicelayer.servicelayer.spell; +package com.iluwatar.servicelayer.spell; import org.hibernate.Criteria; import org.hibernate.Session; diff --git a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java index 5bf42c7ed..c596c9926 100644 --- a/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java +++ b/service-layer/src/main/java/com/iluwatar/servicelayer/spellbook/Spellbook.java @@ -13,7 +13,7 @@ import javax.persistence.OneToMany; import javax.persistence.Table; import com.iluwatar.servicelayer.common.BaseEntity; -import com.iluwatar.servicelayer.servicelayer.spell.Spell; +import com.iluwatar.servicelayer.spell.Spell; import com.iluwatar.servicelayer.wizard.Wizard; /** diff --git a/service-locator/index.md b/service-locator/index.md index 8c2aa6417..03c432749 100644 --- a/service-locator/index.md +++ b/service-locator/index.md @@ -10,7 +10,7 @@ tags: Java **Intent:** Encapsulate the processes involved in obtaining a service with a strong abstraction layer. -![alt text](./etc/service-locator.png "Proxy") +![alt text](./etc/service-locator.png "Service Locator") **Applicability:** The service locator pattern is applicable whenever we want to locate/fetch various services using JNDI which, typically, is a redundant @@ -26,3 +26,7 @@ improves the performance of application to great extent. * when network hits are expensive and time consuming * lookups of services are done quite frequently * large number of services are being used + +**Credits:** + +* [J2EE Design Patterns](http://www.amazon.com/J2EE-Design-Patterns-William-Crawford/dp/0596004273/ref=sr_1_2) diff --git a/service-locator/pom.xml b/service-locator/pom.xml index a596e4b0c..f210c74b6 100644 --- a/service-locator/pom.xml +++ b/service-locator/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 service-locator diff --git a/service-locator/src/main/java/com/iluwatar/servicelocator/App.java b/service-locator/src/main/java/com/iluwatar/servicelocator/App.java index f86e1cc32..5b6615495 100644 --- a/service-locator/src/main/java/com/iluwatar/servicelocator/App.java +++ b/service-locator/src/main/java/com/iluwatar/servicelocator/App.java @@ -1,9 +1,15 @@ package com.iluwatar.servicelocator; /** - * Service locator pattern, used to lookup JNDI-services + * + * The Service Locator pattern is a design pattern used in software development + * to encapsulate the processes involved in obtaining a service with a strong + * abstraction layer. This pattern uses a central registry known as the "service + * locator", which on request returns the information necessary to perform a certain task. + *

+ * In this example we use the Service locator pattern to lookup JNDI-services * and cache them for subsequent requests. - * + *

* @author saifasif * */ diff --git a/singleton/index.md b/singleton/index.md index 7a280bdfa..18c137448 100644 --- a/singleton/index.md +++ b/singleton/index.md @@ -4,7 +4,10 @@ title: Singleton folder: singleton permalink: /patterns/singleton/ categories: Creational -tags: Java +tags: + - Java + - Gang Of Four + - Difficulty-Beginner --- **Intent:** Ensure a class only has one instance, and provide a global point of @@ -26,3 +29,7 @@ access to it. **Real world examples:** * [java.lang.Runtime#getRuntime()](http://docs.oracle.com/javase/8/docs/api/java/lang/Runtime.html#getRuntime%28%29) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/singleton/pom.xml b/singleton/pom.xml index cdd9b613a..ab118a1c3 100644 --- a/singleton/pom.xml +++ b/singleton/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 singleton diff --git a/singleton/src/main/java/com/iluwatar/singleton/App.java b/singleton/src/main/java/com/iluwatar/singleton/App.java index 67cb6fd00..7566c9c4d 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/App.java +++ b/singleton/src/main/java/com/iluwatar/singleton/App.java @@ -1,55 +1,77 @@ package com.iluwatar.singleton; /** - * - * Singleton pattern ensures that the class ({@link IvoryTower}) can have only one - * existing instance per Java classloader instance and provides global access to it. - *

- * http://stackoverflow.com/questions/70689/what-is-an-efficient-way-to-implement-a-singleton-pattern-in-java - *

- * The risk of this pattern is that bugs resulting from setting a singleton up in a distributed environment can - * be tricky to debug, since it will work fine if you debug with a single classloader. Additionally, these - * problems can crop up a while after the implementation of a singleton, since they may start out synchronous and - * only become async with time, so you it may not be clear why you are seeing certain changes in behaviour. - *

- * http://stackoverflow.com/questions/17721263/singleton-across-jvm-or-application-instance-or-tomcat-instance + * Singleton pattern ensures that the class can have only one existing instance per Java classloader instance + * and provides global access to it. + *

+ * One of the risks of this pattern is that bugs resulting from setting a singleton up in + * a distributed environment can be tricky to debug, since it will work fine if you + * debug with a single classloader. Additionally, these problems can crop up a while + * after the implementation of a singleton, since they may start out synchronous and + * only become async with time, so you it may not be clear why you are seeing certain + * changes in behaviour. + *

+ * There are many ways to implement the Singleton. The first one is the eagerly initialized instance in + * {@link IvoryTower}. Eager initialization implies that the implementation is thread safe. If you can + * afford giving up control of the instantiation moment, then this implementation will suit you fine. + *

+ * The other option to implement eagerly initialized Singleton is enum based Singleton. The example is + * found in {@link EnumIvoryTower}. At first glance the code looks short and simple. However, you should + * be aware of the downsides including committing to implementation strategy, extending the enum class, + * serializability and restrictions to coding. These are extensively discussed in Stack Overflow: + * http://programmers.stackexchange.com/questions/179386/what-are-the-downsides-of-implementing-a-singleton-with-javas-enum + *

+ * {@link ThreadSafeLazyLoadedIvoryTower} is a Singleton implementation that is initialized on demand. + * The downside is that it is very slow to access since the whole access method is synchronized. + *

+ * Another Singleton implementation that is initialized on demand is found in {@link ThreadSafeDoubleCheckLocking}. It + * is somewhat faster than {@link ThreadSafeLazyLoadedIvoryTower} since it doesn't synchronize the whole access method + * but only the method internals on specific conditions. + *

+ * Yet another way to implement thread safe lazily initialized Singleton can be found in {@link InitializingOnDemandHolderIdiom}. + * However, this implementation requires at least Java 8 API level to work. */ public class App { - /** - * Program entry point - * @param args command line args - */ - public static void main(String[] args) { + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { - // eagerly initialized singleton - IvoryTower ivoryTower1 = IvoryTower.getInstance(); - IvoryTower ivoryTower2 = IvoryTower.getInstance(); - System.out.println("ivoryTower1=" + ivoryTower1); - System.out.println("ivoryTower2=" + ivoryTower2); + // eagerly initialized singleton + IvoryTower ivoryTower1 = IvoryTower.getInstance(); + IvoryTower ivoryTower2 = IvoryTower.getInstance(); + System.out.println("ivoryTower1=" + ivoryTower1); + System.out.println("ivoryTower2=" + ivoryTower2); - // lazily initialized singleton - ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower1 = ThreadSafeLazyLoadedIvoryTower - .getInstance(); - ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower2 = ThreadSafeLazyLoadedIvoryTower - .getInstance(); - System.out.println("threadSafeIvoryTower1=" + threadSafeIvoryTower1); - System.out.println("threadSafeIvoryTower2=" + threadSafeIvoryTower2); + // lazily initialized singleton + ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower1 = ThreadSafeLazyLoadedIvoryTower + .getInstance(); + ThreadSafeLazyLoadedIvoryTower threadSafeIvoryTower2 = ThreadSafeLazyLoadedIvoryTower + .getInstance(); + System.out.println("threadSafeIvoryTower1=" + threadSafeIvoryTower1); + System.out.println("threadSafeIvoryTower2=" + threadSafeIvoryTower2); - // enum singleton - EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE; - EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE; - System.out.println("enumIvoryTower1=" + enumIvoryTower1); - System.out.println("enumIvoryTower2=" + enumIvoryTower2); - - InitializingOnDemandHolderIdiom demandHolderIdiom = InitializingOnDemandHolderIdiom.getInstance(); - System.out.println(demandHolderIdiom); - InitializingOnDemandHolderIdiom demandHolderIdiom2 = InitializingOnDemandHolderIdiom.getInstance(); - System.out.println(demandHolderIdiom2); - - ThreadSafeDoubleCheckLocking dcl1 = ThreadSafeDoubleCheckLocking.getInstance(); - System.out.println(dcl1); - ThreadSafeDoubleCheckLocking dcl2 = ThreadSafeDoubleCheckLocking.getInstance(); - System.out.println(dcl2); - } + // enum singleton + EnumIvoryTower enumIvoryTower1 = EnumIvoryTower.INSTANCE; + EnumIvoryTower enumIvoryTower2 = EnumIvoryTower.INSTANCE; + System.out.println("enumIvoryTower1=" + enumIvoryTower1); + System.out.println("enumIvoryTower2=" + enumIvoryTower2); + + // double checked locking + ThreadSafeDoubleCheckLocking dcl1 = ThreadSafeDoubleCheckLocking.getInstance(); + System.out.println(dcl1); + ThreadSafeDoubleCheckLocking dcl2 = ThreadSafeDoubleCheckLocking.getInstance(); + System.out.println(dcl2); + + // initialize on demand holder idiom + InitializingOnDemandHolderIdiom demandHolderIdiom = + InitializingOnDemandHolderIdiom.getInstance(); + System.out.println(demandHolderIdiom); + InitializingOnDemandHolderIdiom demandHolderIdiom2 = + InitializingOnDemandHolderIdiom.getInstance(); + System.out.println(demandHolderIdiom2); + } } diff --git a/singleton/src/main/java/com/iluwatar/singleton/EnumIvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/EnumIvoryTower.java index 8f9895924..f39babe45 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/EnumIvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/EnumIvoryTower.java @@ -1,17 +1,15 @@ package com.iluwatar.singleton; /** - * - * Enum Singleton class. + * Enum based singleton implementation. * Effective Java 2nd Edition (Joshua Bloch) p. 18 - * */ public enum EnumIvoryTower { - - INSTANCE; - @Override - public String toString() { - return getDeclaringClass().getCanonicalName() + "@" + hashCode(); - } + INSTANCE; + + @Override + public String toString() { + return getDeclaringClass().getCanonicalName() + "@" + hashCode(); + } } diff --git a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java index 4fd4c8163..88738b8ca 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java +++ b/singleton/src/main/java/com/iluwatar/singleton/InitializingOnDemandHolderIdiom.java @@ -3,34 +3,34 @@ package com.iluwatar.singleton; import java.io.Serializable; /** - * The Initialize-on-demand-holder idiom is a secure way of + * The Initialize-on-demand-holder idiom is a secure way of * creating lazy initialized singleton object in Java. * refer to "The CERT Oracle Secure Coding Standard for Java" * By Dhruv Mohindra, Robert C. Seacord p.378 - *

+ *

* Singleton objects usually are heavy to create and sometimes need to serialize them. * This class also shows how to preserve singleton in serialized version of singleton. - * - * @author mortezaadi@gmail.com * + * @author mortezaadi@gmail.com */ -public class InitializingOnDemandHolderIdiom implements Serializable{ +public class InitializingOnDemandHolderIdiom implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private static class HelperHolder { - public static final InitializingOnDemandHolderIdiom INSTANCE = new InitializingOnDemandHolderIdiom(); - } + private InitializingOnDemandHolderIdiom() { + } - public static InitializingOnDemandHolderIdiom getInstance() { - return HelperHolder.INSTANCE; - } + public static InitializingOnDemandHolderIdiom getInstance() { + return HelperHolder.INSTANCE; + } - private InitializingOnDemandHolderIdiom() { - } + protected Object readResolve() { + return getInstance(); + } - protected Object readResolve() { - return getInstance(); - } + private static class HelperHolder { + public static final InitializingOnDemandHolderIdiom INSTANCE = + new InitializingOnDemandHolderIdiom(); + } } diff --git a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java index 5d418aa54..7470c3f29 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/IvoryTower.java @@ -1,20 +1,30 @@ package com.iluwatar.singleton; /** - * * Singleton class. * Eagerly initialized static instance guarantees thread * safety. - * */ -public class IvoryTower { +public final class IvoryTower { - private static IvoryTower instance = new IvoryTower(); + /** + * Static to class instance of the class. + */ + private static final IvoryTower instance = new IvoryTower(); - private IvoryTower() { - } + /** + * Private constructor so nobody can instantiate the class. + */ + private IvoryTower() { + } - public static IvoryTower getInstance() { - return instance; - } + /** + * To be called by user to + * obtain instance of the class. + * + * @return instance of the singleton. + */ + public static IvoryTower getInstance() { + return instance; + } } diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java index d15509236..26b57d4cf 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java +++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeDoubleCheckLocking.java @@ -2,40 +2,44 @@ package com.iluwatar.singleton; /** * Double check locking - *

+ *

* http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html - *

+ *

* Broken under Java 1.4. - * - * @author mortezaadi@gmail.com * + * @author mortezaadi@gmail.com */ public class ThreadSafeDoubleCheckLocking { - - private static volatile ThreadSafeDoubleCheckLocking INSTANCE; - /** - * private constructor to prevent client from instantiating. - * - */ - private ThreadSafeDoubleCheckLocking() { - //to prevent instantiating by Reflection call - if(INSTANCE != null) - throw new IllegalStateException("Already initialized."); - } - - public static ThreadSafeDoubleCheckLocking getInstance() { - //local variable increases performance by 25 percent - //Joshua Bloch "Effective Java, Second Edition", p. 283-284 - ThreadSafeDoubleCheckLocking result = INSTANCE; - if (result == null) { - synchronized (ThreadSafeDoubleCheckLocking.class) { - result = INSTANCE; - if (result == null) { - INSTANCE = result = new ThreadSafeDoubleCheckLocking(); - } - } - } - return result; - } + private static volatile ThreadSafeDoubleCheckLocking INSTANCE; + + /** + * private constructor to prevent client from instantiating. + */ + private ThreadSafeDoubleCheckLocking() { + //to prevent instantiating by Reflection call + if (INSTANCE != null) { + throw new IllegalStateException("Already initialized."); + } + } + + /** + * Public accessor. + * + * @return an instance of the class. + */ + public static ThreadSafeDoubleCheckLocking getInstance() { + //local variable increases performance by 25 percent + //Joshua Bloch "Effective Java, Second Edition", p. 283-284 + ThreadSafeDoubleCheckLocking result = INSTANCE; + if (result == null) { + synchronized (ThreadSafeDoubleCheckLocking.class) { + result = INSTANCE; + if (result == null) { + INSTANCE = result = new ThreadSafeDoubleCheckLocking(); + } + } + } + return result; + } } diff --git a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java index f7184cfb0..f9b62e798 100644 --- a/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java +++ b/singleton/src/main/java/com/iluwatar/singleton/ThreadSafeLazyLoadedIvoryTower.java @@ -1,28 +1,27 @@ package com.iluwatar.singleton; /** - * * Thread-safe Singleton class. * The instance is lazily initialized and thus needs synchronization * mechanism. - * */ public class ThreadSafeLazyLoadedIvoryTower { - private static ThreadSafeLazyLoadedIvoryTower instance = null; - - private ThreadSafeLazyLoadedIvoryTower() { - } + private static ThreadSafeLazyLoadedIvoryTower instance = null; - public synchronized static ThreadSafeLazyLoadedIvoryTower getInstance() { - /* - * The instance gets created only when it is called for first time. - * Lazy-loading - */ - if (instance == null) { - instance = new ThreadSafeLazyLoadedIvoryTower(); - } + private ThreadSafeLazyLoadedIvoryTower() { + } - return instance; - } + /** + * The instance gets created only when it is called for first time. + * Lazy-loading + */ + public synchronized static ThreadSafeLazyLoadedIvoryTower getInstance() { + + if (instance == null) { + instance = new ThreadSafeLazyLoadedIvoryTower(); + } + + return instance; + } } diff --git a/specification/pom.xml b/specification/pom.xml index b4d6efe90..3c58aa29f 100644 --- a/specification/pom.xml +++ b/specification/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 specification diff --git a/state/index.md b/state/index.md index 1b1e4717f..b743cb8be 100644 --- a/state/index.md +++ b/state/index.md @@ -4,7 +4,10 @@ title: State folder: state permalink: /patterns/state/ categories: Behavioral -tags: Java +tags: + - Java + - Difficulty-Intermediate + - Gang Of Four --- **Intent:** Allow an object to alter its behavior when its internal state @@ -16,3 +19,7 @@ changes. The object will appear to change its class. * an object's behavior depends on its state, and it must change its behavior at run-time depending on that state * operations have large, multipart conditional statements that depend on the object's state. This state is usually represented by one or more enumerated constants. Often, several operations will contain this same conditional structure. The State pattern puts each branch of the conditional in a separate class. This lets you treat the object's state as an object in its own right that can vary independently from other objects. + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/state/pom.xml b/state/pom.xml index 0119146b3..2d87a796a 100644 --- a/state/pom.xml +++ b/state/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 state diff --git a/state/src/main/java/com/iluwatar/state/App.java b/state/src/main/java/com/iluwatar/state/App.java index 5b39d02f7..95d411076 100644 --- a/state/src/main/java/com/iluwatar/state/App.java +++ b/state/src/main/java/com/iluwatar/state/App.java @@ -2,10 +2,14 @@ package com.iluwatar.state; /** * - * In State pattern the container object ({@link Mammoth}) has an internal state object ({@link State}) that + * In State pattern the container object has an internal state object that * defines the current behavior. The state object can be changed to alter the * behavior. *

+ * This can be a cleaner way for an object to change its behavior at runtime + * without resorting to large monolithic conditional statements and thus improves + * maintainability. + *

* In this example the {@link Mammoth} changes its behavior as time passes by. * */ diff --git a/step-builder/pom.xml b/step-builder/pom.xml index f9c98474b..7c7e8ac69 100644 --- a/step-builder/pom.xml +++ b/step-builder/pom.xml @@ -6,7 +6,7 @@ java-design-patterns com.iluwatar - 1.6.0 + 1.7.0 step-builder diff --git a/strategy/index.md b/strategy/index.md index 1d3250517..120dd64d4 100644 --- a/strategy/index.md +++ b/strategy/index.md @@ -4,7 +4,10 @@ title: Strategy folder: strategy permalink: /patterns/strategy/ categories: Behavioral -tags: Java +tags: + - Java + - Difficulty-Beginner + - Gang Of Four --- **Intent:** Define a family of algorithms, encapsulate each one, and make them @@ -19,3 +22,7 @@ that use it. * you need different variants of an algorithm. for example, you might define algorithms reflecting different space/time trade-offs. Strategies can be used when these variants are implemented as a class hierarchy of algorithms * an algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures * a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/strategy/pom.xml b/strategy/pom.xml index 9532a8079..0b71652ba 100644 --- a/strategy/pom.xml +++ b/strategy/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 strategy diff --git a/strategy/src/main/java/com/iluwatar/strategy/App.java b/strategy/src/main/java/com/iluwatar/strategy/App.java index 992514801..b88eae242 100644 --- a/strategy/src/main/java/com/iluwatar/strategy/App.java +++ b/strategy/src/main/java/com/iluwatar/strategy/App.java @@ -2,7 +2,10 @@ package com.iluwatar.strategy; /** * - * Strategy ({@link DragonSlayingStrategy}) encapsulates an algorithm. The containing + * The Strategy pattern (also known as the policy pattern) is a software design pattern that + * enables an algorithm's behavior to be selected at runtime. + *

+ * In this example ({@link DragonSlayingStrategy}) encapsulates an algorithm. The containing * object ({@link DragonSlayer}) can alter its behavior by changing its strategy. * */ diff --git a/template-method/index.md b/template-method/index.md index f647d2cd5..8b8b7878e 100644 --- a/template-method/index.md +++ b/template-method/index.md @@ -4,7 +4,10 @@ title: Template method folder: template-method permalink: /patterns/template-method/ categories: Behavioral -tags: Java +tags: + - Java + - Difficulty-Beginner + - Gang Of Four --- **Intent:** Define the skeleton of an algorithm in an operation, deferring some @@ -18,3 +21,7 @@ an algorithm without changing the algorithm's structure. * to implement the invariant parts of an algorithm once and leave it up to subclasses to implement the behavior that can vary * when common behavior among subclasses should be factored and localized in a common class to avoid code duplication. This is good example of "refactoring to generalize" as described by Opdyke and Johnson. You first identify the differences in the existing code and then separate the differences into new operations. Finally, you replace the differing code with a template method that calls one of these new operations * to control subclasses extensions. You can define a template method that calls "hook" operations at specific points, thereby permitting extensions only at those points + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/template-method/pom.xml b/template-method/pom.xml index 53a7dc56e..4aa776591 100644 --- a/template-method/pom.xml +++ b/template-method/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 template-method diff --git a/thread-pool/pom.xml b/thread-pool/pom.xml index 42e54de7e..e335b06e5 100644 --- a/thread-pool/pom.xml +++ b/thread-pool/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 thread-pool diff --git a/tolerant-reader/pom.xml b/tolerant-reader/pom.xml index 7e852d4ee..086251772 100644 --- a/tolerant-reader/pom.xml +++ b/tolerant-reader/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 tolerant-reader diff --git a/update-ghpages.sh b/update-ghpages.sh new file mode 100644 index 000000000..82486d5a4 --- /dev/null +++ b/update-ghpages.sh @@ -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 diff --git a/visitor/index.md b/visitor/index.md index eeb11a5e5..5f32edbbd 100644 --- a/visitor/index.md +++ b/visitor/index.md @@ -4,7 +4,10 @@ title: Visitor folder: visitor permalink: /patterns/visitor/ categories: Behavioral -tags: Java +tags: + - Java + - Difficulty-Expert + - Gang Of Four --- **Intent:** Represent an operation to be performed on the elements of an object @@ -22,3 +25,7 @@ of the elements on which it operates. **Real world examples:** * [Apache Wicket](https://github.com/apache/wicket) component tree, see [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java) + +**Credits** + +* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612) diff --git a/visitor/pom.xml b/visitor/pom.xml index 8adda4855..ca5f72be8 100644 --- a/visitor/pom.xml +++ b/visitor/pom.xml @@ -5,7 +5,7 @@ com.iluwatar java-design-patterns - 1.6.0 + 1.7.0 visitor