Merge branch 'master' into master
This commit is contained in:
commit
5cbf651a3e
@ -17,7 +17,7 @@ install:
|
|||||||
- mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -e
|
- mvn install -DskipTests=true -Dmaven.javadoc.skip=true -B -V -e
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarqube.com -Dsonar.login=$SONAR_TOKEN
|
- mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar -Dsonar.host.url=https://sonarcloud.io -Dsonar.login=$SONAR_TOKEN
|
||||||
- bash update-ghpages.sh
|
- bash update-ghpages.sh
|
||||||
|
|
||||||
# use latest java version available instead of travis default
|
# use latest java version available instead of travis default
|
||||||
|
15
PULL_REQUEST_TEMPLATE.md
Normal file
15
PULL_REQUEST_TEMPLATE.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
Pull request title
|
||||||
|
|
||||||
|
- Clearly and concisely describes what it does
|
||||||
|
- Refer to the issue that it solves, if available
|
||||||
|
|
||||||
|
|
||||||
|
Pull request description
|
||||||
|
|
||||||
|
- Describes the main changes that come with the pull request
|
||||||
|
- Any relevant additional information is provided
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> For detailed contributing instructions see https://github.com/iluwatar/java-design-patterns/wiki/01.-How-to-contribute
|
@ -7,7 +7,8 @@
|
|||||||
[](https://travis-ci.org/iluwatar/java-design-patterns)
|
[](https://travis-ci.org/iluwatar/java-design-patterns)
|
||||||
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)
|
||||||
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
[](https://sonarqube.com/dashboard/index/com.iluwatar%3Ajava-design-patterns)
|
[](https://sonarcloud.io/dashboard/index/com.iluwatar%3Ajava-design-patterns)
|
||||||
|
[](https://bestpractices.coreinfrastructure.org/projects/1503)
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
|
@ -1,67 +0,0 @@
|
|||||||
#
|
|
||||||
# The MIT License
|
|
||||||
# Copyright (c) 2014-2016 Ilkka Seppälä
|
|
||||||
#
|
|
||||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
# of this software and associated documentation files (the "Software"), to deal
|
|
||||||
# in the Software without restriction, including without limitation the rights
|
|
||||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
# copies of the Software, and to permit persons to whom the Software is
|
|
||||||
# furnished to do so, subject to the following conditions:
|
|
||||||
#
|
|
||||||
# The above copyright notice and this permission notice shall be included in
|
|
||||||
# all copies or substantial portions of the Software.
|
|
||||||
#
|
|
||||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
# THE SOFTWARE.
|
|
||||||
#
|
|
||||||
|
|
||||||
import requests, glob, re, os
|
|
||||||
|
|
||||||
# taken from here: http://stackoverflow.com/a/13641746
|
|
||||||
def replace(file, pattern, subst):
|
|
||||||
# Read contents from file as a single string
|
|
||||||
file_handle = open(file, 'r')
|
|
||||||
file_string = file_handle.read()
|
|
||||||
file_handle.close()
|
|
||||||
|
|
||||||
# Use RE package to allow for replacement (also allowing for (multiline) REGEX)
|
|
||||||
file_string = (re.sub(pattern, subst, file_string))
|
|
||||||
|
|
||||||
# Write contents to file.
|
|
||||||
# Using mode 'w' truncates the file.
|
|
||||||
file_handle = open(file, 'w')
|
|
||||||
file_handle.write(file_string)
|
|
||||||
file_handle.close()
|
|
||||||
|
|
||||||
# list of all puml files
|
|
||||||
fileList = glob.glob('*/etc/*.puml')
|
|
||||||
for puml in fileList:
|
|
||||||
pathSplit = puml.split("/")
|
|
||||||
# parent folder
|
|
||||||
parent = pathSplit[0]
|
|
||||||
# individual artifact/project name
|
|
||||||
artifact = pathSplit[2].replace(".urm.puml", "")
|
|
||||||
print "parent: " + parent + "; artifact: " + artifact
|
|
||||||
|
|
||||||
# do a POST to the official plantuml hosting site with a little trick "!includeurl" and raw github content
|
|
||||||
data = {
|
|
||||||
'text': "!includeurl https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/" + puml
|
|
||||||
}
|
|
||||||
r = requests.post('http://plantuml.com/plantuml/uml', data=data)
|
|
||||||
pumlId = r.url.replace("http://plantuml.com/plantuml/uml/", "")
|
|
||||||
|
|
||||||
# the only thing needed to get a png/svg/ascii from the server back
|
|
||||||
print "Puml Server ID: " + pumlId
|
|
||||||
|
|
||||||
# add the id so jekyll/liquid can use it
|
|
||||||
if (parent == artifact):
|
|
||||||
replace("./" + parent + "/README.md", "categories:", "pumlid: {}\\ncategories:".format(pumlId))
|
|
||||||
else:
|
|
||||||
print "I dont want to program this, just add the following lines to the README.md file that corresponds to this puml file '" + puml + "'\npumlid: {}".format(pumlId)
|
|
||||||
|
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Abstract Document
|
title: Abstract Document
|
||||||
folder: abstract-document
|
folder: abstract-document
|
||||||
permalink: /patterns/abstract-document/
|
permalink: /patterns/abstract-document/
|
||||||
pumlid: PSjB3eCm34NHhPG599vtDyQn85L-ifzX-p3lxEf8Twj3MXGDQvyJMFubChxpKN767gucSq07iinEjSNDOACVNvoAUZr6MWoe3QVE_WRnxZ0Mf38b-hkIGlurX_MyehS7
|
|
||||||
categories: Structural
|
categories: Structural
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
@ -13,8 +12,6 @@ tags:
|
|||||||
## Intent
|
## Intent
|
||||||
Achieve flexibility of untyped languages and keep the type-safety
|
Achieve flexibility of untyped languages and keep the type-safety
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
@ -1,58 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<class-diagram version="1.1.9" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
|
||||||
realizations="true" associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
|
||||||
<interface id="1" language="java" name="com.iluwatar.abstractdocument.Document" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/Document.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="249" y="405"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<class id="2" language="java" name="com.iluwatar.abstractdocument.AbstractDocument" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/AbstractDocument.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="250" y="237"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="3" language="java" name="com.iluwatar.abstractdocument.domain.Car" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/domain/Car.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="108" y="75"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<class id="4" language="java" name="com.iluwatar.abstractdocument.domain.Part" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/domain/Part.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="-1" width="-1" x="400" y="76"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</class>
|
|
||||||
<generalization id="5">
|
|
||||||
<end type="SOURCE" refId="4"/>
|
|
||||||
<end type="TARGET" refId="2"/>
|
|
||||||
</generalization>
|
|
||||||
<realization id="6">
|
|
||||||
<end type="SOURCE" refId="2"/>
|
|
||||||
<end type="TARGET" refId="1"/>
|
|
||||||
</realization>
|
|
||||||
<generalization id="7">
|
|
||||||
<end type="SOURCE" refId="3"/>
|
|
||||||
<end type="TARGET" refId="2"/>
|
|
||||||
</generalization>
|
|
||||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</classifier-display>
|
|
||||||
<association-display labels="true" multiplicity="true"/>
|
|
||||||
</class-diagram>
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 94 KiB |
@ -1,91 +1,137 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<class-diagram version="1.1.9" icons="true" automaticImage="PNG" always-add-relationships="false" generalizations="true"
|
<class-diagram version="1.2.2" icons="true" always-add-relationships="false" generalizations="true" realizations="true"
|
||||||
realizations="true" associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
associations="true" dependencies="false" nesting-relationships="true" router="FAN">
|
||||||
<interface id="1" language="java" name="com.iluwatar.abstractdocument.Document" project="design-patterns"
|
<class id="1" language="java" name="com.iluwatar.abstractdocument.AbstractDocument" project="abstract-document"
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/Document.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/AbstractDocument.java" binary="false"
|
||||||
<position height="-1" width="-1" x="341" y="376"/>
|
corner="BOTTOM_RIGHT">
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<position height="-1" width="-1" x="659" y="286"/>
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<interface id="2" language="java" name="com.iluwatar.abstractdocument.domain.HasModel" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/domain/HasModel.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="81" width="173" x="41" y="194"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<interface id="3" language="java" name="com.iluwatar.abstractdocument.domain.HasPrice" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/domain/HasPrice.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="81" width="175" x="254" y="194"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<interface id="4" language="java" name="com.iluwatar.abstractdocument.domain.HasParts" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/domain/HasParts.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="81" width="173" x="469" y="194"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
|
||||||
sort-features="false" accessors="true" visibility="true">
|
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
|
||||||
</display>
|
|
||||||
</interface>
|
|
||||||
<class id="5" language="java" name="com.iluwatar.abstractdocument.domain.Car" project="design-patterns"
|
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/domain/Car.java" binary="false" corner="BOTTOM_RIGHT">
|
|
||||||
<position height="99" width="173" x="254" y="37"/>
|
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<class id="6" language="java" name="com.iluwatar.abstractdocument.domain.Part" project="design-patterns"
|
<interface id="2" language="java" name="com.iluwatar.abstractdocument.Document" project="abstract-document"
|
||||||
file="/design-patterns/src/com/iluwatar/abstractdocument/domain/Part.java" binary="false" corner="BOTTOM_RIGHT">
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/Document.java" binary="false"
|
||||||
<position height="99" width="173" x="41" y="37"/>
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="562" y="27"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</interface>
|
||||||
|
<class id="3" language="java" name="com.iluwatar.abstractdocument.domain.Car" project="abstract-document"
|
||||||
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Car.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="348" y="737"/>
|
||||||
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
</display>
|
</display>
|
||||||
</class>
|
</class>
|
||||||
<realization id="7">
|
<class id="4" language="java" name="com.iluwatar.abstractdocument.domain.Part" project="abstract-document"
|
||||||
<end type="SOURCE" refId="5"/>
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/Part.java" binary="false"
|
||||||
<end type="TARGET" refId="2"/>
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="760" y="746"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</class>
|
||||||
|
<interface id="5" language="java" name="com.iluwatar.abstractdocument.domain.HasModel" project="abstract-document"
|
||||||
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasModel.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="355" y="297"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</interface>
|
||||||
|
<interface id="6" language="java" name="com.iluwatar.abstractdocument.domain.HasParts" project="abstract-document"
|
||||||
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasParts.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="109" y="297"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</interface>
|
||||||
|
<interface id="7" language="java" name="com.iluwatar.abstractdocument.domain.HasPrice" project="abstract-document"
|
||||||
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasPrice.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="1008" y="283"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</interface>
|
||||||
|
<interface id="8" language="java" name="com.iluwatar.abstractdocument.domain.HasType" project="abstract-document"
|
||||||
|
file="/abstract-document/src/main/java/com/iluwatar/abstractdocument/domain/HasType.java" binary="false"
|
||||||
|
corner="BOTTOM_RIGHT">
|
||||||
|
<position height="-1" width="-1" x="1257" y="277"/>
|
||||||
|
<display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
<attributes public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
<operations public="true" package="true" protected="true" private="true" static="true"/>
|
||||||
|
</display>
|
||||||
|
</interface>
|
||||||
|
<realization id="9">
|
||||||
|
<end type="SOURCE" refId="4"/>
|
||||||
|
<end type="TARGET" refId="8"/>
|
||||||
</realization>
|
</realization>
|
||||||
<realization id="8">
|
<realization id="10">
|
||||||
|
<end type="SOURCE" refId="3"/>
|
||||||
|
<end type="TARGET" refId="7"/>
|
||||||
|
</realization>
|
||||||
|
<generalization id="11">
|
||||||
<end type="SOURCE" refId="6"/>
|
<end type="SOURCE" refId="6"/>
|
||||||
<end type="TARGET" refId="2"/>
|
<end type="TARGET" refId="2"/>
|
||||||
</realization>
|
|
||||||
<generalization id="9">
|
|
||||||
<end type="SOURCE" refId="2"/>
|
|
||||||
<end type="TARGET" refId="1"/>
|
|
||||||
</generalization>
|
</generalization>
|
||||||
<realization id="10">
|
<realization id="12">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="4"/>
|
||||||
<end type="TARGET" refId="3"/>
|
<end type="TARGET" refId="5"/>
|
||||||
</realization>
|
</realization>
|
||||||
<realization id="11">
|
<realization id="13">
|
||||||
<end type="SOURCE" refId="5"/>
|
<end type="SOURCE" refId="4"/>
|
||||||
<end type="TARGET" refId="4"/>
|
<end type="TARGET" refId="7"/>
|
||||||
</realization>
|
</realization>
|
||||||
<generalization id="12">
|
<generalization id="14">
|
||||||
<end type="SOURCE" refId="3"/>
|
<end type="SOURCE" refId="3"/>
|
||||||
<end type="TARGET" refId="1"/>
|
<end type="TARGET" refId="1"/>
|
||||||
</generalization>
|
</generalization>
|
||||||
<generalization id="13">
|
<realization id="15">
|
||||||
|
<end type="SOURCE" refId="3"/>
|
||||||
|
<end type="TARGET" refId="6"/>
|
||||||
|
</realization>
|
||||||
|
<generalization id="16">
|
||||||
|
<end type="SOURCE" refId="8"/>
|
||||||
|
<end type="TARGET" refId="2"/>
|
||||||
|
</generalization>
|
||||||
|
<generalization id="17">
|
||||||
|
<end type="SOURCE" refId="7"/>
|
||||||
|
<end type="TARGET" refId="2"/>
|
||||||
|
</generalization>
|
||||||
|
<realization id="18">
|
||||||
|
<end type="SOURCE" refId="3"/>
|
||||||
|
<end type="TARGET" refId="5"/>
|
||||||
|
</realization>
|
||||||
|
<generalization id="19">
|
||||||
<end type="SOURCE" refId="4"/>
|
<end type="SOURCE" refId="4"/>
|
||||||
<end type="TARGET" refId="1"/>
|
<end type="TARGET" refId="1"/>
|
||||||
</generalization>
|
</generalization>
|
||||||
<realization id="14">
|
<generalization id="20">
|
||||||
<end type="SOURCE" refId="6"/>
|
<end type="SOURCE" refId="5"/>
|
||||||
<end type="TARGET" refId="3"/>
|
<end type="TARGET" refId="2"/>
|
||||||
|
</generalization>
|
||||||
|
<realization id="21">
|
||||||
|
<end type="SOURCE" refId="1"/>
|
||||||
|
<end type="TARGET" refId="2"/>
|
||||||
</realization>
|
</realization>
|
||||||
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
<classifier-display autosize="true" stereotype="true" package="true" initial-value="false" signature="true"
|
||||||
sort-features="false" accessors="true" visibility="true">
|
sort-features="false" accessors="true" visibility="true">
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.abstractdocument.domain {
|
|
||||||
class Car {
|
|
||||||
+ Car(properties : Map<String, Object>)
|
|
||||||
}
|
|
||||||
interface HasModel {
|
|
||||||
+ PROPERTY : String {static}
|
|
||||||
+ getModel() : Optional<String>
|
|
||||||
}
|
|
||||||
interface HasParts {
|
|
||||||
+ PROPERTY : String {static}
|
|
||||||
+ getParts() : Stream<Part>
|
|
||||||
}
|
|
||||||
interface HasPrice {
|
|
||||||
+ PROPERTY : String {static}
|
|
||||||
+ getPrice() : Optional<Number>
|
|
||||||
}
|
|
||||||
interface HasType {
|
|
||||||
+ PROPERTY : String {static}
|
|
||||||
+ getType() : Optional<String>
|
|
||||||
}
|
|
||||||
class Part {
|
|
||||||
+ Part(properties : Map<String, Object>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
package com.iluwatar.abstractdocument {
|
|
||||||
abstract class AbstractDocument {
|
|
||||||
- properties : Map<String, Object>
|
|
||||||
# AbstractDocument(properties : Map<String, Object>)
|
|
||||||
+ children(key : String, constructor : Function<Map<String, Object>, T>) : Stream<T>
|
|
||||||
+ get(key : String) : Object
|
|
||||||
+ put(key : String, value : Object)
|
|
||||||
+ toString() : String
|
|
||||||
}
|
|
||||||
class App {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
interface Document {
|
|
||||||
+ children(String, Function<Map<String, Object>, T>) : Stream<T> {abstract}
|
|
||||||
+ get(String) : Object {abstract}
|
|
||||||
+ put(String, Object) {abstract}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AbstractDocument ..|> Document
|
|
||||||
Car ..|> HasModel
|
|
||||||
Car ..|> HasPrice
|
|
||||||
Car ..|> HasParts
|
|
||||||
Car --|> AbstractDocument
|
|
||||||
HasModel --|> Document
|
|
||||||
HasParts --|> Document
|
|
||||||
HasPrice --|> Document
|
|
||||||
HasType --|> Document
|
|
||||||
Part ..|> HasType
|
|
||||||
Part ..|> HasModel
|
|
||||||
Part ..|> HasPrice
|
|
||||||
Part --|> AbstractDocument
|
|
||||||
@enduml
|
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>abstract-document</artifactId>
|
<artifactId>abstract-document</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -30,8 +30,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static junit.framework.TestCase.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AbstractDocument test class
|
* AbstractDocument test class
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.abstractdocument;
|
package com.iluwatar.abstractdocument;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple App test
|
* Simple App test
|
||||||
|
@ -28,13 +28,13 @@ import com.iluwatar.abstractdocument.domain.HasParts;
|
|||||||
import com.iluwatar.abstractdocument.domain.HasPrice;
|
import com.iluwatar.abstractdocument.domain.HasPrice;
|
||||||
import com.iluwatar.abstractdocument.domain.HasType;
|
import com.iluwatar.abstractdocument.domain.HasType;
|
||||||
import com.iluwatar.abstractdocument.domain.Part;
|
import com.iluwatar.abstractdocument.domain.Part;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for Part and Car
|
* Test for Part and Car
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Abstract Factory
|
title: Abstract Factory
|
||||||
folder: abstract-factory
|
folder: abstract-factory
|
||||||
permalink: /patterns/abstract-factory/
|
permalink: /patterns/abstract-factory/
|
||||||
pumlid: PSZB3OD034NHLa81Czwd6sCC39gVxEUWT1_ssLmTtQLqgR5fM7sTmFGtaV6TZu8prd0r6HtQaMKqAZLk1XjT_E6qgPUZfyc0MdTgx0-8LuUn8ErFXdr98NypXxKyezKV
|
|
||||||
categories: Creational
|
categories: Creational
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
@ -120,6 +119,45 @@ king.getDescription(); // Output: This is the Elven king!
|
|||||||
army.getDescription(); // Output: This is the Elven Army!
|
army.getDescription(); // Output: This is the Elven Army!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Now, we can design a factory for our different kingdom factories. In this example, we created FactoryMaker, responsible for returning an instance of either ElfKingdomFactory or OrcKingdomFactory.
|
||||||
|
The client can use FactoryMaker to create the desired concrete factory which, in turn, will produce different concrete objects (Army, King, Castle).
|
||||||
|
In this example, we also used an enum to parameterize which type of kingdom factory the client will ask for.
|
||||||
|
|
||||||
|
```
|
||||||
|
public static class FactoryMaker {
|
||||||
|
|
||||||
|
public enum KingdomType {
|
||||||
|
ELF, ORC
|
||||||
|
}
|
||||||
|
|
||||||
|
public static KingdomFactory makeFactory(KingdomType type) {
|
||||||
|
switch (type) {
|
||||||
|
case ELF:
|
||||||
|
return new ElfKingdomFactory();
|
||||||
|
case ORC:
|
||||||
|
return new OrcKingdomFactory();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("KingdomType not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
App app = new App();
|
||||||
|
|
||||||
|
LOGGER.info("Elf Kingdom");
|
||||||
|
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
|
||||||
|
LOGGER.info(app.getArmy().getDescription());
|
||||||
|
LOGGER.info(app.getCastle().getDescription());
|
||||||
|
LOGGER.info(app.getKing().getDescription());
|
||||||
|
|
||||||
|
LOGGER.info("Orc Kingdom");
|
||||||
|
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
|
||||||
|
-- similar use of the orc factory
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Applicability
|
## Applicability
|
||||||
Use the Abstract Factory pattern when
|
Use the Abstract Factory pattern when
|
||||||
|
|
||||||
@ -141,9 +179,15 @@ Use the Abstract Factory pattern when
|
|||||||
|
|
||||||
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
|
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time.
|
||||||
|
|
||||||
|
|
||||||
## Tutorial
|
## Tutorial
|
||||||
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
|
||||||
|
|
||||||
|
## Presentations
|
||||||
|
|
||||||
|
* [Abstract Factory Pattern](etc/presentation.html)
|
||||||
|
|
||||||
|
|
||||||
## Real world examples
|
## Real world examples
|
||||||
|
|
||||||
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
||||||
|
BIN
abstract-factory/etc/diagram1.png
Normal file
BIN
abstract-factory/etc/diagram1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
BIN
abstract-factory/etc/diagram2.png
Normal file
BIN
abstract-factory/etc/diagram2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
190
abstract-factory/etc/presentation.html
Normal file
190
abstract-factory/etc/presentation.html
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
Copyright (c) 2017 Rodolfo Forte
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Design Patterns - Abstract Factory Presentation</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
|
||||||
|
|
||||||
|
body { font-family: 'Droid Serif'; }
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-family: 'Yanone Kaffeesatz';
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 0.3em solid rgba(0,0,0,0.5);
|
||||||
|
padding: 0 15px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width:100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<textarea id="source">
|
||||||
|
|
||||||
|
class: center, middle
|
||||||
|
|
||||||
|
# Abstract Factory
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Also known as
|
||||||
|
|
||||||
|
* Kit
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Intent
|
||||||
|
|
||||||
|
* Provide an interface for creating families of related or dependent objects without specifying their concrete classes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Explanation
|
||||||
|
|
||||||
|
* [Wikipedia](https://en.wikipedia.org/wiki/Abstract_factory_pattern) says:
|
||||||
|
> "The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes"
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
* In plain words:
|
||||||
|
* A factory that groups individual but related/dependent factories together without specifying their concrete classes;
|
||||||
|
* A factory of factories;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Example
|
||||||
|
|
||||||
|
* In a factory that creates kingdoms, we need objects with common theme:
|
||||||
|
|
||||||
|
* Elven kingdom needs an Elven king, Elven castle and Elven army;
|
||||||
|
|
||||||
|
* Orcish kingdom needs an Orcish king, Orcish castle and Orcish army;
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
* There is a dependency between the objects in the kingdom;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Diagram
|
||||||
|
|
||||||
|
* Based on the kingdom example, the diagram below showcases the different concrete factories and their concrete products:
|
||||||
|
|
||||||
|
.center[]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Diagram
|
||||||
|
|
||||||
|
* The class diagram below showcases the factory of factories;
|
||||||
|
|
||||||
|
* At runtime, we can define which Kingdom type is needed and pass it as a parameter to define which concrete KingdomFactory to instantiate;
|
||||||
|
|
||||||
|
* The concrete factory returned will then be able to produce the related objects of the specified type;
|
||||||
|
|
||||||
|
.center[]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Applicability
|
||||||
|
|
||||||
|
Use the Abstract Factory pattern when:
|
||||||
|
|
||||||
|
* A system should be independent of how its products are created, composed and represented;
|
||||||
|
|
||||||
|
* A system should be configured with one of multiple families of products;
|
||||||
|
|
||||||
|
* A family of related product objects is designed to be used together, and you need to enforce this constraint;
|
||||||
|
|
||||||
|
* You want to provide a class library of products, and you want to reveal just their interfaces, not their implementations;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Applicability
|
||||||
|
|
||||||
|
Use the Abstract Factory pattern when:
|
||||||
|
|
||||||
|
* The lifetime of the dependency is conceptually shorter than the lifetime of the consumer;
|
||||||
|
|
||||||
|
* You need a run-time value to construct a particular dependency;
|
||||||
|
|
||||||
|
* You want to decide which product to call from a family at runtime;
|
||||||
|
|
||||||
|
* You need to supply one or more parameters only known at run-time before you can resolve a dependency;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#Use Cases
|
||||||
|
|
||||||
|
* Selecting to call the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime;
|
||||||
|
* Unit test case writing becomes much easier;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Consequences
|
||||||
|
|
||||||
|
* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Real world examples
|
||||||
|
|
||||||
|
[javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
|
||||||
|
|
||||||
|
[javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
|
||||||
|
|
||||||
|
[javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tutorials
|
||||||
|
|
||||||
|
* Source code http://java-design-patterns.com/patterns/abstract-factory/
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
var slideshow = remark.create();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>abstract-factory</artifactId>
|
<artifactId>abstract-factory</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -25,6 +25,8 @@ package com.iluwatar.abstractfactory;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
|
* The Abstract Factory pattern provides a way to encapsulate a group of individual factories that have a common theme
|
||||||
@ -94,7 +96,34 @@ public class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Program entry point
|
* The factory of kingdom factories.
|
||||||
|
*/
|
||||||
|
public static class FactoryMaker {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enumeration for the different types of Kingdoms.
|
||||||
|
*/
|
||||||
|
public enum KingdomType {
|
||||||
|
ELF, ORC
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The factory method to create KingdomFactory concrete objects.
|
||||||
|
*/
|
||||||
|
public static KingdomFactory makeFactory(KingdomType type) {
|
||||||
|
switch (type) {
|
||||||
|
case ELF:
|
||||||
|
return new ElfKingdomFactory();
|
||||||
|
case ORC:
|
||||||
|
return new OrcKingdomFactory();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("KingdomType not supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Program entry point.
|
||||||
*
|
*
|
||||||
* @param args
|
* @param args
|
||||||
* command line args
|
* command line args
|
||||||
@ -104,17 +133,15 @@ public class App {
|
|||||||
App app = new App();
|
App app = new App();
|
||||||
|
|
||||||
LOGGER.info("Elf Kingdom");
|
LOGGER.info("Elf Kingdom");
|
||||||
app.createKingdom(new ElfKingdomFactory());
|
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
|
||||||
LOGGER.info(app.getArmy().getDescription());
|
LOGGER.info(app.getArmy().getDescription());
|
||||||
LOGGER.info(app.getCastle().getDescription());
|
LOGGER.info(app.getCastle().getDescription());
|
||||||
LOGGER.info(app.getKing().getDescription());
|
LOGGER.info(app.getKing().getDescription());
|
||||||
|
|
||||||
LOGGER.info("Orc Kingdom");
|
LOGGER.info("Orc Kingdom");
|
||||||
app.createKingdom(new OrcKingdomFactory());
|
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
|
||||||
LOGGER.info(app.getArmy().getDescription());
|
LOGGER.info(app.getArmy().getDescription());
|
||||||
LOGGER.info(app.getCastle().getDescription());
|
LOGGER.info(app.getCastle().getDescription());
|
||||||
LOGGER.info(app.getKing().getDescription());
|
LOGGER.info(app.getKing().getDescription());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -22,11 +22,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import org.junit.Before;
|
import com.iluwatar.abstractfactory.App.FactoryMaker;
|
||||||
import org.junit.Test;
|
import com.iluwatar.abstractfactory.App.FactoryMaker.KingdomType;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for abstract factory
|
* Test for abstract factory
|
||||||
@ -37,10 +40,10 @@ public class AbstractFactoryTest {
|
|||||||
private KingdomFactory elfFactory;
|
private KingdomFactory elfFactory;
|
||||||
private KingdomFactory orcFactory;
|
private KingdomFactory orcFactory;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
elfFactory = new ElfKingdomFactory();
|
elfFactory = FactoryMaker.makeFactory(KingdomType.ELF);
|
||||||
orcFactory = new OrcKingdomFactory();
|
orcFactory = FactoryMaker.makeFactory(KingdomType.ORC);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.abstractfactory;
|
package com.iluwatar.abstractfactory;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Adapter
|
title: Adapter
|
||||||
folder: adapter
|
folder: adapter
|
||||||
permalink: /patterns/adapter/
|
permalink: /patterns/adapter/
|
||||||
pumlid: DSR14S8m30J0Lg20M7-wEMnDOiPMFDA9j0yyUEtUkzMHJTF7xI1NF4GSLzaxZtncgDVJgCPIpobzv0N2vOKtjgRHTziMI7KBcOXl10thfxB-Nz9dMJd71m00
|
|
||||||
categories: Structural
|
categories: Structural
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>adapter</artifactId>
|
<artifactId>adapter</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -46,7 +46,7 @@ public class AdapterPatternTest {
|
|||||||
/**
|
/**
|
||||||
* This method runs before the test execution and sets the bean objects in the beans Map.
|
* This method runs before the test execution and sets the bean objects in the beans Map.
|
||||||
*/
|
*/
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
beans = new HashMap<>();
|
beans = new HashMap<>();
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.adapter;
|
package com.iluwatar.adapter;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Aggregator Microservices
|
title: Aggregator Microservices
|
||||||
folder: aggregator-microservices
|
folder: aggregator-microservices
|
||||||
permalink: /patterns/aggregator-microservices/
|
permalink: /patterns/aggregator-microservices/
|
||||||
pumlid: JOov3SCm301NIGQGs7iRXYPa1g8ayB7NjuiKwGvtmBrbKC-Tq_hhY5Y-0HXUjKaS-Kbdepc2HrIQ2jBpma23BvvOTdPfeooCO1iEYlu0O6l63MDQKI6Rp-CKOWSE-ey_NzEqhjH-0m00
|
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@ -54,8 +54,13 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -22,15 +22,15 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.aggregator.microservices;
|
package com.iluwatar.aggregator.microservices;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import static org.mockito.Mockito.when;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test Aggregation of domain objects
|
* Test Aggregation of domain objects
|
||||||
*/
|
*/
|
||||||
@ -45,7 +45,7 @@ public class AggregatorTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private ProductInventoryClient inventoryClient;
|
private ProductInventoryClient inventoryClient;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
}
|
}
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.aggregator.microservices {
|
|
||||||
class Aggregator {
|
|
||||||
- informationClient : ProductInformationClient
|
|
||||||
- inventoryClient : ProductInventoryClient
|
|
||||||
+ Aggregator()
|
|
||||||
+ getProduct() : Product
|
|
||||||
}
|
|
||||||
class App {
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class Product {
|
|
||||||
- productInventories : int
|
|
||||||
- title : String
|
|
||||||
+ Product()
|
|
||||||
+ getProductInventories() : int
|
|
||||||
+ getTitle() : String
|
|
||||||
+ setProductInventories(productInventories : int)
|
|
||||||
+ setTitle(title : String)
|
|
||||||
}
|
|
||||||
interface ProductInformationClient {
|
|
||||||
+ getProductTitle() : String {abstract}
|
|
||||||
}
|
|
||||||
class ProductInformationClientImpl {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ ProductInformationClientImpl()
|
|
||||||
+ getProductTitle() : String
|
|
||||||
}
|
|
||||||
interface ProductInventoryClient {
|
|
||||||
+ getProductInventories() : int {abstract}
|
|
||||||
}
|
|
||||||
class ProductInventoryClientImpl {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ ProductInventoryClientImpl()
|
|
||||||
+ getProductInventories() : int
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Aggregator --> "-informationClient" ProductInformationClient
|
|
||||||
Aggregator --> "-inventoryClient" ProductInventoryClient
|
|
||||||
ProductInformationClientImpl ..|> ProductInformationClient
|
|
||||||
ProductInventoryClientImpl ..|> ProductInventoryClient
|
|
||||||
@enduml
|
|
@ -1,12 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.information.microservice {
|
|
||||||
class InformationApplication {
|
|
||||||
+ InformationApplication()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class InformationController {
|
|
||||||
+ InformationController()
|
|
||||||
+ getProductTitle() : String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@enduml
|
|
@ -1,12 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.inventory.microservice {
|
|
||||||
class InventoryApplication {
|
|
||||||
+ InventoryApplication()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class InventoryController {
|
|
||||||
+ InventoryController()
|
|
||||||
+ getProductInventories() : int
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@enduml
|
|
@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@ -54,8 +54,13 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,8 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.information.microservice;
|
package com.iluwatar.information.microservice;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for Information Rest Controller
|
* Test for Information Rest Controller
|
||||||
@ -36,7 +37,7 @@ public class InformationControllerTest {
|
|||||||
|
|
||||||
String title = infoController.getProductTitle();
|
String title = infoController.getProductTitle();
|
||||||
|
|
||||||
Assert.assertEquals("The Product Title.", title);
|
assertEquals("The Product Title.", title);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
@ -54,8 +54,13 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,8 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.inventory.microservice;
|
package com.iluwatar.inventory.microservice;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test Inventory Rest Controller
|
* Test Inventory Rest Controller
|
||||||
@ -35,6 +36,6 @@ public class InventoryControllerTest {
|
|||||||
|
|
||||||
int numberOfInventories = inventoryController.getProductInventories();
|
int numberOfInventories = inventoryController.getProductInventories();
|
||||||
|
|
||||||
Assert.assertEquals(5, numberOfInventories);
|
assertEquals(5, numberOfInventories);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,32 +29,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>aggregator-microservices</artifactId>
|
<artifactId>aggregator-microservices</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.github.markusmo3.urm</groupId>
|
|
||||||
<artifactId>urm-maven-plugin</artifactId>
|
|
||||||
<version>${urm.version}</version>
|
|
||||||
<configuration combine.self="override">
|
|
||||||
<outputDirectory>${project.basedir}/../etc</outputDirectory>
|
|
||||||
<packages>
|
|
||||||
<param>com.iluwatar</param>
|
|
||||||
</packages>
|
|
||||||
<skipForProjects>
|
|
||||||
<!-- skip for parent project -->
|
|
||||||
<param>aggregator-microservices</param>
|
|
||||||
</skipForProjects>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>information-microservice</module>
|
<module>information-microservice</module>
|
||||||
<module>aggregator-service</module>
|
<module>aggregator-service</module>
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: API Gateway
|
title: API Gateway
|
||||||
folder: api-gateway
|
folder: api-gateway
|
||||||
permalink: /patterns/api-gateway/
|
permalink: /patterns/api-gateway/
|
||||||
pumlid: JSox3SCm303HLP819FRUXg49cO542_nOyFPncUvUSszHwhbpMdyT4TCt0CDLcyIHdtGsEZLOez8vG7ek33JuueLbPvUcPM84cpeCz2S0fvI6mGjluA1_b-Tt2N5D6tNcw3y0
|
|
||||||
categories: Architectural
|
categories: Architectural
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>api-gateway-service</artifactId>
|
<artifactId>api-gateway-service</artifactId>
|
||||||
@ -53,8 +53,13 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -22,15 +22,15 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.api.gateway;
|
package com.iluwatar.api.gateway;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import static org.mockito.Mockito.when;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test API Gateway Pattern
|
* Test API Gateway Pattern
|
||||||
*/
|
*/
|
||||||
@ -45,7 +45,7 @@ public class ApiGatewayTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private PriceClient priceClient;
|
private PriceClient priceClient;
|
||||||
|
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.api.gateway {
|
|
||||||
class ApiGateway {
|
|
||||||
- imageClient : ImageClient
|
|
||||||
- priceClient : PriceClient
|
|
||||||
+ ApiGateway()
|
|
||||||
+ getProductDesktop() : DesktopProduct
|
|
||||||
+ getProductMobile() : MobileProduct
|
|
||||||
}
|
|
||||||
class App {
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class DesktopProduct {
|
|
||||||
- imagePath : String
|
|
||||||
- price : String
|
|
||||||
+ DesktopProduct()
|
|
||||||
+ getImagePath() : String
|
|
||||||
+ getPrice() : String
|
|
||||||
+ setImagePath(imagePath : String)
|
|
||||||
+ setPrice(price : String)
|
|
||||||
}
|
|
||||||
interface ImageClient {
|
|
||||||
+ getImagePath() : String {abstract}
|
|
||||||
}
|
|
||||||
class ImageClientImpl {
|
|
||||||
+ ImageClientImpl()
|
|
||||||
+ getImagePath() : String
|
|
||||||
}
|
|
||||||
class MobileProduct {
|
|
||||||
- price : String
|
|
||||||
+ MobileProduct()
|
|
||||||
+ getPrice() : String
|
|
||||||
+ setPrice(price : String)
|
|
||||||
}
|
|
||||||
interface PriceClient {
|
|
||||||
+ getPrice() : String {abstract}
|
|
||||||
}
|
|
||||||
class PriceClientImpl {
|
|
||||||
+ PriceClientImpl()
|
|
||||||
+ getPrice() : String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ApiGateway --> "-imageClient" ImageClient
|
|
||||||
ApiGateway --> "-priceClient" PriceClient
|
|
||||||
ImageClientImpl ..|> ImageClient
|
|
||||||
PriceClientImpl ..|> PriceClient
|
|
||||||
@enduml
|
|
@ -1,12 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.image.microservice {
|
|
||||||
class ImageApplication {
|
|
||||||
+ ImageApplication()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class ImageController {
|
|
||||||
+ ImageController()
|
|
||||||
+ getImagePath() : String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@enduml
|
|
@ -1,12 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.price.microservice {
|
|
||||||
class PriceApplication {
|
|
||||||
+ PriceApplication()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class PriceController {
|
|
||||||
+ PriceController()
|
|
||||||
+ getPrice() : String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@enduml
|
|
@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@ -54,8 +54,13 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,8 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.image.microservice;
|
package com.iluwatar.image.microservice;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for Image Rest Controller
|
* Test for Image Rest Controller
|
||||||
@ -35,6 +36,6 @@ public class ImageControllerTest {
|
|||||||
|
|
||||||
String imagePath = imageController.getImagePath();
|
String imagePath = imageController.getImagePath();
|
||||||
|
|
||||||
Assert.assertEquals("/product-image.png", imagePath);
|
assertEquals("/product-image.png", imagePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,32 +29,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>com.github.markusmo3.urm</groupId>
|
|
||||||
<artifactId>urm-maven-plugin</artifactId>
|
|
||||||
<version>${urm.version}</version>
|
|
||||||
<configuration combine.self="override">
|
|
||||||
<outputDirectory>${project.basedir}/../etc</outputDirectory>
|
|
||||||
<packages>
|
|
||||||
<param>com.iluwatar</param>
|
|
||||||
</packages>
|
|
||||||
<skipForProjects>
|
|
||||||
<!-- skip for parent project -->
|
|
||||||
<param>api-gateway</param>
|
|
||||||
</skipForProjects>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>image-microservice</module>
|
<module>image-microservice</module>
|
||||||
<module>price-microservice</module>
|
<module>price-microservice</module>
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>api-gateway</artifactId>
|
<artifactId>api-gateway</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@ -54,8 +54,13 @@
|
|||||||
<artifactId>spring-boot-starter-web</artifactId>
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.price.microservice;
|
package com.iluwatar.price.microservice;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for Price Rest Controller
|
* Test for Price Rest Controller
|
||||||
@ -36,6 +36,6 @@ public class PriceControllerTest {
|
|||||||
|
|
||||||
String price = priceController.getPrice();
|
String price = priceController.getPrice();
|
||||||
|
|
||||||
Assert.assertEquals("20", price);
|
assertEquals("20", price);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Async Method Invocation
|
title: Async Method Invocation
|
||||||
folder: async-method-invocation
|
folder: async-method-invocation
|
||||||
permalink: /patterns/async-method-invocation/
|
permalink: /patterns/async-method-invocation/
|
||||||
pumlid: TSdB3SCW303GLTe1mFTkunWhk0A3_4dKxTi5UdlIUuhIoCPfuz4Zjhy03EzwIlGyqjbeQR16fJL1HjuOQF362qjZbrFBnWWsTPZeFm3wHwbCZhvQ4RqMOSXIuA1_LzDctJd75m00
|
|
||||||
categories: Concurrency
|
categories: Concurrency
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.async.method.invocation {
|
|
||||||
class App {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ App()
|
|
||||||
- callback(name : String) : AsyncCallback<T> {static}
|
|
||||||
- lazyval(value : T, delayMillis : long) : Callable<T> {static}
|
|
||||||
- log(msg : String) {static}
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
interface AsyncCallback<T> {
|
|
||||||
+ onComplete(T, Optional<Exception>) {abstract}
|
|
||||||
}
|
|
||||||
interface AsyncExecutor {
|
|
||||||
+ endProcess(AsyncResult<T>) : T {abstract}
|
|
||||||
+ startProcess(Callable<T>) : AsyncResult<T> {abstract}
|
|
||||||
+ startProcess(Callable<T>, AsyncCallback<T>) : AsyncResult<T> {abstract}
|
|
||||||
}
|
|
||||||
interface AsyncResult<T> {
|
|
||||||
+ await() {abstract}
|
|
||||||
+ getValue() : T {abstract}
|
|
||||||
+ isCompleted() : boolean {abstract}
|
|
||||||
}
|
|
||||||
class ThreadAsyncExecutor {
|
|
||||||
- idx : AtomicInteger
|
|
||||||
+ ThreadAsyncExecutor()
|
|
||||||
+ endProcess(asyncResult : AsyncResult<T>) : T
|
|
||||||
+ startProcess(task : Callable<T>) : AsyncResult<T>
|
|
||||||
+ startProcess(task : Callable<T>, callback : AsyncCallback<T>) : AsyncResult<T>
|
|
||||||
}
|
|
||||||
-class CompletableResult<T> {
|
|
||||||
~ COMPLETED : int {static}
|
|
||||||
~ FAILED : int {static}
|
|
||||||
~ RUNNING : int {static}
|
|
||||||
~ callback : Optional<AsyncCallback<T>>
|
|
||||||
~ exception : Exception
|
|
||||||
~ lock : Object
|
|
||||||
~ state : int
|
|
||||||
~ value : T
|
|
||||||
~ CompletableResult<T>(callback : AsyncCallback<T>)
|
|
||||||
+ await()
|
|
||||||
+ getValue() : T
|
|
||||||
+ isCompleted() : boolean
|
|
||||||
~ setException(exception : Exception)
|
|
||||||
~ setValue(value : T)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
CompletableResult ..+ ThreadAsyncExecutor
|
|
||||||
ThreadAsyncExecutor ..|> AsyncExecutor
|
|
||||||
CompletableResult ..|> AsyncResult
|
|
||||||
@enduml
|
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>async-method-invocation</artifactId>
|
<artifactId>async-method-invocation</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.async.method.invocation;
|
package com.iluwatar.async.method.invocation;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.async.method.invocation;
|
package com.iluwatar.async.method.invocation;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Matchers;
|
import org.mockito.Matchers;
|
||||||
|
|
||||||
@ -30,8 +30,21 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static java.time.Duration.ofMillis;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTimeout;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.timeout;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,205 +57,217 @@ public class ThreadAsyncExecutorTest {
|
|||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)}
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)}
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 3000)
|
@Test
|
||||||
public void testSuccessfulTaskWithoutCallback() throws Exception {
|
public void testSuccessfulTaskWithoutCallback() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
|
||||||
final Object result = new Object();
|
final Object result = new Object();
|
||||||
final Callable<Object> task = mock(Callable.class);
|
final Callable<Object> task = mock(Callable.class);
|
||||||
when(task.call()).thenReturn(result);
|
when(task.call()).thenReturn(result);
|
||||||
|
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
||||||
assertNotNull(asyncResult);
|
assertNotNull(asyncResult);
|
||||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||||
assertTrue(asyncResult.isCompleted());
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
|
||||||
// Our task should only execute once ...
|
// Our task should only execute once ...
|
||||||
verify(task, times(1)).call();
|
verify(task, times(1)).call();
|
||||||
|
|
||||||
// ... and the result should be exactly the same object
|
// ... and the result should be exactly the same object
|
||||||
assertSame(result, asyncResult.getValue());
|
assertSame(result, asyncResult.getValue());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)}
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 3000)
|
@Test
|
||||||
public void testSuccessfulTaskWithCallback() throws Exception {
|
public void testSuccessfulTaskWithCallback() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
|
||||||
final Object result = new Object();
|
final Object result = new Object();
|
||||||
final Callable<Object> task = mock(Callable.class);
|
final Callable<Object> task = mock(Callable.class);
|
||||||
when(task.call()).thenReturn(result);
|
when(task.call()).thenReturn(result);
|
||||||
|
|
||||||
final AsyncCallback callback = mock(AsyncCallback.class);
|
final AsyncCallback callback = mock(AsyncCallback.class);
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
|
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
|
||||||
assertNotNull(asyncResult);
|
assertNotNull(asyncResult);
|
||||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||||
assertTrue(asyncResult.isCompleted());
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
|
||||||
// Our task should only execute once ...
|
// Our task should only execute once ...
|
||||||
verify(task, times(1)).call();
|
verify(task, times(1)).call();
|
||||||
|
|
||||||
// ... same for the callback, we expect our object
|
// ... same for the callback, we expect our object
|
||||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||||
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
|
verify(callback, times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||||
|
|
||||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||||
assertNotNull(optionalException);
|
assertNotNull(optionalException);
|
||||||
assertFalse(optionalException.isPresent());
|
assertFalse(optionalException.isPresent());
|
||||||
|
|
||||||
// ... and the result should be exactly the same object
|
// ... and the result should be exactly the same object
|
||||||
assertSame(result, asyncResult.getValue());
|
assertSame(result, asyncResult.getValue());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
||||||
* to execute
|
* to execute
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 5000)
|
@Test
|
||||||
public void testLongRunningTaskWithoutCallback() throws Exception {
|
public void testLongRunningTaskWithoutCallback() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(5000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
|
||||||
final Object result = new Object();
|
final Object result = new Object();
|
||||||
final Callable<Object> task = mock(Callable.class);
|
final Callable<Object> task = mock(Callable.class);
|
||||||
when(task.call()).thenAnswer(i -> {
|
when(task.call()).thenAnswer(i -> {
|
||||||
Thread.sleep(1500);
|
Thread.sleep(1500);
|
||||||
return result;
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
||||||
|
assertNotNull(asyncResult);
|
||||||
|
assertFalse(asyncResult.isCompleted());
|
||||||
|
|
||||||
|
try {
|
||||||
|
asyncResult.getValue();
|
||||||
|
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
assertNotNull(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our task should only execute once, but it can take a while ...
|
||||||
|
verify(task, timeout(3000).times(1)).call();
|
||||||
|
|
||||||
|
// Prevent timing issues, and wait until the result is available
|
||||||
|
asyncResult.await();
|
||||||
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
verifyNoMoreInteractions(task);
|
||||||
|
|
||||||
|
// ... and the result should be exactly the same object
|
||||||
|
assertSame(result, asyncResult.getValue());
|
||||||
});
|
});
|
||||||
|
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
|
||||||
assertNotNull(asyncResult);
|
|
||||||
assertFalse(asyncResult.isCompleted());
|
|
||||||
|
|
||||||
try {
|
|
||||||
asyncResult.getValue();
|
|
||||||
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
assertNotNull(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our task should only execute once, but it can take a while ...
|
|
||||||
verify(task, timeout(3000).times(1)).call();
|
|
||||||
|
|
||||||
// Prevent timing issues, and wait until the result is available
|
|
||||||
asyncResult.await();
|
|
||||||
assertTrue(asyncResult.isCompleted());
|
|
||||||
verifyNoMoreInteractions(task);
|
|
||||||
|
|
||||||
// ... and the result should be exactly the same object
|
|
||||||
assertSame(result, asyncResult.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when a task
|
||||||
* takes a while to execute
|
* takes a while to execute
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 5000)
|
@Test
|
||||||
public void testLongRunningTaskWithCallback() throws Exception {
|
public void testLongRunningTaskWithCallback() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(5000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
|
||||||
final Object result = new Object();
|
final Object result = new Object();
|
||||||
final Callable<Object> task = mock(Callable.class);
|
final Callable<Object> task = mock(Callable.class);
|
||||||
when(task.call()).thenAnswer(i -> {
|
when(task.call()).thenAnswer(i -> {
|
||||||
Thread.sleep(1500);
|
Thread.sleep(1500);
|
||||||
return result;
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
final AsyncCallback<Object> callback = mock(AsyncCallback.class);
|
||||||
|
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
|
||||||
|
assertNotNull(asyncResult);
|
||||||
|
assertFalse(asyncResult.isCompleted());
|
||||||
|
|
||||||
|
verifyZeroInteractions(callback);
|
||||||
|
|
||||||
|
try {
|
||||||
|
asyncResult.getValue();
|
||||||
|
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
assertNotNull(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our task should only execute once, but it can take a while ...
|
||||||
|
verify(task, timeout(3000).times(1)).call();
|
||||||
|
|
||||||
|
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||||
|
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
|
||||||
|
|
||||||
|
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||||
|
assertNotNull(optionalException);
|
||||||
|
assertFalse(optionalException.isPresent());
|
||||||
|
|
||||||
|
// Prevent timing issues, and wait until the result is available
|
||||||
|
asyncResult.await();
|
||||||
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
verifyNoMoreInteractions(task, callback);
|
||||||
|
|
||||||
|
// ... and the result should be exactly the same object
|
||||||
|
assertSame(result, asyncResult.getValue());
|
||||||
});
|
});
|
||||||
|
|
||||||
final AsyncCallback<Object> callback = mock(AsyncCallback.class);
|
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(task, callback);
|
|
||||||
assertNotNull(asyncResult);
|
|
||||||
assertFalse(asyncResult.isCompleted());
|
|
||||||
|
|
||||||
verifyZeroInteractions(callback);
|
|
||||||
|
|
||||||
try {
|
|
||||||
asyncResult.getValue();
|
|
||||||
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
assertNotNull(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our task should only execute once, but it can take a while ...
|
|
||||||
verify(task, timeout(3000).times(1)).call();
|
|
||||||
|
|
||||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
|
||||||
verify(callback, timeout(3000).times(1)).onComplete(eq(result), optionalCaptor.capture());
|
|
||||||
|
|
||||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
|
||||||
assertNotNull(optionalException);
|
|
||||||
assertFalse(optionalException.isPresent());
|
|
||||||
|
|
||||||
// Prevent timing issues, and wait until the result is available
|
|
||||||
asyncResult.await();
|
|
||||||
assertTrue(asyncResult.isCompleted());
|
|
||||||
verifyNoMoreInteractions(task, callback);
|
|
||||||
|
|
||||||
// ... and the result should be exactly the same object
|
|
||||||
assertSame(result, asyncResult.getValue());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
* Test used to verify the happy path of {@link ThreadAsyncExecutor#startProcess(Callable)} when a task takes a while
|
||||||
* to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
|
* to execute, while waiting on the result using {@link ThreadAsyncExecutor#endProcess(AsyncResult)}
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 5000)
|
@Test
|
||||||
public void testEndProcess() throws Exception {
|
public void testEndProcess() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(5000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
|
||||||
final Object result = new Object();
|
final Object result = new Object();
|
||||||
final Callable<Object> task = mock(Callable.class);
|
final Callable<Object> task = mock(Callable.class);
|
||||||
when(task.call()).thenAnswer(i -> {
|
when(task.call()).thenAnswer(i -> {
|
||||||
Thread.sleep(1500);
|
Thread.sleep(1500);
|
||||||
return result;
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
||||||
|
assertNotNull(asyncResult);
|
||||||
|
assertFalse(asyncResult.isCompleted());
|
||||||
|
|
||||||
|
try {
|
||||||
|
asyncResult.getValue();
|
||||||
|
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
assertNotNull(e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSame(result, executor.endProcess(asyncResult));
|
||||||
|
verify(task, times(1)).call();
|
||||||
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
|
||||||
|
// Calling end process a second time while already finished should give the same result
|
||||||
|
assertSame(result, executor.endProcess(asyncResult));
|
||||||
|
verifyNoMoreInteractions(task);
|
||||||
});
|
});
|
||||||
|
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(task);
|
|
||||||
assertNotNull(asyncResult);
|
|
||||||
assertFalse(asyncResult.isCompleted());
|
|
||||||
|
|
||||||
try {
|
|
||||||
asyncResult.getValue();
|
|
||||||
fail("Expected IllegalStateException when calling AsyncResult#getValue on a non-completed task");
|
|
||||||
} catch (IllegalStateException e) {
|
|
||||||
assertNotNull(e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
assertSame(result, executor.endProcess(asyncResult));
|
|
||||||
verify(task, times(1)).call();
|
|
||||||
assertTrue(asyncResult.isCompleted());
|
|
||||||
|
|
||||||
// Calling end process a second time while already finished should give the same result
|
|
||||||
assertSame(result, executor.endProcess(asyncResult));
|
|
||||||
verifyNoMoreInteractions(task);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when the callable is 'null'
|
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable)} when the callable is 'null'
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 3000)
|
@Test
|
||||||
public void testNullTask() throws Exception {
|
public void testNullTask() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(null);
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
final AsyncResult<Object> asyncResult = executor.startProcess(null);
|
||||||
|
|
||||||
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
|
assertNotNull(asyncResult, "The AsyncResult should not be 'null', even though the task was 'null'.");
|
||||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||||
assertTrue(asyncResult.isCompleted());
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
asyncResult.getValue();
|
asyncResult.getValue();
|
||||||
fail("Expected ExecutionException with NPE as cause");
|
fail("Expected ExecutionException with NPE as cause");
|
||||||
} catch (final ExecutionException e) {
|
} catch (final ExecutionException e) {
|
||||||
assertNotNull(e.getMessage());
|
assertNotNull(e.getMessage());
|
||||||
assertNotNull(e.getCause());
|
assertNotNull(e.getCause());
|
||||||
assertEquals(NullPointerException.class, e.getCause().getClass());
|
assertEquals(NullPointerException.class, e.getCause().getClass());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,36 +275,38 @@ public class ThreadAsyncExecutorTest {
|
|||||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the
|
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when the
|
||||||
* callable is 'null', but the asynchronous callback is provided
|
* callable is 'null', but the asynchronous callback is provided
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 3000)
|
@Test
|
||||||
public void testNullTaskWithCallback() throws Exception {
|
public void testNullTaskWithCallback() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final AsyncCallback<Object> callback = mock(AsyncCallback.class);
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(null, callback);
|
final AsyncCallback<Object> callback = mock(AsyncCallback.class);
|
||||||
|
final AsyncResult<Object> asyncResult = executor.startProcess(null, callback);
|
||||||
|
|
||||||
assertNotNull("The AsyncResult should not be 'null', even though the task was 'null'.", asyncResult);
|
assertNotNull(asyncResult, "The AsyncResult should not be 'null', even though the task was 'null'.");
|
||||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||||
assertTrue(asyncResult.isCompleted());
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
|
||||||
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
final ArgumentCaptor<Optional<Exception>> optionalCaptor = ArgumentCaptor.forClass((Class) Optional.class);
|
||||||
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
|
verify(callback, times(1)).onComplete(Matchers.isNull(), optionalCaptor.capture());
|
||||||
|
|
||||||
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
final Optional<Exception> optionalException = optionalCaptor.getValue();
|
||||||
assertNotNull(optionalException);
|
assertNotNull(optionalException);
|
||||||
assertTrue(optionalException.isPresent());
|
assertTrue(optionalException.isPresent());
|
||||||
|
|
||||||
final Exception exception = optionalException.get();
|
final Exception exception = optionalException.get();
|
||||||
assertNotNull(exception);
|
assertNotNull(exception);
|
||||||
assertEquals(NullPointerException.class, exception.getClass());
|
assertEquals(NullPointerException.class, exception.getClass());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
asyncResult.getValue();
|
asyncResult.getValue();
|
||||||
fail("Expected ExecutionException with NPE as cause");
|
fail("Expected ExecutionException with NPE as cause");
|
||||||
} catch (final ExecutionException e) {
|
} catch (final ExecutionException e) {
|
||||||
assertNotNull(e.getMessage());
|
assertNotNull(e.getMessage());
|
||||||
assertNotNull(e.getCause());
|
assertNotNull(e.getCause());
|
||||||
assertEquals(NullPointerException.class, e.getCause().getClass());
|
assertEquals(NullPointerException.class, e.getCause().getClass());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,24 +314,29 @@ public class ThreadAsyncExecutorTest {
|
|||||||
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both
|
* Test used to verify the behaviour of {@link ThreadAsyncExecutor#startProcess(Callable, AsyncCallback)} when both
|
||||||
* the callable and the asynchronous callback are 'null'
|
* the callable and the asynchronous callback are 'null'
|
||||||
*/
|
*/
|
||||||
@Test(timeout = 3000)
|
@Test
|
||||||
public void testNullTaskWithNullCallback() throws Exception {
|
public void testNullTaskWithNullCallback() throws Exception {
|
||||||
// Instantiate a new executor and start a new 'null' task ...
|
assertTimeout(ofMillis(3000), () -> {
|
||||||
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
// Instantiate a new executor and start a new 'null' task ...
|
||||||
final AsyncResult<Object> asyncResult = executor.startProcess(null, null);
|
final ThreadAsyncExecutor executor = new ThreadAsyncExecutor();
|
||||||
|
final AsyncResult<Object> asyncResult = executor.startProcess(null, null);
|
||||||
|
|
||||||
assertNotNull("The AsyncResult should not be 'null', even though the task and callback were 'null'.", asyncResult);
|
assertNotNull(
|
||||||
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
asyncResult,
|
||||||
assertTrue(asyncResult.isCompleted());
|
"The AsyncResult should not be 'null', even though the task and callback were 'null'."
|
||||||
|
);
|
||||||
|
asyncResult.await(); // Prevent timing issues, and wait until the result is available
|
||||||
|
assertTrue(asyncResult.isCompleted());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
asyncResult.getValue();
|
asyncResult.getValue();
|
||||||
fail("Expected ExecutionException with NPE as cause");
|
fail("Expected ExecutionException with NPE as cause");
|
||||||
} catch (final ExecutionException e) {
|
} catch (final ExecutionException e) {
|
||||||
assertNotNull(e.getMessage());
|
assertNotNull(e.getMessage());
|
||||||
assertNotNull(e.getCause());
|
assertNotNull(e.getCause());
|
||||||
assertEquals(NullPointerException.class, e.getCause().getClass());
|
assertEquals(NullPointerException.class, e.getCause().getClass());
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,8 +18,8 @@ incomplete or inappropriate state
|
|||||||
## Applicability
|
## Applicability
|
||||||
Use the Balking pattern when
|
Use the Balking pattern when
|
||||||
|
|
||||||
*you want to invoke an action on an object only when it is in a particular state
|
* you want to invoke an action on an object only when it is in a particular state
|
||||||
*objects are generally only in a state that is prone to balking temporarily
|
* objects are generally only in a state that is prone to balking temporarily
|
||||||
but for an unknown amount of time
|
but for an unknown amount of time
|
||||||
|
|
||||||
## Related patterns
|
## Related patterns
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.balking {
|
|
||||||
class App {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class WashingMachine {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
- washingMachineState : WashingMachineState
|
|
||||||
+ WashingMachine()
|
|
||||||
+ endOfWashing()
|
|
||||||
+ getWashingMachineState() : WashingMachineState
|
|
||||||
+ wash()
|
|
||||||
}
|
|
||||||
enum WashingMachineState {
|
|
||||||
+ ENABLED {static}
|
|
||||||
+ WASHING {static}
|
|
||||||
+ valueOf(name : String) : WashingMachineState {static}
|
|
||||||
+ values() : WashingMachineState[] {static}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WashingMachine --> "-washingMachineState" WashingMachineState
|
|
||||||
@enduml
|
|
@ -29,15 +29,20 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
<artifactId>balking</artifactId>
|
<artifactId>balking</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
package com.iluwatar.balking;
|
package com.iluwatar.balking;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Application test
|
* Application test
|
||||||
|
@ -22,13 +22,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.balking;
|
package com.iluwatar.balking;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link WashingMachine}
|
* Tests for {@link WashingMachine}
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Bridge
|
title: Bridge
|
||||||
folder: bridge
|
folder: bridge
|
||||||
permalink: /patterns/bridge/
|
permalink: /patterns/bridge/
|
||||||
pumlid: BSR14SCm20J0Lf82BFxf1akCJ4R26ZZYzkE7zxLljJgoIVfu7S2A3v7pLRhYo3r3l9u6CPHwJjAH5uETllpZhKbejsqn86v1a-CExQwj2mdgqv8-oyev_W00
|
|
||||||
categories: Structural
|
categories: Structural
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>bridge</artifactId>
|
<artifactId>bridge</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.bridge;
|
package com.iluwatar.bridge;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -22,11 +22,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.bridge;
|
package com.iluwatar.bridge;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for hammer
|
* Tests for hammer
|
||||||
|
@ -22,11 +22,10 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.bridge;
|
package com.iluwatar.bridge;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for sword
|
* Tests for sword
|
||||||
|
@ -22,10 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.bridge;
|
package com.iluwatar.bridge;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
import org.junit.jupiter.api.Disabled;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
import static org.mockito.internal.verification.VerificationModeFactory.times;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for weapon tests
|
* Base class for weapon tests
|
||||||
@ -44,15 +45,15 @@ public abstract class WeaponTest {
|
|||||||
assertNotNull(weapon.getEnchantment());
|
assertNotNull(weapon.getEnchantment());
|
||||||
|
|
||||||
weapon.swing();
|
weapon.swing();
|
||||||
verify(enchantment, times(1)).apply();
|
verify(enchantment).apply();
|
||||||
verifyNoMoreInteractions(enchantment);
|
verifyNoMoreInteractions(enchantment);
|
||||||
|
|
||||||
weapon.wield();
|
weapon.wield();
|
||||||
verify(enchantment, times(1)).onActivate();
|
verify(enchantment).onActivate();
|
||||||
verifyNoMoreInteractions(enchantment);
|
verifyNoMoreInteractions(enchantment);
|
||||||
|
|
||||||
weapon.unwield();
|
weapon.unwield();
|
||||||
verify(enchantment, times(1)).onDeactivate();
|
verify(enchantment).onDeactivate();
|
||||||
verifyNoMoreInteractions(enchantment);
|
verifyNoMoreInteractions(enchantment);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Builder
|
title: Builder
|
||||||
folder: builder
|
folder: builder
|
||||||
permalink: /patterns/builder/
|
permalink: /patterns/builder/
|
||||||
pumlid: DSR94O0m2030LhG0mzzkC64KXs26GzlNZw_TcRLADagJwOWOlW8OFcNdE79B9wkN1ccKUdLWoGS33KwySMdalEioC89C7Jhw5zYIfNrIrFybhPUHNLu0
|
|
||||||
categories: Creational
|
categories: Creational
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>builder</artifactId>
|
<artifactId>builder</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -22,10 +22,11 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.builder;
|
package com.iluwatar.builder;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date: 12/6/15 - 11:01 PM
|
* Date: 12/6/15 - 11:01 PM
|
||||||
@ -37,17 +38,17 @@ public class HeroTest {
|
|||||||
/**
|
/**
|
||||||
* Test if we get the expected exception when trying to create a hero without a profession
|
* Test if we get the expected exception when trying to create a hero without a profession
|
||||||
*/
|
*/
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test
|
||||||
public void testMissingProfession() throws Exception {
|
public void testMissingProfession() throws Exception {
|
||||||
new Hero.Builder(null, "Sir without a job");
|
assertThrows(IllegalArgumentException.class, () -> new Hero.Builder(null, "Sir without a job"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test if we get the expected exception when trying to create a hero without a name
|
* Test if we get the expected exception when trying to create a hero without a name
|
||||||
*/
|
*/
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test
|
||||||
public void testMissingName() throws Exception {
|
public void testMissingName() throws Exception {
|
||||||
new Hero.Builder(Profession.THIEF, null);
|
assertThrows(IllegalArgumentException.class, () -> new Hero.Builder(Profession.THIEF, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Business Delegate
|
title: Business Delegate
|
||||||
folder: business-delegate
|
folder: business-delegate
|
||||||
permalink: /patterns/business-delegate/
|
permalink: /patterns/business-delegate/
|
||||||
pumlid: POl13SCm3CHMQGU8zUysgYCuBcJ5a4x9-l6_Fu84tzsgvYxf-Zg06HyYvxkqZYE_6UBrD8YXr7DGrxmPxFJZYxTTeZVR9WFY5ZGu5j2wkad4wYgD8IIe_xQaZp9pw0C0
|
|
||||||
categories: Business Tier
|
categories: Business Tier
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -1,57 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.business.delegate {
|
|
||||||
class App {
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class BusinessDelegate {
|
|
||||||
- businessService : BusinessService
|
|
||||||
- lookupService : BusinessLookup
|
|
||||||
- serviceType : ServiceType
|
|
||||||
+ BusinessDelegate()
|
|
||||||
+ doTask()
|
|
||||||
+ setLookupService(businessLookup : BusinessLookup)
|
|
||||||
+ setServiceType(serviceType : ServiceType)
|
|
||||||
}
|
|
||||||
class BusinessLookup {
|
|
||||||
- ejbService : EjbService
|
|
||||||
- jmsService : JmsService
|
|
||||||
+ BusinessLookup()
|
|
||||||
+ getBusinessService(serviceType : ServiceType) : BusinessService
|
|
||||||
+ setEjbService(ejbService : EjbService)
|
|
||||||
+ setJmsService(jmsService : JmsService)
|
|
||||||
}
|
|
||||||
interface BusinessService {
|
|
||||||
+ doProcessing() {abstract}
|
|
||||||
}
|
|
||||||
class Client {
|
|
||||||
- businessDelegate : BusinessDelegate
|
|
||||||
+ Client(businessDelegate : BusinessDelegate)
|
|
||||||
+ doTask()
|
|
||||||
}
|
|
||||||
class EjbService {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ EjbService()
|
|
||||||
+ doProcessing()
|
|
||||||
}
|
|
||||||
class JmsService {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ JmsService()
|
|
||||||
+ doProcessing()
|
|
||||||
}
|
|
||||||
enum ServiceType {
|
|
||||||
+ EJB {static}
|
|
||||||
+ JMS {static}
|
|
||||||
+ valueOf(name : String) : ServiceType {static}
|
|
||||||
+ values() : ServiceType[] {static}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BusinessLookup --> "-ejbService" EjbService
|
|
||||||
BusinessDelegate --> "-serviceType" ServiceType
|
|
||||||
Client --> "-businessDelegate" BusinessDelegate
|
|
||||||
BusinessDelegate --> "-businessService" BusinessService
|
|
||||||
BusinessDelegate --> "-lookupService" BusinessLookup
|
|
||||||
BusinessLookup --> "-jmsService" JmsService
|
|
||||||
EjbService ..|> BusinessService
|
|
||||||
JmsService ..|> BusinessService
|
|
||||||
@enduml
|
|
@ -30,13 +30,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>business-delegate</artifactId>
|
<artifactId>business-delegate</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.business.delegate;
|
package com.iluwatar.business.delegate;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -22,13 +22,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.business.delegate;
|
package com.iluwatar.business.delegate;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Business Delegate pattern adds an abstraction layer between the presentation and business
|
* The Business Delegate pattern adds an abstraction layer between the presentation and business
|
||||||
* tiers. By using the pattern we gain loose coupling between the tiers. The Business Delegate
|
* tiers. By using the pattern we gain loose coupling between the tiers. The Business Delegate
|
||||||
@ -53,7 +53,7 @@ public class BusinessDelegateTest {
|
|||||||
* This method sets up the instance variables of this test class. It is executed before the
|
* This method sets up the instance variables of this test class. It is executed before the
|
||||||
* execution of every test.
|
* execution of every test.
|
||||||
*/
|
*/
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
ejbService = spy(new EjbService());
|
ejbService = spy(new EjbService());
|
||||||
jmsService = spy(new JmsService());
|
jmsService = spy(new JmsService());
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Caching
|
title: Caching
|
||||||
folder: caching
|
folder: caching
|
||||||
permalink: /patterns/caching/
|
permalink: /patterns/caching/
|
||||||
pumlid: DSRB4OKm2030LhG0m_rrWyWaE0bc-6ZxpujxsbMKUXwSrfSMCVq7OFYKAj5oJsUZIuCr2bq3fEU3WGOdthWTx59rcnZ1fWu3_GqGKXEjm47VIzeeCqV_0m00
|
|
||||||
categories: Other
|
categories: Other
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -1,110 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.caching {
|
|
||||||
class App {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
+ useCacheAsideStategy()
|
|
||||||
+ useReadAndWriteThroughStrategy()
|
|
||||||
+ useReadThroughAndWriteAroundStrategy()
|
|
||||||
+ useReadThroughAndWriteBehindStrategy()
|
|
||||||
}
|
|
||||||
class AppManager {
|
|
||||||
- cachingPolicy : CachingPolicy {static}
|
|
||||||
- AppManager()
|
|
||||||
+ find(userId : String) : UserAccount {static}
|
|
||||||
- findAside(userId : String) : UserAccount {static}
|
|
||||||
+ initCacheCapacity(capacity : int) {static}
|
|
||||||
+ initCachingPolicy(policy : CachingPolicy) {static}
|
|
||||||
+ initDb(useMongoDb : boolean) {static}
|
|
||||||
+ printCacheContent() : String {static}
|
|
||||||
+ save(userAccount : UserAccount) {static}
|
|
||||||
- saveAside(userAccount : UserAccount) {static}
|
|
||||||
}
|
|
||||||
class CacheStore {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
~ cache : LruCache {static}
|
|
||||||
- CacheStore()
|
|
||||||
+ clearCache() {static}
|
|
||||||
+ flushCache() {static}
|
|
||||||
+ get(userId : String) : UserAccount {static}
|
|
||||||
+ initCapacity(capacity : int) {static}
|
|
||||||
+ invalidate(userId : String) {static}
|
|
||||||
+ print() : String {static}
|
|
||||||
+ readThrough(userId : String) : UserAccount {static}
|
|
||||||
+ readThroughWithWriteBackPolicy(userId : String) : UserAccount {static}
|
|
||||||
+ set(userId : String, userAccount : UserAccount) {static}
|
|
||||||
+ writeAround(userAccount : UserAccount) {static}
|
|
||||||
+ writeBehind(userAccount : UserAccount) {static}
|
|
||||||
+ writeThrough(userAccount : UserAccount) {static}
|
|
||||||
}
|
|
||||||
enum CachingPolicy {
|
|
||||||
+ AROUND {static}
|
|
||||||
+ ASIDE {static}
|
|
||||||
+ BEHIND {static}
|
|
||||||
+ THROUGH {static}
|
|
||||||
- policy : String
|
|
||||||
+ getPolicy() : String
|
|
||||||
+ valueOf(name : String) : CachingPolicy {static}
|
|
||||||
+ values() : CachingPolicy[] {static}
|
|
||||||
}
|
|
||||||
class DbManager {
|
|
||||||
- db : MongoDatabase {static}
|
|
||||||
- mongoClient : MongoClient {static}
|
|
||||||
- useMongoDB : boolean {static}
|
|
||||||
- virtualDB : Map<String, UserAccount> {static}
|
|
||||||
- DbManager()
|
|
||||||
+ connect() {static}
|
|
||||||
+ createVirtualDb() {static}
|
|
||||||
+ readFromDb(userId : String) : UserAccount {static}
|
|
||||||
+ updateDb(userAccount : UserAccount) {static}
|
|
||||||
+ upsertDb(userAccount : UserAccount) {static}
|
|
||||||
+ writeToDb(userAccount : UserAccount) {static}
|
|
||||||
}
|
|
||||||
class LruCache {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
~ cache : Map<String, Node>
|
|
||||||
~ capacity : int
|
|
||||||
~ end : Node
|
|
||||||
~ head : Node
|
|
||||||
+ LruCache(capacity : int)
|
|
||||||
+ clear()
|
|
||||||
+ contains(userId : String) : boolean
|
|
||||||
+ get(userId : String) : UserAccount
|
|
||||||
+ getCacheDataInListForm() : List<UserAccount>
|
|
||||||
+ getLruData() : UserAccount
|
|
||||||
+ invalidate(userId : String)
|
|
||||||
+ isFull() : boolean
|
|
||||||
+ remove(node : Node)
|
|
||||||
+ set(userId : String, userAccount : UserAccount)
|
|
||||||
+ setCapacity(newCapacity : int)
|
|
||||||
+ setHead(node : Node)
|
|
||||||
}
|
|
||||||
~class Node {
|
|
||||||
~ next : Node
|
|
||||||
~ previous : Node
|
|
||||||
~ userAccount : UserAccount
|
|
||||||
~ userId : String
|
|
||||||
+ Node(this$0 : String, userId : UserAccount)
|
|
||||||
}
|
|
||||||
class UserAccount {
|
|
||||||
- additionalInfo : String
|
|
||||||
- userId : String
|
|
||||||
- userName : String
|
|
||||||
+ UserAccount(userId : String, userName : String, additionalInfo : String)
|
|
||||||
+ getAdditionalInfo() : String
|
|
||||||
+ getUserId() : String
|
|
||||||
+ getUserName() : String
|
|
||||||
+ setAdditionalInfo(additionalInfo : String)
|
|
||||||
+ setUserId(userId : String)
|
|
||||||
+ setUserName(userName : String)
|
|
||||||
+ toString() : String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LruCache --> "-head" Node
|
|
||||||
Node --+ LruCache
|
|
||||||
Node --> "-previous" Node
|
|
||||||
AppManager --> "-cachingPolicy" CachingPolicy
|
|
||||||
Node --> "-userAccount" UserAccount
|
|
||||||
CacheStore --> "-cache" LruCache
|
|
||||||
@enduml
|
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>caching</artifactId>
|
<artifactId>caching</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.caching;
|
package com.iluwatar.caching;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.caching;
|
package com.iluwatar.caching;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -36,7 +36,7 @@ public class CachingTest {
|
|||||||
/**
|
/**
|
||||||
* Setup of application test includes: initializing DB connection and cache size/capacity.
|
* Setup of application test includes: initializing DB connection and cache size/capacity.
|
||||||
*/
|
*/
|
||||||
@Before
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
|
AppManager.initDb(false); // VirtualDB (instead of MongoDB) was used in running the JUnit tests
|
||||||
// to avoid Maven compilation errors. Set flag to true to run the
|
// to avoid Maven compilation errors. Set flag to true to run the
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Callback
|
title: Callback
|
||||||
folder: callback
|
folder: callback
|
||||||
permalink: /patterns/callback/
|
permalink: /patterns/callback/
|
||||||
pumlid: FSVB4S8m30N0Lg20M7UwUL4qYOciUFGXxSE9s-wp6sjjKgwF8tF6YyXnjxtdKMk5E5-MOjdu6jIrRYIStlXWsIJwRij4fhW53SGFn51TmIT9yZ-jVBHPGxy0
|
|
||||||
categories: Other
|
categories: Other
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.callback {
|
|
||||||
class App {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
interface Callback {
|
|
||||||
+ call() {abstract}
|
|
||||||
}
|
|
||||||
class LambdasApp {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ LambdasApp()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
class SimpleTask {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
+ SimpleTask()
|
|
||||||
+ execute()
|
|
||||||
}
|
|
||||||
abstract class Task {
|
|
||||||
+ Task()
|
|
||||||
+ execute() {abstract}
|
|
||||||
+ executeWith(callback : Callback)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SimpleTask --|> Task
|
|
||||||
@enduml
|
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>callback</artifactId>
|
<artifactId>callback</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.callback;
|
package com.iluwatar.callback;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.callback;
|
package com.iluwatar.callback;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a field as a counter. Every time the callback method is called increment this field. Unit
|
* Add a field as a counter. Every time the callback method is called increment this field. Unit
|
||||||
@ -47,15 +47,15 @@ public class CallbackTest {
|
|||||||
|
|
||||||
Task task = new SimpleTask();
|
Task task = new SimpleTask();
|
||||||
|
|
||||||
assertEquals("Initial calling count of 0", new Integer(0), callingCount);
|
assertEquals(new Integer(0), callingCount, "Initial calling count of 0");
|
||||||
|
|
||||||
task.executeWith(callback);
|
task.executeWith(callback);
|
||||||
|
|
||||||
assertEquals("Callback called once", new Integer(1), callingCount);
|
assertEquals(new Integer(1), callingCount, "Callback called once");
|
||||||
|
|
||||||
task.executeWith(callback);
|
task.executeWith(callback);
|
||||||
|
|
||||||
assertEquals("Callback called twice", new Integer(2), callingCount);
|
assertEquals(new Integer(2), callingCount, "Callback called twice");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,15 +65,15 @@ public class CallbackTest {
|
|||||||
|
|
||||||
Task task = new SimpleTask();
|
Task task = new SimpleTask();
|
||||||
|
|
||||||
assertEquals("Initial calling count of 0", new Integer(0), callingCount);
|
assertEquals(new Integer(0), callingCount, "Initial calling count of 0");
|
||||||
|
|
||||||
task.executeWith(callback);
|
task.executeWith(callback);
|
||||||
|
|
||||||
assertEquals("Callback called once", new Integer(1), callingCount);
|
assertEquals(new Integer(1), callingCount, "Callback called once");
|
||||||
|
|
||||||
task.executeWith(callback);
|
task.executeWith(callback);
|
||||||
|
|
||||||
assertEquals("Callback called twice", new Integer(2), callingCount);
|
assertEquals(new Integer(2), callingCount, "Callback called twice");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Chain of responsibility
|
title: Chain of responsibility
|
||||||
folder: chain
|
folder: chain
|
||||||
permalink: /patterns/chain/
|
permalink: /patterns/chain/
|
||||||
pumlid: 9SR13SCm20NGLTe1OkxTXX0KKzd4Wa-pVYlrdTxJN4OTMZ4U7LZv8Wg-ssdejLTgoELGHvDhaesw6HpqvWzlXwQTlYq6D3nfSlv2qjcS5F9VgvXjrHnV
|
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>chain</artifactId>
|
<artifactId>chain</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.chain;
|
package com.iluwatar.chain;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.chain;
|
package com.iluwatar.chain;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Date: 12/6/15 - 9:29 PM
|
* Date: 12/6/15 - 9:29 PM
|
||||||
@ -49,8 +49,8 @@ public class OrcKingTest {
|
|||||||
for (final Request request : REQUESTS) {
|
for (final Request request : REQUESTS) {
|
||||||
king.makeRequest(request);
|
king.makeRequest(request);
|
||||||
assertTrue(
|
assertTrue(
|
||||||
"Expected all requests from King to be handled, but [" + request + "] was not!",
|
request.isHandled(),
|
||||||
request.isHandled()
|
"Expected all requests from King to be handled, but [" + request + "] was not!"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,9 +85,7 @@
|
|||||||
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
value="LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, LITERAL_IF, LITERAL_ELSE, LITERAL_SWITCH"/>
|
||||||
</module>
|
</module>
|
||||||
<module name="NeedBraces"/>
|
<module name="NeedBraces"/>
|
||||||
<module name="LeftCurly">
|
<module name="LeftCurly"/>
|
||||||
<property name="maxLineLength" value="120"/>
|
|
||||||
</module>
|
|
||||||
<module name="RightCurly"/>
|
<module name="RightCurly"/>
|
||||||
<module name="RightCurly">
|
<module name="RightCurly">
|
||||||
<property name="option" value="alone"/>
|
<property name="option" value="alone"/>
|
||||||
@ -181,7 +179,7 @@
|
|||||||
<property name="allowMissingThrowsTags" value="true"/>
|
<property name="allowMissingThrowsTags" value="true"/>
|
||||||
<property name="allowMissingReturnTag" value="true"/>
|
<property name="allowMissingReturnTag" value="true"/>
|
||||||
<property name="minLineCount" value="2"/>
|
<property name="minLineCount" value="2"/>
|
||||||
<property name="allowedAnnotations" value="Override, Test, Before, After, Parameters, Given, When, BeforeClass, AfterClass, Parameterized"/>
|
<property name="allowedAnnotations" value="Override, Test, Before, After, Parameters, Given, When, BeforeClass, AfterClass, Parameterized, ParameterizedTest, BeforeAll, BeforeEach"/>
|
||||||
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
<property name="allowThrowsTagsForSubclasses" value="true"/>
|
||||||
</module>
|
</module>
|
||||||
<module name="JavadocType">
|
<module name="JavadocType">
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Command
|
title: Command
|
||||||
folder: command
|
folder: command
|
||||||
permalink: /patterns/command/
|
permalink: /patterns/command/
|
||||||
pumlid: DSgn4OCm30NGLM00h3xR25i7vYpXaxx2-g59zugtTgiZcwIFvGHcV8YSdt9qdBbdYDVR88PIRwK-yc6mqyLVtff4FsoR38XRa7Aye3SgMoD1_RkaQvcfumS0
|
|
||||||
categories: Behavioral
|
categories: Behavioral
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
@ -37,6 +36,10 @@ Use the Command pattern when you want to
|
|||||||
* implement callback functionality
|
* implement callback functionality
|
||||||
* implement the undo functionality
|
* implement the undo functionality
|
||||||
|
|
||||||
|
## Presentations
|
||||||
|
|
||||||
|
* [Command Pattern](etc/presentation.html)
|
||||||
|
|
||||||
## Real world examples
|
## Real world examples
|
||||||
|
|
||||||
* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
|
* [java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
@startuml
|
|
||||||
package com.iluwatar.command {
|
|
||||||
class App {
|
|
||||||
+ App()
|
|
||||||
+ main(args : String[]) {static}
|
|
||||||
}
|
|
||||||
abstract class Command {
|
|
||||||
+ Command()
|
|
||||||
+ execute(Target) {abstract}
|
|
||||||
+ redo() {abstract}
|
|
||||||
+ toString() : String {abstract}
|
|
||||||
+ undo() {abstract}
|
|
||||||
}
|
|
||||||
class Goblin {
|
|
||||||
+ Goblin()
|
|
||||||
+ toString() : String
|
|
||||||
}
|
|
||||||
class InvisibilitySpell {
|
|
||||||
- target : Target
|
|
||||||
+ InvisibilitySpell()
|
|
||||||
+ execute(target : Target)
|
|
||||||
+ redo()
|
|
||||||
+ toString() : String
|
|
||||||
+ undo()
|
|
||||||
}
|
|
||||||
class ShrinkSpell {
|
|
||||||
- oldSize : Size
|
|
||||||
- target : Target
|
|
||||||
+ ShrinkSpell()
|
|
||||||
+ execute(target : Target)
|
|
||||||
+ redo()
|
|
||||||
+ toString() : String
|
|
||||||
+ undo()
|
|
||||||
}
|
|
||||||
enum Size {
|
|
||||||
+ LARGE {static}
|
|
||||||
+ NORMAL {static}
|
|
||||||
+ SMALL {static}
|
|
||||||
+ UNDEFINED {static}
|
|
||||||
- title : String
|
|
||||||
+ toString() : String
|
|
||||||
+ valueOf(name : String) : Size {static}
|
|
||||||
+ values() : Size[] {static}
|
|
||||||
}
|
|
||||||
abstract class Target {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
- size : Size
|
|
||||||
- visibility : Visibility
|
|
||||||
+ Target()
|
|
||||||
+ getSize() : Size
|
|
||||||
+ getVisibility() : Visibility
|
|
||||||
+ printStatus()
|
|
||||||
+ setSize(size : Size)
|
|
||||||
+ setVisibility(visibility : Visibility)
|
|
||||||
+ toString() : String {abstract}
|
|
||||||
}
|
|
||||||
enum Visibility {
|
|
||||||
+ INVISIBLE {static}
|
|
||||||
+ UNDEFINED {static}
|
|
||||||
+ VISIBLE {static}
|
|
||||||
- title : String
|
|
||||||
+ toString() : String
|
|
||||||
+ valueOf(name : String) : Visibility {static}
|
|
||||||
+ values() : Visibility[] {static}
|
|
||||||
}
|
|
||||||
class Wizard {
|
|
||||||
- LOGGER : Logger {static}
|
|
||||||
- redoStack : Deque<Command>
|
|
||||||
- undoStack : Deque<Command>
|
|
||||||
+ Wizard()
|
|
||||||
+ castSpell(command : Command, target : Target)
|
|
||||||
+ redoLastSpell()
|
|
||||||
+ toString() : String
|
|
||||||
+ undoLastSpell()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Target --> "-size" Size
|
|
||||||
Wizard --> "-undoStack" Command
|
|
||||||
ShrinkSpell --> "-oldSize" Size
|
|
||||||
InvisibilitySpell --> "-target" Target
|
|
||||||
ShrinkSpell --> "-target" Target
|
|
||||||
Target --> "-visibility" Visibility
|
|
||||||
Goblin --|> Target
|
|
||||||
InvisibilitySpell --|> Command
|
|
||||||
ShrinkSpell --|> Command
|
|
||||||
@enduml
|
|
BIN
command/etc/diagram.png
Normal file
BIN
command/etc/diagram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
243
command/etc/presentation.html
Normal file
243
command/etc/presentation.html
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
The MIT License
|
||||||
|
Copyright (c) 2017 Rodolfo Forte
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Design Patterns - Command Presentation</title>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<style>
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Yanone+Kaffeesatz);
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Droid+Serif:400,700,400italic);
|
||||||
|
@import url(https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700,400italic);
|
||||||
|
|
||||||
|
body { font-family: 'Droid Serif'; }
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-family: 'Yanone Kaffeesatz';
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.remark-code, .remark-inline-code { font-family: 'Ubuntu Mono'; }
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
border-left: 0.3em solid rgba(0,0,0,0.5);
|
||||||
|
padding: 0 15px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width:100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<textarea id="source">
|
||||||
|
|
||||||
|
class: center, middle
|
||||||
|
|
||||||
|
# Command
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Also known as
|
||||||
|
|
||||||
|
* Action, Transaction
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Intent
|
||||||
|
|
||||||
|
* Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Explanation
|
||||||
|
|
||||||
|
* [Wikipedia](https://en.wikipedia.org/wiki/Command_pattern) says:
|
||||||
|
> In object-oriented programming, 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.
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
* In plain words:
|
||||||
|
|
||||||
|
* Enable the construction of components that are able to delegate, sequence or execute method calls at a time of their choosing;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Explanation
|
||||||
|
|
||||||
|
Four terms always associated with the pattern:
|
||||||
|
|
||||||
|
* Command
|
||||||
|
* Object that knows about the receiver and invokes a method of the receiver;
|
||||||
|
|
||||||
|
* Receiver
|
||||||
|
* Object that does the work;
|
||||||
|
|
||||||
|
* Invoker
|
||||||
|
* Knows how to execute a command, and optionally does the bookkeeping about the command execution;
|
||||||
|
|
||||||
|
* Client
|
||||||
|
* Decides which commands to execute at which points, passing the command object to the invoker object;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Example
|
||||||
|
|
||||||
|
In our example, a Wizard can cast spells on targets.
|
||||||
|
|
||||||
|
* Spell will be the command (implements the Command interface);
|
||||||
|
* Goblin (a Target object) will be the receiver;
|
||||||
|
* Wizard will be the invoker;
|
||||||
|
* App will be the client;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
//App.java
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Wizard wizard = new Wizard();
|
||||||
|
Goblin goblin = new Goblin();
|
||||||
|
goblin.printStatus(); //Goblin, [size=normal] [visibility=visible]
|
||||||
|
|
||||||
|
wizard.castSpell(new ShrinkSpell(), goblin);
|
||||||
|
wizard.castSpell(new InvisibilitySpell(), goblin);
|
||||||
|
|
||||||
|
goblin.printStatus(); //Goblin, [size=small] [visibility=invisible]
|
||||||
|
|
||||||
|
wizard.undoLastSpell();
|
||||||
|
|
||||||
|
goblin.printStatus(); //Goblin, [size=small] [visibility=visible]
|
||||||
|
|
||||||
|
wizard.redoLastSpell();
|
||||||
|
goblin.printStatus(); //Goblin, [size=small] [visibility=invisible]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Diagram
|
||||||
|
|
||||||
|
.center[]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Applicability
|
||||||
|
|
||||||
|
Use the Command pattern when you want to:
|
||||||
|
|
||||||
|
* Parameterize objects by an action to perform;
|
||||||
|
* You can express such parameterization in a procedural language with a callback function, that is, a function that's registered somewhere to be called at a later point;
|
||||||
|
|
||||||
|
* Commands are an object-oriented replacement for callbacks;
|
||||||
|
|
||||||
|
<br />
|
||||||
|
|
||||||
|
* Specify, queue, and execute requests at different times;
|
||||||
|
* A Command object can have a lifetime independent of the original request;
|
||||||
|
|
||||||
|
* If the receiver of a request can be represented in an address space-independent way, then you can transfer a command object for the request to a different process and fulfill the request there;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Applicability
|
||||||
|
|
||||||
|
Use the Command pattern when you want to:
|
||||||
|
|
||||||
|
* Support undo;
|
||||||
|
* The Command's execute() operation can store state for reversing its effects in the command itself;
|
||||||
|
|
||||||
|
* The Command interface must have an added unexecute() operation that reverses the effects of a previous call to execute;
|
||||||
|
|
||||||
|
* Executed commands are stored in a history list;
|
||||||
|
|
||||||
|
* Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling unexecute() and execute(), respectively;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Applicability
|
||||||
|
|
||||||
|
Use the Command pattern when you want to:
|
||||||
|
|
||||||
|
* Support logging changes so that they can be reapplied in case of a system crash;
|
||||||
|
* By augmenting the Command interface with load() and store() operations, you can keep a persistent log of changes;
|
||||||
|
|
||||||
|
* Recovering from a crash involves reloading logged commands from disk and re-executing them with the execute operation;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Applicability
|
||||||
|
|
||||||
|
Use the Command pattern when you want to:
|
||||||
|
|
||||||
|
* Structure a system around high-level operations build on primitive operations;
|
||||||
|
* Such a structure is common in information systems that support transactions;
|
||||||
|
|
||||||
|
* A transaction encapsulates a set of changes to data;
|
||||||
|
|
||||||
|
* The Command pattern offers a way to model transactions;
|
||||||
|
|
||||||
|
* Commands have a common interface, letting you invoke all transactions the same way;
|
||||||
|
|
||||||
|
* The pattern also makes it easy to extend the system with new transactions
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Use Cases
|
||||||
|
|
||||||
|
* To keep a history of requests;
|
||||||
|
|
||||||
|
* Implement callback functionality;
|
||||||
|
|
||||||
|
* Implement the undo functionality;
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Real world examples
|
||||||
|
|
||||||
|
[java.lang.Runnable](http://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html)
|
||||||
|
|
||||||
|
[Netflix Hystrix](https://github.com/Netflix/Hystrix/wiki)
|
||||||
|
|
||||||
|
[javax.swing.Action](http://docs.oracle.com/javase/8/docs/api/javax/swing/Action.html)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
|
||||||
|
* [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tutorials
|
||||||
|
|
||||||
|
* Source code http://java-design-patterns.com/patterns/command/
|
||||||
|
|
||||||
|
</textarea>
|
||||||
|
<script src="https://gnab.github.io/remark/downloads/remark-latest.min.js">
|
||||||
|
</script>
|
||||||
|
<script>
|
||||||
|
var slideshow = remark.create();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -29,18 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>command</artifactId>
|
<artifactId>command</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mockito</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>mockito-core</artifactId>
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
@ -29,7 +29,7 @@ package com.iluwatar.command;
|
|||||||
*/
|
*/
|
||||||
public enum Size {
|
public enum Size {
|
||||||
|
|
||||||
SMALL("small"), NORMAL("normal"), LARGE("large"), UNDEFINED("");
|
SMALL("small"), NORMAL("normal");
|
||||||
|
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ package com.iluwatar.command;
|
|||||||
*/
|
*/
|
||||||
public enum Visibility {
|
public enum Visibility {
|
||||||
|
|
||||||
VISIBLE("visible"), INVISIBLE("invisible"), UNDEFINED("");
|
VISIBLE("visible"), INVISIBLE("invisible");
|
||||||
|
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
@ -40,7 +40,9 @@ public class Wizard {
|
|||||||
private Deque<Command> undoStack = new LinkedList<>();
|
private Deque<Command> undoStack = new LinkedList<>();
|
||||||
private Deque<Command> redoStack = new LinkedList<>();
|
private Deque<Command> redoStack = new LinkedList<>();
|
||||||
|
|
||||||
public Wizard() {}
|
public Wizard() {
|
||||||
|
// comment to ignore sonar issue: LEVEL critical
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cast spell
|
* Cast spell
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.command;
|
package com.iluwatar.command;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
*/
|
*/
|
||||||
package com.iluwatar.command;
|
package com.iluwatar.command;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.junit.Test;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Command pattern is a behavioral design pattern in which an object is used to encapsulate all
|
* The Command pattern is a behavioral design pattern in which an object is used to encapsulate all
|
||||||
@ -81,13 +81,13 @@ public class CommandTest {
|
|||||||
* @param goblin a goblin object whose state is to be verified against other parameters
|
* @param goblin a goblin object whose state is to be verified against other parameters
|
||||||
* @param expectedName expectedName of the goblin
|
* @param expectedName expectedName of the goblin
|
||||||
* @param expectedSize expected size of the goblin
|
* @param expectedSize expected size of the goblin
|
||||||
* @param expectedVisibilty exepcted visibility of the goblin
|
* @param expectedVisibility expected visibility of the goblin
|
||||||
*/
|
*/
|
||||||
private void verifyGoblin(Goblin goblin, String expectedName, Size expectedSize,
|
private void verifyGoblin(Goblin goblin, String expectedName, Size expectedSize,
|
||||||
Visibility expectedVisibilty) {
|
Visibility expectedVisibility) {
|
||||||
assertEquals("Goblin's name must be same as expectedName", expectedName, goblin.toString());
|
assertEquals(expectedName, goblin.toString(), "Goblin's name must be same as expectedName");
|
||||||
assertEquals("Goblin's size must be same as expectedSize", expectedSize, goblin.getSize());
|
assertEquals(expectedSize, goblin.getSize(), "Goblin's size must be same as expectedSize");
|
||||||
assertEquals("Goblin's visibility must be same as expectedVisibility", expectedVisibilty,
|
assertEquals(expectedVisibility, goblin.getVisibility(),
|
||||||
goblin.getVisibility());
|
"Goblin's visibility must be same as expectedVisibility");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ layout: pattern
|
|||||||
title: Composite
|
title: Composite
|
||||||
folder: composite
|
folder: composite
|
||||||
permalink: /patterns/composite/
|
permalink: /patterns/composite/
|
||||||
pumlid: HSf13eCm30NHgy01YFUzZGaM62LEP7-NwvTTT_EaMTLgoqFIst81Cpv4payv5LVk6U9r6CHGwkYaBHy6EztyvUsGqDEsoO2u1NMED-WTvmY5aA3-LT9xcTdR3m00
|
|
||||||
categories: Structural
|
categories: Structural
|
||||||
tags:
|
tags:
|
||||||
- Java
|
- Java
|
||||||
|
@ -29,13 +29,18 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.iluwatar</groupId>
|
<groupId>com.iluwatar</groupId>
|
||||||
<artifactId>java-design-patterns</artifactId>
|
<artifactId>java-design-patterns</artifactId>
|
||||||
<version>1.17.0-SNAPSHOT</version>
|
<version>1.19.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>composite</artifactId>
|
<artifactId>composite</artifactId>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>org.junit.jupiter</groupId>
|
||||||
<artifactId>junit</artifactId>
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user