diff --git a/.circleci/config.yml b/.circleci/config.yml index dad7997a8699..a847c8d007e5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,34 +21,34 @@ # THE SOFTWARE. # -version: 2 +#version: 2 -jobs: - sonar-pr: - docker: - - image: cimg/openjdk:11.0-node - steps: - - checkout - - restore_cache: - key: jdp-sonar-pr-{{ checksum "pom.xml" }} - - run: | - sudo apt-get update - sudo apt-get install -y openjdk-11-jdk xvfb - if [ -n "${CIRCLE_PR_NUMBER}" ]; then - MAVEN_OPTS="-Xmx3000m" xvfb-run ./mvnw -B clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \ - -Dsonar.pullrequest.key=${CIRCLE_PR_NUMBER} \ - -Dsonar.pullrequest.branch=${CIRCLE_BRANCH} \ - -Dsonar.pullrequest.base=master - else - echo "No Sonar PR analysis as this is not a pull request" - fi - - save_cache: - key: jdp-sonar-pr-{{ checksum "pom.xml" }} - paths: - - ~/.m2 +#jobs: + #sonar-pr: + #docker: + #- image: cimg/openjdk:11.0-node + #steps: + #- checkout + #- restore_cache: + #key: jdp-sonar-pr-{{ checksum "pom.xml" }} + #- run: | + #sudo apt-get update + #sudo apt-get install -y openjdk-11-jdk xvfb + #if [ -n "${CIRCLE_PR_NUMBER}" ]; then + #MAVEN_OPTS="-Xmx3000m" xvfb-run ./mvnw -B clean verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar \ + #-Dsonar.pullrequest.key=${CIRCLE_PR_NUMBER} \ + #-Dsonar.pullrequest.branch=${CIRCLE_BRANCH} \ + #-Dsonar.pullrequest.base=master + #else + #echo "No Sonar PR analysis as this is not a pull request" + #fi + #- save_cache: + #key: jdp-sonar-pr-{{ checksum "pom.xml" }} + #paths: + #- ~/.m2 -workflows: - version: 2 - all: - jobs: - - sonar-pr +#workflows: + #version: 2 + #all: + #jobs: + #- sonar-pr diff --git a/etc/Bass-Drum-1.aif b/etc/Bass-Drum-1.aif new file mode 100644 index 000000000000..f1eae69db029 Binary files /dev/null and b/etc/Bass-Drum-1.aif differ diff --git a/etc/Bass-Drum-1.wav b/etc/Bass-Drum-1.wav new file mode 100644 index 000000000000..566181d942aa Binary files /dev/null and b/etc/Bass-Drum-1.wav differ diff --git a/etc/Claim-Check-Pattern.png b/etc/Claim-Check-Pattern.png new file mode 100644 index 000000000000..a2d8040afaf6 Binary files /dev/null and b/etc/Claim-Check-Pattern.png differ diff --git a/etc/Closed-Hi-Hat-1.aif b/etc/Closed-Hi-Hat-1.aif new file mode 100644 index 000000000000..ac248e4f4a57 Binary files /dev/null and b/etc/Closed-Hi-Hat-1.aif differ diff --git a/etc/Closed-Hi-Hat-1.wav b/etc/Closed-Hi-Hat-1.wav new file mode 100644 index 000000000000..2320db510273 Binary files /dev/null and b/etc/Closed-Hi-Hat-1.wav differ diff --git a/etc/Converter.ucls b/etc/Converter.ucls new file mode 100644 index 000000000000..368657430e2b --- /dev/null +++ b/etc/Converter.ucls @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/IdentityMap.png b/etc/IdentityMap.png new file mode 100644 index 000000000000..1bac10ebf294 Binary files /dev/null and b/etc/IdentityMap.png differ diff --git a/etc/MarkerDiagram.png b/etc/MarkerDiagram.png new file mode 100644 index 000000000000..6ed4f9c56780 Binary files /dev/null and b/etc/MarkerDiagram.png differ diff --git a/etc/MarkerDiagram.ucls b/etc/MarkerDiagram.ucls new file mode 100644 index 000000000000..0f8376e40e23 --- /dev/null +++ b/etc/MarkerDiagram.ucls @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/MonoState.ucls b/etc/MonoState.ucls new file mode 100644 index 000000000000..76b48ad0fa2a --- /dev/null +++ b/etc/MonoState.ucls @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/ServiceDiagram.png b/etc/ServiceDiagram.png new file mode 100644 index 000000000000..885320a4d901 Binary files /dev/null and b/etc/ServiceDiagram.png differ diff --git a/etc/StateDiagram.png b/etc/StateDiagram.png new file mode 100644 index 000000000000..38485526d342 Binary files /dev/null and b/etc/StateDiagram.png differ diff --git a/etc/abstract-document.png b/etc/abstract-document.png new file mode 100644 index 000000000000..6bc0b29a4e77 Binary files /dev/null and b/etc/abstract-document.png differ diff --git a/etc/abstract-document.ucls b/etc/abstract-document.ucls new file mode 100644 index 000000000000..f555394d04c2 --- /dev/null +++ b/etc/abstract-document.ucls @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/abstract-document.urm.puml b/etc/abstract-document.urm.puml new file mode 100644 index 000000000000..9940dc2cfd05 --- /dev/null +++ b/etc/abstract-document.urm.puml @@ -0,0 +1,65 @@ +@startuml +package com.iluwatar.abstractdocument.domain.enums { + enum Property { + + MODEL {static} + + PARTS {static} + + PRICE {static} + + TYPE {static} + + valueOf(name : String) : Property {static} + + values() : Property[] {static} + } +} +package com.iluwatar.abstractdocument.domain { + class Car { + + Car(properties : Map) + } + interface HasModel { + + getModel() : Optional + } + interface HasParts { + + getParts() : Stream + } + interface HasPrice { + + getPrice() : Optional + } + interface HasType { + + getType() : Optional + } + class Part { + + Part(properties : Map) + } +} +package com.iluwatar.abstractdocument { + abstract class AbstractDocument { + - properties : Map + # AbstractDocument(properties : Map) + + children(key : String, constructor : Function, T>) : Stream + + 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, T>) : Stream {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 \ No newline at end of file diff --git a/etc/abstract-factory.urm.png b/etc/abstract-factory.urm.png new file mode 100644 index 000000000000..836858a2c652 Binary files /dev/null and b/etc/abstract-factory.urm.png differ diff --git a/etc/abstract-factory.urm.puml b/etc/abstract-factory.urm.puml new file mode 100644 index 000000000000..999091ef54f6 --- /dev/null +++ b/etc/abstract-factory.urm.puml @@ -0,0 +1,101 @@ +@startuml +package com.iluwatar.abstractfactory { + class App { + - LOGGER : Logger {static} + - army : Army + - castle : Castle + - king : King + + App() + + createKingdom(factory : KingdomFactory) + + getArmy() : Army + ~ getArmy(factory : KingdomFactory) : Army + + getCastle() : Castle + ~ getCastle(factory : KingdomFactory) : Castle + + getKing() : King + ~ getKing(factory : KingdomFactory) : King + + main(args : String[]) {static} + - setArmy(army : Army) + - setCastle(castle : Castle) + - setKing(king : King) + } + class FactoryMaker { + + FactoryMaker() + + makeFactory(type : KingdomType) : KingdomFactory {static} + } + enum KingdomType { + + ELF {static} + + ORC {static} + + valueOf(name : String) : KingdomType {static} + + values() : KingdomType[] {static} + } + interface Army { + + getDescription() : String {abstract} + } + interface Castle { + + getDescription() : String {abstract} + } + class ElfArmy { + ~ DESCRIPTION : String {static} + + ElfArmy() + + getDescription() : String + } + class ElfCastle { + ~ DESCRIPTION : String {static} + + ElfCastle() + + getDescription() : String + } + class ElfKing { + ~ DESCRIPTION : String {static} + + ElfKing() + + getDescription() : String + } + class ElfKingdomFactory { + + ElfKingdomFactory() + + createArmy() : Army + + createCastle() : Castle + + createKing() : King + } + interface King { + + getDescription() : String {abstract} + } + interface KingdomFactory { + + createArmy() : Army {abstract} + + createCastle() : Castle {abstract} + + createKing() : King {abstract} + } + class OrcArmy { + ~ DESCRIPTION : String {static} + + OrcArmy() + + getDescription() : String + } + class OrcCastle { + ~ DESCRIPTION : String {static} + + OrcCastle() + + getDescription() : String + } + class OrcKing { + ~ DESCRIPTION : String {static} + + OrcKing() + + getDescription() : String + } + class OrcKingdomFactory { + + OrcKingdomFactory() + + createArmy() : Army + + createCastle() : Castle + + createKing() : King + } +} +KingdomType ..+ FactoryMaker +App --> "-castle" Castle +FactoryMaker ..+ App +App --> "-king" King +App --> "-army" Army +ElfArmy ..|> Army +ElfCastle ..|> Castle +ElfKing ..|> King +ElfKingdomFactory ..|> KingdomFactory +OrcArmy ..|> Army +OrcCastle ..|> Castle +OrcKing ..|> King +OrcKingdomFactory ..|> KingdomFactory +@enduml \ No newline at end of file diff --git a/etc/active-object.urm.PNG b/etc/active-object.urm.PNG new file mode 100644 index 000000000000..c14f66144ee2 Binary files /dev/null and b/etc/active-object.urm.PNG differ diff --git a/etc/active-object.urm.png b/etc/active-object.urm.png new file mode 100644 index 000000000000..c14f66144ee2 Binary files /dev/null and b/etc/active-object.urm.png differ diff --git a/etc/active-object.urm.puml b/etc/active-object.urm.puml new file mode 100644 index 000000000000..3fc3c8e1e921 --- /dev/null +++ b/etc/active-object.urm.puml @@ -0,0 +1,25 @@ +@startuml +package com.iluwatar.activeobject { + abstract class ActiveCreature { + - logger : Logger + - name : String + - requests : BlockingQueue + - thread : Thread + + ActiveCreature(name : String) + + eat() + + name() : String + + roam() + } + class App { + - creatures : Integer + - logger : Logger + + App() + + main(args : String[]) {static} + + run() + } + class Orc { + + Orc(name : String) + } +} +Orc --|> ActiveCreature +@enduml \ No newline at end of file diff --git a/etc/acyclic-visitor.png b/etc/acyclic-visitor.png new file mode 100644 index 000000000000..7b4df13d80f8 Binary files /dev/null and b/etc/acyclic-visitor.png differ diff --git a/etc/acyclic-visitor.urm.puml b/etc/acyclic-visitor.urm.puml new file mode 100644 index 000000000000..e67bbde4407c --- /dev/null +++ b/etc/acyclic-visitor.urm.puml @@ -0,0 +1,53 @@ +@startuml +package com.iluwatar.acyclicvisitor { + interface AllModemVisitor { + } + class App { + + App() + + main(args : String[]) {static} + } + class ConfigureForDosVisitor { + - LOGGER : Logger {static} + + ConfigureForDosVisitor() + + visit(hayes : Hayes) + + visit(zoom : Zoom) + } + class ConfigureForUnixVisitor { + - LOGGER : Logger {static} + + ConfigureForUnixVisitor() + + visit(zoom : Zoom) + } + class Hayes { + - LOGGER : Logger {static} + + Hayes() + + accept(modemVisitor : ModemVisitor) + + toString() : String + } + interface HayesVisitor { + + visit(Hayes) {abstract} + } + abstract class Modem { + + Modem() + + accept(ModemVisitor) {abstract} + } + interface ModemVisitor { + } + class Zoom { + - LOGGER : Logger {static} + + Zoom() + + accept(modemVisitor : ModemVisitor) + + toString() : String + } + interface ZoomVisitor { + + visit(Zoom) {abstract} + } +} +AllModemVisitor --|> ZoomVisitor +AllModemVisitor --|> HayesVisitor +ConfigureForDosVisitor ..|> AllModemVisitor +ConfigureForUnixVisitor ..|> ZoomVisitor +Hayes --|> Modem +HayesVisitor --|> ModemVisitor +Zoom --|> Modem +ZoomVisitor --|> ModemVisitor +@enduml \ No newline at end of file diff --git a/etc/adapter.urm.png b/etc/adapter.urm.png new file mode 100644 index 000000000000..341ad67699d9 Binary files /dev/null and b/etc/adapter.urm.png differ diff --git a/etc/adapter.urm.puml b/etc/adapter.urm.puml new file mode 100644 index 000000000000..1277cbb87125 --- /dev/null +++ b/etc/adapter.urm.puml @@ -0,0 +1,31 @@ +@startuml +package com.iluwatar.adapter { + class App { + - App() + + main(args : String[]) {static} + } + class Captain { + - rowingBoat : RowingBoat + + Captain() + + Captain(boat : RowingBoat) + ~ row() + ~ setRowingBoat(boat : RowingBoat) + } + ~class FishingBoat { + - LOGGER : Logger {static} + ~ FishingBoat() + ~ sail() + } + class FishingBoatAdapter { + - boat : FishingBoat + + FishingBoatAdapter() + + row() + } + interface RowingBoat { + + row() {abstract} + } +} +FishingBoatAdapter --> "-boat" FishingBoat +Captain --> "-rowingBoat" RowingBoat +FishingBoatAdapter ..|> RowingBoat +@enduml \ No newline at end of file diff --git a/etc/aggregator-microservices.urm.puml b/etc/aggregator-microservices.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/etc/aggregator-microservices.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/etc/aggregator.gif b/etc/aggregator.gif new file mode 100644 index 000000000000..b06cdfb0c920 Binary files /dev/null and b/etc/aggregator.gif differ diff --git a/etc/ambassador.urm.png b/etc/ambassador.urm.png new file mode 100644 index 000000000000..9b50a02ad356 Binary files /dev/null and b/etc/ambassador.urm.png differ diff --git a/etc/ambassador.urm.puml b/etc/ambassador.urm.puml new file mode 100644 index 000000000000..517b0bf51d07 --- /dev/null +++ b/etc/ambassador.urm.puml @@ -0,0 +1,47 @@ +@startuml +package com.iluwatar.ambassador.util { + interface RandomProvider { + + random() : double {abstract} + } +} +package com.iluwatar.ambassador { + class App { + + App() + + main(args : String[]) {static} + } + class Client { + - LOGGER : Logger {static} + - serviceAmbassador : ServiceAmbassador + + Client() + ~ useService(value : int) : long + } + class RemoteService { + - LOGGER : Logger {static} + - THRESHOLD : int {static} + - randomProvider : RandomProvider + - service : RemoteService {static} + - RemoteService() + ~ RemoteService(randomProvider : RandomProvider) + + doRemoteFunction(value : int) : long + ~ getRemoteService() : RemoteService {static} + } + ~interface RemoteServiceInterface { + + FAILURE : int {static} + + doRemoteFunction(int) : long {abstract} + } + class ServiceAmbassador { + - DELAY_MS : int {static} + - LOGGER : Logger {static} + - RETRIES : int {static} + ~ ServiceAmbassador() + - checkLatency(value : int) : long + + doRemoteFunction(value : int) : long + - safeCall(value : int) : long + } +} +RemoteService --> "-service" RemoteService +Client --> "-serviceAmbassador" ServiceAmbassador +RemoteService --> "-randomProvider" RandomProvider +RemoteService ..|> RemoteServiceInterface +ServiceAmbassador ..|> RemoteServiceInterface +@enduml \ No newline at end of file diff --git a/etc/api-gateway.png b/etc/api-gateway.png new file mode 100644 index 000000000000..bb3ec2e2e1a8 Binary files /dev/null and b/etc/api-gateway.png differ diff --git a/etc/api-gateway.ucls b/etc/api-gateway.ucls new file mode 100644 index 000000000000..4a74c2108b22 --- /dev/null +++ b/etc/api-gateway.ucls @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/api-gateway.urm.puml b/etc/api-gateway.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/etc/api-gateway.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/etc/arrange-act-assert.urm.puml b/etc/arrange-act-assert.urm.puml new file mode 100644 index 000000000000..4b22d2a4e4bb --- /dev/null +++ b/etc/arrange-act-assert.urm.puml @@ -0,0 +1,11 @@ +@startuml +package com.iluwatar.arrangeactassert { + class Cash { + - amount : int + ~ Cash(amount : int) + ~ count() : int + ~ minus(subtrahend : int) : boolean + ~ plus(addend : int) + } +} +@enduml \ No newline at end of file diff --git a/etc/async-method-invocation.png b/etc/async-method-invocation.png new file mode 100644 index 000000000000..764895d7a217 Binary files /dev/null and b/etc/async-method-invocation.png differ diff --git a/etc/async-method-invocation.ucls b/etc/async-method-invocation.ucls new file mode 100644 index 000000000000..f2e189eaeae0 --- /dev/null +++ b/etc/async-method-invocation.ucls @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/async-method-invocation.urm.puml b/etc/async-method-invocation.urm.puml new file mode 100644 index 000000000000..6f5d0b27f9d4 --- /dev/null +++ b/etc/async-method-invocation.urm.puml @@ -0,0 +1,51 @@ +@startuml +package com.iluwatar.async.method.invocation { + class App { + - LOGGER : Logger {static} + + App() + - callback(name : String) : AsyncCallback {static} + - lazyval(value : T, delayMillis : long) : Callable {static} + - log(msg : String) {static} + + main(args : String[]) {static} + } + interface AsyncCallback { + + onComplete(T, Optional) {abstract} + } + interface AsyncExecutor { + + endProcess(AsyncResult) : T {abstract} + + startProcess(Callable) : AsyncResult {abstract} + + startProcess(Callable, AsyncCallback) : AsyncResult {abstract} + } + interface AsyncResult { + + await() {abstract} + + getValue() : T {abstract} + + isCompleted() : boolean {abstract} + } + class ThreadAsyncExecutor { + - idx : AtomicInteger + + ThreadAsyncExecutor() + + endProcess(asyncResult : AsyncResult) : T + + startProcess(task : Callable) : AsyncResult + + startProcess(task : Callable, callback : AsyncCallback) : AsyncResult + } + -class CompletableResult { + ~ COMPLETED : int {static} + ~ FAILED : int {static} + ~ RUNNING : int {static} + ~ callback : Optional> + ~ exception : Exception + ~ lock : Object + ~ state : int + ~ value : T + ~ CompletableResult(callback : AsyncCallback) + + await() + + getValue() : T + + isCompleted() : boolean + ~ setException(exception : Exception) + ~ setValue(value : T) + } +} +CompletableResult ..+ ThreadAsyncExecutor +ThreadAsyncExecutor ..|> AsyncExecutor +CompletableResult ..|> AsyncResult +@enduml \ No newline at end of file diff --git a/etc/aws-black.png b/etc/aws-black.png new file mode 100644 index 000000000000..7b5ba317856f Binary files /dev/null and b/etc/aws-black.png differ diff --git a/etc/azure-black.png b/etc/azure-black.png new file mode 100644 index 000000000000..95ceb7e828ca Binary files /dev/null and b/etc/azure-black.png differ diff --git a/etc/balking.png b/etc/balking.png new file mode 100644 index 000000000000..f409eaacbb95 Binary files /dev/null and b/etc/balking.png differ diff --git a/etc/balking.ucls b/etc/balking.ucls new file mode 100644 index 000000000000..e750f888a9ef --- /dev/null +++ b/etc/balking.ucls @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/balking.urm.puml b/etc/balking.urm.puml new file mode 100644 index 000000000000..191fd350bcd8 --- /dev/null +++ b/etc/balking.urm.puml @@ -0,0 +1,30 @@ +@startuml +package com.iluwatar.balking { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + interface DelayProvider { + + executeAfterDelay(long, TimeUnit, Runnable) {abstract} + } + class WashingMachine { + - LOGGER : Logger {static} + - delayProvider : DelayProvider + - washingMachineState : WashingMachineState + + WashingMachine() + + WashingMachine(delayProvider : DelayProvider) + + endOfWashing() + + getWashingMachineState() : WashingMachineState + + wash() + } + enum WashingMachineState { + + ENABLED {static} + + WASHING {static} + + valueOf(name : String) : WashingMachineState {static} + + values() : WashingMachineState[] {static} + } +} +WashingMachine --> "-washingMachineState" WashingMachineState +WashingMachine --> "-delayProvider" DelayProvider +@enduml \ No newline at end of file diff --git a/etc/bridge.urm.png b/etc/bridge.urm.png new file mode 100644 index 000000000000..785585bf8163 Binary files /dev/null and b/etc/bridge.urm.png differ diff --git a/etc/bridge.urm.puml b/etc/bridge.urm.puml new file mode 100644 index 000000000000..d5d6a38a91d9 --- /dev/null +++ b/etc/bridge.urm.puml @@ -0,0 +1,58 @@ +@startuml +package com.iluwatar.bridge { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + interface Enchantment { + + apply() {abstract} + + onActivate() {abstract} + + onDeactivate() {abstract} + } + class FlyingEnchantment { + - LOGGER : Logger {static} + + FlyingEnchantment() + + apply() + + onActivate() + + onDeactivate() + } + class Hammer { + - LOGGER : Logger {static} + - enchantment : Enchantment + + Hammer(enchantment : Enchantment) + + getEnchantment() : Enchantment + + swing() + + unwield() + + wield() + } + class SoulEatingEnchantment { + - LOGGER : Logger {static} + + SoulEatingEnchantment() + + apply() + + onActivate() + + onDeactivate() + } + class Sword { + - LOGGER : Logger {static} + - enchantment : Enchantment + + Sword(enchantment : Enchantment) + + getEnchantment() : Enchantment + + swing() + + unwield() + + wield() + } + interface Weapon { + + getEnchantment() : Enchantment {abstract} + + swing() {abstract} + + unwield() {abstract} + + wield() {abstract} + } +} +Sword --> "-enchantment" Enchantment +Hammer --> "-enchantment" Enchantment +FlyingEnchantment ..|> Enchantment +Hammer ..|> Weapon +SoulEatingEnchantment ..|> Enchantment +Sword ..|> Weapon +@enduml \ No newline at end of file diff --git a/etc/bst.jpg b/etc/bst.jpg new file mode 100644 index 000000000000..f7ed6af8271e Binary files /dev/null and b/etc/bst.jpg differ diff --git a/etc/builder.urm.png b/etc/builder.urm.png new file mode 100644 index 000000000000..d77808d36097 Binary files /dev/null and b/etc/builder.urm.png differ diff --git a/etc/builder.urm.puml b/etc/builder.urm.puml new file mode 100644 index 000000000000..43d595a176fc --- /dev/null +++ b/etc/builder.urm.puml @@ -0,0 +1,100 @@ +@startuml +package com.iluwatar.builder { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + enum Armor { + + CHAIN_MAIL {static} + + CLOTHES {static} + + LEATHER {static} + + PLATE_MAIL {static} + - title : String + + toString() : String + + valueOf(name : String) : Armor {static} + + values() : Armor[] {static} + } + enum HairColor { + + BLACK {static} + + BLOND {static} + + BROWN {static} + + RED {static} + + WHITE {static} + + toString() : String + + valueOf(name : String) : HairColor {static} + + values() : HairColor[] {static} + } + enum HairType { + + BALD {static} + + CURLY {static} + + LONG_CURLY {static} + + LONG_STRAIGHT {static} + + SHORT {static} + - title : String + + toString() : String + + valueOf(name : String) : HairType {static} + + values() : HairType[] {static} + } + class Hero { + - armor : Armor + - hairColor : HairColor + - hairType : HairType + - name : String + - profession : Profession + - weapon : Weapon + - Hero(builder : Builder) + + getArmor() : Armor + + getHairColor() : HairColor + + getHairType() : HairType + + getName() : String + + getProfession() : Profession + + getWeapon() : Weapon + + toString() : String + } + class Builder { + - armor : Armor + - hairColor : HairColor + - hairType : HairType + - name : String + - profession : Profession + - weapon : Weapon + + Builder(profession : Profession, name : String) + + build() : Hero + + withArmor(armor : Armor) : Builder + + withHairColor(hairColor : HairColor) : Builder + + withHairType(hairType : HairType) : Builder + + withWeapon(weapon : Weapon) : Builder + } + enum Profession { + + MAGE {static} + + PRIEST {static} + + THIEF {static} + + WARRIOR {static} + + toString() : String + + valueOf(name : String) : Profession {static} + + values() : Profession[] {static} + } + enum Weapon { + + AXE {static} + + BOW {static} + + DAGGER {static} + + SWORD {static} + + WARHAMMER {static} + + toString() : String + + valueOf(name : String) : Weapon {static} + + values() : Weapon[] {static} + } +} +Hero --> "-profession" Profession +Builder ..+ Hero +Hero --> "-armor" Armor +Builder --> "-hairColor" HairColor +Builder --> "-weapon" Weapon +Builder --> "-hairType" HairType +Hero --> "-hairColor" HairColor +Builder --> "-profession" Profession +Hero --> "-weapon" Weapon +Hero --> "-hairType" HairType +Builder --> "-armor" Armor +@enduml \ No newline at end of file diff --git a/etc/business-delegate.urm.png b/etc/business-delegate.urm.png new file mode 100644 index 000000000000..4dca6c263b99 Binary files /dev/null and b/etc/business-delegate.urm.png differ diff --git a/etc/business-delegate.urm.puml b/etc/business-delegate.urm.puml new file mode 100644 index 000000000000..407e3e12d1ea --- /dev/null +++ b/etc/business-delegate.urm.puml @@ -0,0 +1,46 @@ +@startuml +package com.iluwatar.business.delegate { + class App { + + App() + + main(args : String[]) {static} + } + class BusinessDelegate { + - lookupService : BusinessLookup + + BusinessDelegate() + + playbackMovie(movie : String) + + setLookupService(lookupService : BusinessLookup) + } + class BusinessLookup { + - netflixService : NetflixService + - youTubeService : YouTubeService + + BusinessLookup() + + getBusinessService(movie : String) : VideoStreamingService + + setNetflixService(netflixService : NetflixService) + + setYouTubeService(youTubeService : YouTubeService) + } + class MobileClient { + - businessDelegate : BusinessDelegate + + MobileClient(businessDelegate : BusinessDelegate) + + playbackMovie(movie : String) + } + class NetflixService { + - LOGGER : Logger {static} + + NetflixService() + + doProcessing() + } + interface VideoStreamingService { + + doProcessing() {abstract} + } + class YouTubeService { + - LOGGER : Logger {static} + + YouTubeService() + + doProcessing() + } +} +BusinessLookup --> "-netflixService" NetflixService +BusinessLookup --> "-youTubeService" YouTubeService +MobileClient --> "-businessDelegate" BusinessDelegate +BusinessDelegate --> "-lookupService" BusinessLookup +NetflixService ..|> VideoStreamingService +YouTubeService ..|> VideoStreamingService +@enduml \ No newline at end of file diff --git a/etc/bytecode.urm.png b/etc/bytecode.urm.png new file mode 100644 index 000000000000..51335fa0a4b4 Binary files /dev/null and b/etc/bytecode.urm.png differ diff --git a/etc/bytecode.urm.puml b/etc/bytecode.urm.puml new file mode 100644 index 000000000000..224e909efa15 --- /dev/null +++ b/etc/bytecode.urm.puml @@ -0,0 +1,73 @@ +@startuml +package com.iluwatar.bytecode { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + enum Instruction { + + ADD {static} + + DIVIDE {static} + + GET_AGILITY {static} + + GET_HEALTH {static} + + GET_WISDOM {static} + + LITERAL {static} + + PLAY_SOUND {static} + + SET_AGILITY {static} + + SET_HEALTH {static} + + SET_WISDOM {static} + + SPAWN_PARTICLES {static} + - intValue : int + + getInstruction(value : int) : Instruction {static} + + getIntValue() : int + + valueOf(name : String) : Instruction {static} + + values() : Instruction[] {static} + } + class VirtualMachine { + - LOGGER : Logger {static} + - stack : Stack + - wizards : Wizard[] + + VirtualMachine() + + VirtualMachine(wizard1 : Wizard, wizard2 : Wizard) + + execute(bytecode : int[]) + + getAgility(wizard : int) : int + + getHealth(wizard : int) : int + + getStack() : Stack + + getWisdom(wizard : int) : int + + getWizards() : Wizard[] + - randomInt(min : int, max : int) : int + + setAgility(wizard : int, amount : int) + + setHealth(wizard : int, amount : int) + + setWisdom(wizard : int, amount : int) + } + class Wizard { + - LOGGER : Logger {static} + - agility : int + - health : int + - numberOfPlayedSounds : int + - numberOfSpawnedParticles : int + - wisdom : int + + Wizard(health : int, agility : int, wisdom : int, numberOfPlayedSounds : int, numberOfSpawnedParticles : int) + + getAgility() : int + + getHealth() : int + + getNumberOfPlayedSounds() : int + + getNumberOfSpawnedParticles() : int + + getWisdom() : int + + playSound() + + setAgility(agility : int) + + setHealth(health : int) + + setNumberOfPlayedSounds(numberOfPlayedSounds : int) + + setNumberOfSpawnedParticles(numberOfSpawnedParticles : int) + + setWisdom(wisdom : int) + + spawnParticles() + } +} +package com.iluwatar.bytecode.util { + class InstructionConverterUtil { + + InstructionConverterUtil() + + convertToByteCode(instructions : String) : int[] {static} + - isValidInstruction(instruction : String) : boolean {static} + - isValidInt(value : String) : boolean {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/caching.png b/etc/caching.png new file mode 100644 index 000000000000..5be2dc0ea7f8 Binary files /dev/null and b/etc/caching.png differ diff --git a/etc/caching.ucls b/etc/caching.ucls new file mode 100644 index 000000000000..a058277ea2fd --- /dev/null +++ b/etc/caching.ucls @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/caching.urm.puml b/etc/caching.urm.puml new file mode 100644 index 000000000000..a9dae801eb20 --- /dev/null +++ b/etc/caching.urm.puml @@ -0,0 +1,119 @@ +@startuml +package com.iluwatar.caching.constants { + class CachingConstants { + + ADD_INFO : String {static} + + USER_ACCOUNT : String {static} + + USER_ID : String {static} + + USER_NAME : String {static} + + CachingConstants() + } +} +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 {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 + ~ capacity : int + ~ end : Node + ~ head : Node + + LruCache(capacity : int) + + clear() + + contains(userId : String) : boolean + + get(userId : String) : UserAccount + + getCacheDataInListForm() : List + + 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 + } +} +Node --+ LruCache +LruCache --> "-head" Node +Node --> "-previous" Node +AppManager --> "-cachingPolicy" CachingPolicy +Node --> "-userAccount" UserAccount +CacheStore --> "-cache" LruCache +@enduml \ No newline at end of file diff --git a/etc/callback.png b/etc/callback.png new file mode 100644 index 000000000000..7b499f79fcaa Binary files /dev/null and b/etc/callback.png differ diff --git a/etc/callback.ucls b/etc/callback.ucls new file mode 100644 index 000000000000..ae3e7b23223a --- /dev/null +++ b/etc/callback.ucls @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/callback.urm.puml b/etc/callback.urm.puml new file mode 100644 index 000000000000..2d213eda800c --- /dev/null +++ b/etc/callback.urm.puml @@ -0,0 +1,23 @@ +@startuml +package com.iluwatar.callback { + class App { + - LOGGER : Logger {static} + - App() + + main(args : String[]) {static} + } + interface Callback { + + call() {abstract} + } + class SimpleTask { + - LOGGER : Logger {static} + + SimpleTask() + + execute() + } + abstract class Task { + + Task() + + execute() {abstract} + ~ executeWith(callback : Callback) + } +} +SimpleTask --|> Task +@enduml \ No newline at end of file diff --git a/etc/chain-of-responsibility.urm.png b/etc/chain-of-responsibility.urm.png new file mode 100644 index 000000000000..af1bd105455b Binary files /dev/null and b/etc/chain-of-responsibility.urm.png differ diff --git a/etc/chain-of-responsibility.urm.puml b/etc/chain-of-responsibility.urm.puml new file mode 100644 index 000000000000..b548cab81847 --- /dev/null +++ b/etc/chain-of-responsibility.urm.puml @@ -0,0 +1,67 @@ +@startuml +package com.iluwatar.chain { + class App { + + App() + + main(args : String[]) {static} + } + class OrcCommander { + - LOGGER : Logger {static} + + OrcCommander() + + canHandleRequest(req : Request) : boolean + + getPriority() : int + + handle(req : Request) + + name() : String + } + class OrcKing { + - handlers : List + + OrcKing() + - buildChain() + + makeRequest(req : Request) + } + class OrcOfficer { + - LOGGER : Logger {static} + + OrcOfficer() + + canHandleRequest(req : Request) : boolean + + getPriority() : int + + handle(req : Request) + + name() : String + } + class OrcSoldier { + - LOGGER : Logger {static} + + OrcSoldier() + + canHandleRequest(req : Request) : boolean + + getPriority() : int + + handle(req : Request) + + name() : String + } + class Request { + - handled : boolean + - requestDescription : String + - requestType : RequestType + + Request(requestType : RequestType, requestDescription : String) + + getRequestDescription() : String + + getRequestType() : RequestType + + isHandled() : boolean + + markHandled() + + toString() : String + } + interface RequestHandler { + + canHandleRequest(Request) : boolean {abstract} + + getPriority() : int {abstract} + + handle(Request) {abstract} + + name() : String {abstract} + } + enum RequestType { + + COLLECT_TAX {static} + + DEFEND_CASTLE {static} + + TORTURE_PRISONER {static} + + valueOf(name : String) : RequestType {static} + + values() : RequestType[] {static} + } +} +OrcKing --> "-handlers" RequestHandler +Request --> "-requestType" RequestType +OrcCommander ..|> RequestHandler +OrcOfficer ..|> RequestHandler +OrcSoldier ..|> RequestHandler +@enduml \ No newline at end of file diff --git a/etc/chain.urm.png b/etc/chain.urm.png new file mode 100644 index 000000000000..c3a4c80ba322 Binary files /dev/null and b/etc/chain.urm.png differ diff --git a/etc/chain.urm.puml b/etc/chain.urm.puml new file mode 100644 index 000000000000..43c78a04223e --- /dev/null +++ b/etc/chain.urm.puml @@ -0,0 +1,61 @@ +@startuml +package com.iluwatar.chain { + class App { + + App() + + main(args : String[]) {static} + } + class OrcCommander { + + OrcCommander(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } + class OrcKing { + - chain : RequestHandler + + OrcKing() + - buildChain() + + makeRequest(req : Request) + } + class OrcOfficer { + + OrcOfficer(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } + class OrcSoldier { + + OrcSoldier(handler : RequestHandler) + + handleRequest(req : Request) + + toString() : String + } + class Request { + - handled : boolean + - requestDescription : String + - requestType : RequestType + + Request(requestType : RequestType, requestDescription : String) + + getRequestDescription() : String + + getRequestType() : RequestType + + isHandled() : boolean + + markHandled() + + toString() : String + } + abstract class RequestHandler { + - LOGGER : Logger {static} + - next : RequestHandler + + RequestHandler(next : RequestHandler) + + handleRequest(req : Request) + # printHandling(req : Request) + + toString() : String {abstract} + } + enum RequestType { + + COLLECT_TAX {static} + + DEFEND_CASTLE {static} + + TORTURE_PRISONER {static} + + valueOf(name : String) : RequestType {static} + + values() : RequestType[] {static} + } +} +OrcKing --> "-chain" RequestHandler +RequestHandler --> "-next" RequestHandler +Request --> "-requestType" RequestType +OrcCommander --|> RequestHandler +OrcOfficer --|> RequestHandler +OrcSoldier --|> RequestHandler +@enduml \ No newline at end of file diff --git a/etc/circuit-breaker.urm.png b/etc/circuit-breaker.urm.png new file mode 100644 index 000000000000..fc90318ec8da Binary files /dev/null and b/etc/circuit-breaker.urm.png differ diff --git a/etc/circuit-breaker.urm.puml b/etc/circuit-breaker.urm.puml new file mode 100644 index 000000000000..951ec02d31c5 --- /dev/null +++ b/etc/circuit-breaker.urm.puml @@ -0,0 +1,69 @@ +@startuml +package com.iluwatar.circuitbreaker { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + interface CircuitBreaker { + + attemptRequest() : String {abstract} + + getState() : String {abstract} + + recordFailure(String) {abstract} + + recordSuccess() {abstract} + + setState(State) {abstract} + } + class DefaultCircuitBreaker { + ~ failureCount : int + - failureThreshold : int + - futureTime : long + - lastFailureResponse : String + ~ lastFailureTime : long + - retryTimePeriod : long + - service : RemoteService + - state : State + - timeout : long + ~ DefaultCircuitBreaker(serviceToCall : RemoteService, timeout : long, failureThreshold : int, retryTimePeriod : long) + + attemptRequest() : String + # evaluateState() + + getState() : String + + recordFailure(response : String) + + recordSuccess() + + setState(state : State) + } + class DelayedRemoteService { + - delay : int + - serverStartTime : long + + DelayedRemoteService() + + DelayedRemoteService(serverStartTime : long, delay : int) + + call() : String + } + class MonitoringService { + - delayedService : CircuitBreaker + - quickService : CircuitBreaker + + MonitoringService(delayedService : CircuitBreaker, quickService : CircuitBreaker) + + delayedServiceResponse() : String + + localResourceResponse() : String + + quickServiceResponse() : String + } + class QuickRemoteService { + + QuickRemoteService() + + call() : String + } + interface RemoteService { + + call() : String {abstract} + } + enum State { + + CLOSED {static} + + HALF_OPEN {static} + + OPEN {static} + + valueOf(name : String) : State {static} + + values() : State[] {static} + } +} +DefaultCircuitBreaker --> "-state" State +MonitoringService --> "-delayedService" CircuitBreaker +DefaultCircuitBreaker --> "-service" RemoteService +DefaultCircuitBreaker ..|> CircuitBreaker +DelayedRemoteService ..|> RemoteService +QuickRemoteService ..|> RemoteService +@enduml \ No newline at end of file diff --git a/etc/claim-check-pattern.urm.puml b/etc/claim-check-pattern.urm.puml new file mode 100644 index 000000000000..14df8b68b046 --- /dev/null +++ b/etc/claim-check-pattern.urm.puml @@ -0,0 +1,117 @@ +@startuml +class UsageDetailPublisherFunction [[java:com.iluwatar.producer.calldetails.functions]] { + -messageHandlerUtility: MessageHandlerUtility + -eventHandlerUtility: EventHandlerUtility + +run(): HttpResponseMessage +} + +class UsageCostProcessorFunction [[java:com.iluwatar.consumer.callcostprocessor.functions]] { + -messageHandlerUtilityForUsageDetail: MessageHandlerUtility + -messageHandlerUtilityForUsageCostDetail: MessageHandlerUtility + +run(): HttpResponseMessage +} + +class "MessageHandlerUtility" as MessageHandlerUtility_T [[java:com.iluwatar.claimcheckpattern.utility]] { + +readFromPersistantStorage(messageReference: MessageReference, logger: Logger): Message + +dropToPersistantStorage(message: Message, logger: Logger): void +} + +class "EventHandlerUtility" as EventHandlerUtility_T [[java:com.callusage.utility.PersistentLocalStorageUtility]] { + +publishEvent(customEvent: T, logger: Logger): void +} + +class "Message" as Message_T [[java:com.iluwatar.claimcheckpattern.domain]] { + -messageHeader: MessageHeader + -messageData: MessageData + +Message(messageHeader: MessageHeader, messageData: MessageData) + +getMessageData(): MessageData + +getMessageHeader(): MessageHeader +} + + +class MessageHeader [[java:com.iluwatar.claimcheckpattern.domain]] { + -id: String + -subject: String + -topic: String + -eventType: String + -eventTime: String + -data: Object + -dataVersion: String + +getId(): String + +setId(id: String): void + +getSubject(): String + +setSubject(subject: String): void + +getTopic(): String + +setTopic(topic: String): void + +getEventType(): String + +setEventType(eventType: String): void + +getEventTime(): String + +setEventTime(eventTime: String): void + +getData(): Object + +setData(data: Object): void + +getDataVersion(): String + +setDataVersion(dataVersion:String): void + +} + + +class "MessageBody" as MessageBody_T [[java:com.iluwatar.claimcheckpattern.domain]] { + -data: List[] T + +getData(): List[] T + +setData(data:List[] T): void +} + +class MessageReference [[java:com.iluwatar.claimcheckpattern.domain]] { + -dataLocation: String + -dataFileName: String + +getDataLocation(): String + +setDataLocation(dataLocation:String): void + +getDataFileName(): String + +setDataFileName(dataFileName:String): void +} + +class UsageDetail [[java:com.iluwatar.claimcheckpattern.domain]] { + -userId: String + -duration: int + -data: int + +getUserId(): String + +setUserId(userId: String): void + +getDuration(): long + +setDuration(duration: long): void + +getData(): long + +setData(data: long): void +} + +class UsageCostDetail [[java:com.iluwatar.claimcheckpattern.domain]] { + -userId: String + -callCost: double + -dataCost: double + +getUserId(): String + +setUserId(userId: String): void + +getCallCost(): double + +setCallCost(callCost:double): void + +getDataCost(): double + +setDataCost(dataCost:double) : void +} + + + + + + + +Message_T "1" *-- "1" MessageHeader : has +Message_T "1" *-- "1" MessageBody_T : has +MessageHeader "1" *-- "1" MessageReference : has as data object +MessageBody_T "1" *-- "1" UsageDetail: has +MessageBody_T "1" *-- "1" UsageCostDetail: has + +EventHandlerUtility_T "1" *-- "1" MessageHeader: has +MessageHandlerUtility_T "1" *-- "1" Message_T: has + +UsageDetailPublisherFunction "1" *-- "1" MessageHandlerUtility_T : has +UsageDetailPublisherFunction "1" *-- "1" EventHandlerUtility_T : has + +UsageCostProcessorFunction "1" *-- "1" MessageHandlerUtility_T : has +UsageCostProcessorFunction "1" *-- "1" MessageHandlerUtility_T : has +@enduml \ No newline at end of file diff --git a/etc/class-diagram.png b/etc/class-diagram.png new file mode 100644 index 000000000000..d627b1b70c21 Binary files /dev/null and b/etc/class-diagram.png differ diff --git a/etc/class_diagram.png b/etc/class_diagram.png new file mode 100644 index 000000000000..10d509801f79 Binary files /dev/null and b/etc/class_diagram.png differ diff --git a/etc/class_diagram.urm.png b/etc/class_diagram.urm.png new file mode 100644 index 000000000000..fb8e7a73428d Binary files /dev/null and b/etc/class_diagram.urm.png differ diff --git a/etc/classes.png b/etc/classes.png new file mode 100644 index 000000000000..295719ea3712 Binary files /dev/null and b/etc/classes.png differ diff --git a/etc/classes.ucls b/etc/classes.ucls new file mode 100644 index 000000000000..4a869b9d24e2 --- /dev/null +++ b/etc/classes.ucls @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/collection-pipeline.png b/etc/collection-pipeline.png new file mode 100644 index 000000000000..67d52629cb86 Binary files /dev/null and b/etc/collection-pipeline.png differ diff --git a/etc/collection-pipeline.ucls b/etc/collection-pipeline.ucls new file mode 100644 index 000000000000..6373db62f67a --- /dev/null +++ b/etc/collection-pipeline.ucls @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/collection-pipeline.urm.puml b/etc/collection-pipeline.urm.puml new file mode 100644 index 000000000000..8cd51c44656b --- /dev/null +++ b/etc/collection-pipeline.urm.puml @@ -0,0 +1,52 @@ +@startuml +package com.iluwatar.collectionpipeline { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Car { + - category : Category + - make : String + - model : String + - year : int + + Car(make : String, model : String, yearOfMake : int, category : Category) + + equals(obj : Object) : boolean + + getCategory() : Category + + getMake() : String + + getModel() : String + + getYear() : int + + hashCode() : int + } + class CarFactory { + - CarFactory() + + createCars() : List {static} + } + enum Category { + + CONVERTIBLE {static} + + JEEP {static} + + SEDAN {static} + + valueOf(name : String) : Category {static} + + values() : Category[] {static} + } + class FunctionalProgramming { + - FunctionalProgramming() + + getGroupingOfCarsByCategory(cars : List) : Map> {static} + + getModelsAfter2000(cars : List) : List {static} + + getSedanCarsOwnedSortedByDate(persons : List) : List {static} + } + class ImperativeProgramming { + - ImperativeProgramming() + + getGroupingOfCarsByCategory(cars : List) : Map> {static} + + getModelsAfter2000(cars : List) : List {static} + + getSedanCarsOwnedSortedByDate(persons : List) : List {static} + } + class Person { + - cars : List + + Person(cars : List) + + getCars() : List + } +} +Person --> "-cars" Car +Car --> "-category" Category +@enduml \ No newline at end of file diff --git a/etc/combinator.urm.png b/etc/combinator.urm.png new file mode 100644 index 000000000000..80fdd36340bb Binary files /dev/null and b/etc/combinator.urm.png differ diff --git a/etc/combinator.urm.puml b/etc/combinator.urm.puml new file mode 100644 index 000000000000..83feec1ae782 --- /dev/null +++ b/etc/combinator.urm.puml @@ -0,0 +1,26 @@ +@startuml +package com.iluwatar.combinator { + class CombinatorApp { + - LOGGER : Logger {static} + + CombinatorApp() + + main(args : String[]) {static} + - text() : String {static} + } + interface Finder { + + and(andFinder : Finder) : Finder + + contains(word : String) : Finder {static} + + find(String) : List {abstract} + + not(notFinder : Finder) : Finder + + or(orFinder : Finder) : Finder + } + class Finders { + - Finders() + + advancedFinder(query : String, orQuery : String, notQuery : String) : Finder {static} + + expandedFinder(queries : String[]) : Finder {static} + + filteredFinder(query : String, excludeQueries : String[]) : Finder {static} + - identMult() : Finder {static} + - identSum() : Finder {static} + + specializedFinder(queries : String[]) : Finder {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/command.png b/etc/command.png new file mode 100644 index 000000000000..0f026464ecc4 Binary files /dev/null and b/etc/command.png differ diff --git a/etc/command.ucls b/etc/command.ucls new file mode 100644 index 000000000000..afc7e1762f98 --- /dev/null +++ b/etc/command.ucls @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/etc/command.urm.puml b/etc/command.urm.puml new file mode 100644 index 000000000000..f85949c566da --- /dev/null +++ b/etc/command.urm.puml @@ -0,0 +1,58 @@ +@startuml +package com.iluwatar.command { + class App { + + App() + + main(args : String[]) {static} + } + class Goblin { + + Goblin() + + toString() : String + + changeSize() + + changeVisibility() + } + enum Size { + + NORMAL {static} + + SMALL {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} + + VISIBLE {static} + - title : String + + toString() : String + + valueOf(name : String) : Visibility {static} + + values() : Visibility[] {static} + } + class Wizard { + - LOGGER : Logger {static} + - redoStack : Deque + - undoStack : Deque + + Wizard() + + castSpell(Runnable : runnable) + + redoLastSpell() + + toString() : String + + undoLastSpell() + } +} +Target --> "-size" Size +Wizard --> "-changeSize" Goblin +Wizard --> "-changeVisibility" Goblin +Target --> "-visibility" Visibility +Goblin --|> Target +App --> "castSpell" Wizard +@enduml diff --git a/etc/commander.urm.png b/etc/commander.urm.png new file mode 100644 index 000000000000..6b5ebba75bd6 Binary files /dev/null and b/etc/commander.urm.png differ diff --git a/etc/commander.urm.puml b/etc/commander.urm.puml new file mode 100644 index 000000000000..959fbfadcf88 --- /dev/null +++ b/etc/commander.urm.puml @@ -0,0 +1,329 @@ +@startuml +package com.iluwatar.commander.queue { + class Queue { + - front : Queue.Node + - rear : Queue.Node + - size : int + ~ Queue() + ~ dequeue() : T + ~ enqueue(obj : T) + ~ isEmpty() : boolean + ~ peek() : T + } + ~class Node { + ~ next : Queue.Node + ~ value : V + ~ Node(obj : V, b : Queue.Node) + } + class QueueDatabase { + - data : Queue + + exceptionsList : List + + QueueDatabase(exc : Exception[]) + + add(t : QueueTask) : QueueTask + + dequeue() : QueueTask + + get(taskId : String) : QueueTask + + peek() : QueueTask + } + class QueueTask { + + firstAttemptTime : long + + messageType : int + + order : Order + + taskType : TaskType + + QueueTask(o : Order, t : TaskType, messageType : int) + + getType() : String + } + enum TaskType { + + EmployeeDb {static} + + Messaging {static} + + Payment {static} + + valueOf(name : String) : TaskType {static} + + values() : TaskType[] {static} + } +} +package com.iluwatar.commander.messagingservice { + class MessagingDatabase { + - data : Hashtable + + MessagingDatabase() + + add(r : MessageRequest) : MessageRequest + + get(requestId : String) : MessageRequest + } + class MessagingService { + - LOGGER : Logger {static} + + MessagingService(db : MessagingDatabase, exc : Exception[]) + + receiveRequest(parameters : Object[]) : String + ~ sendMessage(m : MessageToSend) : String + # updateDb(parameters : Object[]) : String + } + ~class MessageRequest { + ~ msg : MessageToSend + ~ reqId : String + ~ MessageRequest(this$0 : String, reqId : MessageToSend) + } + ~enum MessageToSend { + + PaymentFail {static} + + PaymentSuccessful {static} + + PaymentTrying {static} + + valueOf(name : String) : MessageToSend {static} + + values() : MessageToSend[] {static} + } +} +package com.iluwatar.commander { + class AppEmployeeDbFailCases { + - employeeTime : long + - messageTime : long + - numOfRetries : int + - paymentTime : long + - queueTaskTime : long + - queueTime : long + - retryDuration : long + + AppEmployeeDbFailCases() + ~ employeeDatabaseUnavailableCase() + ~ employeeDbSuccessCase() + + main(args : String[]) {static} + } + class AppMessagingFailCases { + - employeeTime : long + - messageTime : long + - numOfRetries : int + - paymentTime : long + - queueTaskTime : long + - queueTime : long + - retryDuration : long + + AppMessagingFailCases() + + main(args : String[]) {static} + ~ messagingDatabaseUnavailableCasePaymentError() + ~ messagingDatabaseUnavailableCasePaymentFailure() + ~ messagingDatabaseUnavailableCasePaymentSuccess() + ~ messagingSuccessCase() + } + class AppPaymentFailCases { + - employeeTime : long + - messageTime : long + - numOfRetries : int + - paymentTime : long + - queueTaskTime : long + - queueTime : long + - retryDuration : long + + AppPaymentFailCases() + + main(args : String[]) {static} + ~ paymentDatabaseUnavailableCase() + ~ paymentNotPossibleCase() + ~ paymentSuccessCase() + } + class AppQueueFailCases { + - employeeTime : long + - messageTime : long + - numOfRetries : int + - paymentTime : long + - queueTaskTime : long + - queueTime : long + - retryDuration : long + + AppQueueFailCases() + + main(args : String[]) {static} + ~ queueEmployeeDbTaskDatabaseUnavailableCase() + ~ queueMessageTaskDatabaseUnavailableCase() + ~ queuePaymentTaskDatabaseUnavailableCase() + ~ queueSuccessCase() + } + class AppShippingFailCases { + - employeeTime : long + - messageTime : long + - numOfRetries : int + - paymentTime : long + - queueTaskTime : long + - queueTime : long + - retryDuration : long + + AppShippingFailCases() + ~ itemUnavailableCase() + + main(args : String[]) {static} + ~ shippingDatabaseUnavailableCase() + ~ shippingNotPossibleCase() + ~ shippingSuccessCase() + } + class Commander { + - LOG : Logger {static} + - employeeDb : EmployeeHandle + - employeeTime : long + - finalSiteMsgShown : boolean + - messageTime : long + - messagingService : MessagingService + - numOfRetries : int + - paymentService : PaymentService + - paymentTime : long + - queue : QueueDatabase + - queueItems : int + - queueTaskTime : long + - queueTime : long + - retryDuration : long + - shippingService : ShippingService + ~ Commander(empDb : EmployeeHandle, paymentService : PaymentService, shippingService : ShippingService, messagingService : MessagingService, qdb : QueueDatabase, numOfRetries : int, retryDuration : long, queueTime : long, queueTaskTime : long, paymentTime : long, messageTime : long, employeeTime : long) + - doTasksInQueue() + - employeeHandleIssue(order : Order) + ~ placeOrder(order : Order) + - sendPaymentFailureMessage(order : Order) + - sendPaymentPossibleErrorMsg(order : Order) + - sendPaymentRequest(order : Order) + - sendShippingRequest(order : Order) + - sendSuccessMessage(order : Order) + - tryDequeue() + - tryDoingTasksInQueue() + - updateQueue(qt : QueueTask) + } + abstract class Database { + + Database() + + add(T) : T {abstract} + + get(String) : T {abstract} + } + class Order { + - ALL_CHARS : String {static} + - RANDOM : Random {static} + - USED_IDS : Hashtable {static} + ~ addedToEmployeeHandle : boolean + ~ createdTime : long + + id : String + ~ item : String + ~ messageSent : MessageSent + ~ paid : PaymentStatus + ~ price : float + ~ user : User + ~ Order(user : User, item : String, price : float) + - createUniqueId() : String + } + ~enum MessageSent { + + NoneSent {static} + + PaymentFail {static} + + PaymentSuccessful {static} + + PaymentTrying {static} + + valueOf(name : String) : MessageSent {static} + + values() : MessageSent[] {static} + } + ~enum PaymentStatus { + + Done {static} + + NotDone {static} + + Trying {static} + + valueOf(name : String) : PaymentStatus {static} + + values() : PaymentStatus[] {static} + } + class Retry { + - RANDOM : Random {static} + - attempts : AtomicInteger + - errors : List + - handleError : Retry.HandleErrorIssue + - maxAttempts : int + - maxDelay : long + - op : Operation + - test : Predicate + ~ Retry(op : Operation, handleError : Retry.HandleErrorIssue, maxAttempts : int, maxDelay : long, ignoreTests : Predicate[]) + + perform(list : List, obj : T) + } + interface HandleErrorIssue { + + handleIssue(T, Exception) {abstract} + } + interface Operation { + + operation(List) {abstract} + } + abstract class Service { + - ALL_CHARS : String {static} + - RANDOM : Random {static} + - USED_IDS : Hashtable {static} + # database : Database + + exceptionsList : ArrayList + # Service(db : Database, exc : Exception[]) + # generateId() : String + + receiveRequest(Object[]) : String {abstract} + # updateDb(Object[]) : String {abstract} + } + class User { + ~ address : String + ~ name : String + ~ User(name : String, address : String) + } +} +package com.iluwatar.commander.shippingservice { + class ShippingDatabase { + - data : Hashtable + + ShippingDatabase() + + add(r : ShippingRequest) : ShippingRequest + + get(trasnactionId : String) : ShippingRequest + } + class ShippingService { + + ShippingService(db : ShippingDatabase, exc : Exception[]) + + receiveRequest(parameters : Object[]) : String + # updateDb(parameters : Object[]) : String + } + ~class ShippingRequest { + ~ address : String + ~ item : String + ~ transactionId : String + ~ ShippingRequest(transactionId : String, item : String, address : String) + } +} +package com.iluwatar.commander.paymentservice { + class PaymentDatabase { + - data : Hashtable + + PaymentDatabase() + + add(r : PaymentRequest) : PaymentRequest + + get(requestId : String) : PaymentRequest + } + class PaymentService { + + PaymentService(db : PaymentDatabase, exc : Exception[]) + + receiveRequest(parameters : Object[]) : String + # updateDb(parameters : Object[]) : String + } + ~class PaymentRequest { + ~ paid : boolean + ~ payment : float + ~ transactionId : String + ~ PaymentRequest(this$0 : String, transactionId : float) + } +} +package com.iluwatar.commander.employeehandle { + class EmployeeDatabase { + - data : Hashtable + + EmployeeDatabase() + + add(o : Order) : Order + + get(orderId : String) : Order + } + class EmployeeHandle { + + EmployeeHandle(db : EmployeeDatabase, exc : Exception[]) + + receiveRequest(parameters : Object[]) : String + # updateDb(parameters : Object[]) : String + } +} +Order --> "-messageSent" MessageSent +MessageSent ..+ Order +MessageToSend ..+ MessagingService +Retry --> "-op" Operation +Operation ..+ Retry +Service --> "-database" Database +Node --> "-next" Node +PaymentRequest --+ PaymentService +Commander --> "-messagingService" MessagingService +ShippingRequest ..+ ShippingService +Commander --> "-shippingService" ShippingService +Commander --> "-paymentService" PaymentService +MessageRequest --+ MessagingService +Commander --> "-employeeDb" EmployeeHandle +HandleErrorIssue ..+ Retry +Retry --> "-handleError" HandleErrorIssue +QueueTask --> "-taskType" TaskType +TaskType ..+ QueueTask +Order --> "-user" User +MessageRequest --> "-msg" MessageToSend +QueueTask --> "-order" Order +Commander --> "-queue" QueueDatabase +QueueDatabase --> "-data" Queue +Queue --> "-front" Node +Node ..+ Queue +Order --> "-paid" PaymentStatus +PaymentStatus ..+ Order +EmployeeDatabase --|> Database +EmployeeHandle --|> Service +MessagingDatabase --|> Database +MessagingService --|> Service +PaymentDatabase --|> Database +PaymentService --|> Service +QueueDatabase --|> Database +ShippingDatabase --|> Database +ShippingService --|> Service +@enduml \ No newline at end of file diff --git a/etc/composite-entity.urm.puml b/etc/composite-entity.urm.puml new file mode 100644 index 000000000000..5ac4b9e655d8 --- /dev/null +++ b/etc/composite-entity.urm.puml @@ -0,0 +1,45 @@ +@startuml +package com.iluwatar.compositeentity { + class App { + + App(message: String, signal: String) + + main(args : String[]) {static} + } + class CompositeEntity{ + - console : ConsoleCoarseGrainedObject + + CompositeEntity() + + setData(message: String, signal: String) + + getData() + + init() + } + abstract CoarseGrainedObject{ + - dependentObjects : DependentObject[] + + CoarseGrainedObject() + + setData(data: T[]) + + getData() + } + abstract DependentObject{ + - data : T + + DependentObject() + + setData(data: T) + + getData() + } + class ConsoleCoarseGrainedObject{ + + ConsoleCoarseGrainedObject() + + getData() + + init() + } + class MessageDependentObject{ + + MessageDependentObject() + } + class SignalDependentObject{ + + SignalDependentObject() + } + + MessageDependentObject --|> DependentObject + SignalDependentObject --|> DependentObject + ConsoleCoarseGrainedObject --|> CoarseGrainedObject + CompositeEntity -right-> ConsoleCoarseGrainedObject + CoarseGrainedObject "1" o--> "0.." DependentObject + App .right.> CompositeEntity +} +@enduml diff --git a/etc/composite-view.urm.puml b/etc/composite-view.urm.puml new file mode 100644 index 000000000000..e92b13ea5961 --- /dev/null +++ b/etc/composite-view.urm.puml @@ -0,0 +1,29 @@ +@startuml +package com.iluwatar.compositeview { + class ClientPropertiesBean { + - BUSINESS_PARAM : String {static} + - DEFAULT_NAME : String {static} + - NAME_PARAM : String {static} + - SCIENCE_PARAM : String {static} + - SPORTS_PARAM : String {static} + - WORLD_PARAM : String {static} + - businessInterest : boolean + - name : String + - scienceNewsInterest : boolean + - sportsInterest : boolean + - worldNewsInterest : boolean + + ClientPropertiesBean() + + ClientPropertiesBean(req : HttpServletRequest) + + getName() : String + + isBusinessInterest() : boolean + + isScienceNewsInterest() : boolean + + isSportsInterest() : boolean + + isWorldNewsInterest() : boolean + + setBusinessInterest(businessInterest : boolean) + + setName(name : String) + + setScienceNewsInterest(scienceNewsInterest : boolean) + + setSportsInterest(sportsInterest : boolean) + + setWorldNewsInterest(worldNewsInterest : boolean) + } +} +@enduml \ No newline at end of file diff --git a/etc/composite.urm.png b/etc/composite.urm.png new file mode 100644 index 000000000000..93c160f6450a Binary files /dev/null and b/etc/composite.urm.png differ diff --git a/etc/composite.urm.puml b/etc/composite.urm.puml new file mode 100644 index 000000000000..6ff774711bcd --- /dev/null +++ b/etc/composite.urm.puml @@ -0,0 +1,41 @@ +@startuml +package com.iluwatar.composite { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Letter { + - character : char + + Letter(c : char) + # printThisBefore() + } + abstract class LetterComposite { + - children : List + + LetterComposite() + + add(letter : LetterComposite) + + count() : int + + print() + # printThisAfter() + # printThisBefore() + } + class Messenger { + + Messenger() + ~ messageFromElves() : LetterComposite + ~ messageFromOrcs() : LetterComposite + } + class Sentence { + + Sentence(words : List) + # printThisAfter() + } + class Word { + + Word(letters : List) + + Word(letters : char[]) + # printThisBefore() + } +} +LetterComposite --> "-children" LetterComposite +Letter --|> LetterComposite +Sentence --|> LetterComposite +Word --|> LetterComposite +@enduml \ No newline at end of file diff --git a/etc/composite_entity.urm.png b/etc/composite_entity.urm.png new file mode 100644 index 000000000000..d6c29a718837 Binary files /dev/null and b/etc/composite_entity.urm.png differ diff --git a/etc/composite_view.png b/etc/composite_view.png new file mode 100644 index 000000000000..66215d9416b8 Binary files /dev/null and b/etc/composite_view.png differ diff --git a/etc/converter.png b/etc/converter.png new file mode 100644 index 000000000000..01435ef5ae29 Binary files /dev/null and b/etc/converter.png differ diff --git a/etc/converter.urm.puml b/etc/converter.urm.puml new file mode 100644 index 000000000000..275af84e6bc8 --- /dev/null +++ b/etc/converter.urm.puml @@ -0,0 +1,50 @@ +@startuml +package com.iluwatar.converter { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Converter { + - fromDto : Function + - fromEntity : Function + + Converter(fromDto : Function, fromEntity : Function) + + convertFromDto(dto : T) : U + + convertFromEntity(entity : U) : T + + createFromDtos(dtos : Collection) : List + + createFromEntities(entities : Collection) : List + } + class User { + - firstName : String + - isActive : boolean + - lastName : String + - userId : String + + User(firstName : String, lastName : String, isActive : boolean, userId : String) + + equals(o : Object) : boolean + + getFirstName() : String + + getLastName() : String + + getUserId() : String + + hashCode() : int + + isActive() : boolean + + toString() : String + } + class UserConverter { + + UserConverter() + } + class UserDto { + - email : String + - firstName : String + - isActive : boolean + - lastName : String + + UserDto(firstName : String, lastName : String, isActive : boolean, email : String) + + equals(o : Object) : boolean + + getEmail() : String + + getFirstName() : String + + getLastName() : String + + hashCode() : int + + isActive() : boolean + + toString() : String + } +} +UserConverter --|> Converter +@enduml \ No newline at end of file diff --git a/etc/cqrs.png b/etc/cqrs.png new file mode 100644 index 000000000000..28174bc9ab8e Binary files /dev/null and b/etc/cqrs.png differ diff --git a/etc/cqrs.ucls b/etc/cqrs.ucls new file mode 100644 index 000000000000..6cdfebbb2e4b --- /dev/null +++ b/etc/cqrs.ucls @@ -0,0 +1,115 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/cqrs.urm.puml b/etc/cqrs.urm.puml new file mode 100644 index 000000000000..2b06980983c5 --- /dev/null +++ b/etc/cqrs.urm.puml @@ -0,0 +1,134 @@ +@startuml +package com.iluwatar.cqrs.util { + class HibernateUtil { + - LOGGER : Logger {static} + - SESSIONFACTORY : SessionFactory {static} + + HibernateUtil() + - buildSessionFactory() : SessionFactory {static} + + getSessionFactory() : SessionFactory {static} + } +} +package com.iluwatar.cqrs.app { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.cqrs.dto { + class Author { + - email : String + - name : String + - username : String + + Author() + + Author(name : String, email : String, username : String) + + equals(obj : Object) : boolean + + getEmail() : String + + getName() : String + + getUsername() : String + + hashCode() : int + + toString() : String + } + class Book { + - price : double + - title : String + + Book() + + Book(title : String, price : double) + + equals(obj : Object) : boolean + + getPrice() : double + + getTitle() : String + + hashCode() : int + + toString() : String + } +} +package com.iluwatar.cqrs.commandes { + class CommandServiceImpl { + - sessionFactory : SessionFactory + + CommandServiceImpl() + + authorCreated(username : String, name : String, email : String) + + authorEmailUpdated(username : String, email : String) + + authorNameUpdated(username : String, name : String) + + authorUsernameUpdated(oldUsername : String, newUsername : String) + + bookAddedToAuthor(title : String, price : double, username : String) + + bookPriceUpdated(title : String, price : double) + + bookTitleUpdated(oldTitle : String, newTitle : String) + - getAuthorByUsername(username : String) : Author + - getBookByTitle(title : String) : Book + } + interface ICommandService { + + authorCreated(String, String, String) {abstract} + + authorEmailUpdated(String, String) {abstract} + + authorNameUpdated(String, String) {abstract} + + authorUsernameUpdated(String, String) {abstract} + + bookAddedToAuthor(String, double, String) {abstract} + + bookPriceUpdated(String, double) {abstract} + + bookTitleUpdated(String, String) {abstract} + } +} +package com.iluwatar.cqrs.queries { + interface IQueryService { + + getAuthorBooks(String) : List {abstract} + + getAuthorBooksCount(String) : BigInteger {abstract} + + getAuthorByUsername(String) : Author {abstract} + + getAuthorsCount() : BigInteger {abstract} + + getBook(String) : Book {abstract} + } + class QueryServiceImpl { + - sessionFactory : SessionFactory + + QueryServiceImpl() + + getAuthorBooks(username : String) : List + + getAuthorBooksCount(username : String) : BigInteger + + getAuthorByUsername(username : String) : Author + + getAuthorsCount() : BigInteger + + getBook(title : String) : Book + } +} +package com.iluwatar.cqrs.constants { + class AppConstants { + + E_EVANS : String {static} + + J_BLOCH : String {static} + + M_FOWLER : String {static} + + USER_NAME : String {static} + + AppConstants() + } +} +package com.iluwatar.cqrs.domain.model { + class Author { + - email : String + - id : long + - name : String + - username : String + # Author() + + Author(username : String, name : String, email : String) + + getEmail() : String + + getId() : long + + getName() : String + + getUsername() : String + + setEmail(email : String) + + setId(id : long) + + setName(name : String) + + setUsername(username : String) + + toString() : String + } + class Book { + - author : Author + - id : long + - price : double + - title : String + # Book() + + Book(title : String, price : double, author : Author) + + getAuthor() : Author + + getId() : long + + getPrice() : double + + getTitle() : String + + setAuthor(author : Author) + + setId(id : long) + + setPrice(price : double) + + setTitle(title : String) + + toString() : String + } +} +Book --> "-author" Author +CommandServiceImpl ..|> ICommandService +QueryServiceImpl ..|> IQueryService +@enduml \ No newline at end of file diff --git a/etc/dao.png b/etc/dao.png new file mode 100644 index 000000000000..452e72ba10ac Binary files /dev/null and b/etc/dao.png differ diff --git a/etc/dao.ucls b/etc/dao.ucls new file mode 100644 index 000000000000..0706837fc075 --- /dev/null +++ b/etc/dao.ucls @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/dao.urm.puml b/etc/dao.urm.puml new file mode 100644 index 000000000000..12dfd5e51215 --- /dev/null +++ b/etc/dao.urm.puml @@ -0,0 +1,68 @@ +@startuml +package com.iluwatar.dao { + class App { + - ALL_CUSTOMERS : String {static} + - DB_URL : String {static} + - log : Logger {static} + + App() + - addCustomers(customerDao : CustomerDao) {static} + - createDataSource() : DataSource {static} + - createSchema(dataSource : DataSource) {static} + - deleteSchema(dataSource : DataSource) {static} + + generateSampleCustomers() : List {static} + + main(args : String[]) {static} + - performOperationsUsing(customerDao : CustomerDao) {static} + } + class Customer { + - firstName : String + - id : int + - lastName : String + + Customer(id : int, firstName : String, lastName : String) + + equals(that : Object) : boolean + + getFirstName() : String + + getId() : int + + getLastName() : String + + hashCode() : int + + setFirstName(firstName : String) + + setId(id : int) + + setLastName(lastName : String) + + toString() : String + } + interface CustomerDao { + + add(Customer) : boolean {abstract} + + delete(Customer) : boolean {abstract} + + getAll() : Stream {abstract} + + getById(int) : Optional {abstract} + + update(Customer) : boolean {abstract} + } + class CustomerSchemaSql { + + CREATE_SCHEMA_SQL : String {static} + + DELETE_SCHEMA_SQL : String {static} + - CustomerSchemaSql() + } + class DbCustomerDao { + - LOGGER : Logger {static} + - dataSource : DataSource + + DbCustomerDao(dataSource : DataSource) + + add(customer : Customer) : boolean + - createCustomer(resultSet : ResultSet) : Customer + + delete(customer : Customer) : boolean + + getAll() : Stream + + getById(id : int) : Optional + - getConnection() : Connection + - mutedClose(connection : Connection, statement : PreparedStatement, resultSet : ResultSet) + + update(customer : Customer) : boolean + } + class InMemoryCustomerDao { + - idToCustomer : Map + + InMemoryCustomerDao() + + add(customer : Customer) : boolean + + delete(customer : Customer) : boolean + + getAll() : Stream + + getById(id : int) : Optional + + update(customer : Customer) : boolean + } +} +DbCustomerDao ..|> CustomerDao +InMemoryCustomerDao ..|> CustomerDao +@enduml \ No newline at end of file diff --git a/etc/data-bus.urm.png b/etc/data-bus.urm.png new file mode 100644 index 000000000000..8bd2148174e4 Binary files /dev/null and b/etc/data-bus.urm.png differ diff --git a/etc/data-bus.urm.puml b/etc/data-bus.urm.puml new file mode 100644 index 000000000000..8ca7f85efb11 --- /dev/null +++ b/etc/data-bus.urm.puml @@ -0,0 +1,82 @@ +@startuml +package com.iluwatar.databus { + class AbstractDataType { + - dataBus : DataBus + + AbstractDataType() + + getDataBus() : DataBus + + setDataBus(dataBus : DataBus) + } + ~class App { + ~ App() + + main(args : String[]) {static} + } + class DataBus { + - INSTANCE : DataBus {static} + - listeners : Set + + DataBus() + + getInstance() : DataBus {static} + + publish(event : DataType) + + subscribe(member : Member) + + unsubscribe(member : Member) + } + interface DataType { + + getDataBus() : DataBus {abstract} + + setDataBus(DataBus) {abstract} + } + interface Member { + + accept(DataType) {abstract} + } +} +package com.iluwatar.databus.data { + class MessageData { + - message : String + + MessageData(message : String) + + getMessage() : String + + of(message : String) : DataType {static} + } + class StartingData { + - when : LocalDateTime + + StartingData(when : LocalDateTime) + + getWhen() : LocalDateTime + + of(when : LocalDateTime) : DataType {static} + } + class StoppingData { + - when : LocalDateTime + + StoppingData(when : LocalDateTime) + + getWhen() : LocalDateTime + + of(when : LocalDateTime) : DataType {static} + } +} +package com.iluwatar.databus.members { + class MessageCollectorMember { + - LOGGER : Logger {static} + - messages : List + - name : String + + MessageCollectorMember(name : String) + + accept(data : DataType) + + getMessages() : List + - handleEvent(data : MessageData) + } + class StatusMember { + - LOGGER : Logger {static} + - id : int + - started : LocalDateTime + - stopped : LocalDateTime + + StatusMember(id : int) + + accept(data : DataType) + + getStarted() : LocalDateTime + + getStopped() : LocalDateTime + - handleEvent(data : StartingData) + - handleEvent(data : StoppingData) + } +} +AbstractDataType --> "-dataBus" DataBus +DataBus --> "-INSTANCE" DataBus +DataBus --> "-listeners" Member +AbstractDataType ..|> DataType +MessageData --|> AbstractDataType +StartingData --|> AbstractDataType +StoppingData --|> AbstractDataType +MessageCollectorMember ..|> Member +StatusMember ..|> Member +@enduml \ No newline at end of file diff --git a/etc/data-locality.urm.png b/etc/data-locality.urm.png new file mode 100644 index 000000000000..d19873739551 Binary files /dev/null and b/etc/data-locality.urm.png differ diff --git a/etc/data-locality.urm.puml b/etc/data-locality.urm.puml new file mode 100644 index 000000000000..1e2d3e6793cb --- /dev/null +++ b/etc/data-locality.urm.puml @@ -0,0 +1,80 @@ +@startuml +package com.iluwatar.data.locality.game.component.manager { + class AiComponentManager { + - AI_COMPONENTS : Component[] {static} + - LOGGER : Logger {static} + - MAX_ENTITIES : int {static} + - numEntities : int + + AiComponentManager(numEntities : int) + + start() + + update() + } + class PhysicsComponentManager { + - LOGGER : Logger {static} + - MAX_ENTITIES : int {static} + - PHYSICS_COMPONENTS : Component[] {static} + - numEntities : int + + PhysicsComponentManager(numEntities : int) + + start() + + update() + } + class RenderComponentManager { + - LOGGER : Logger {static} + - MAX_ENTITIES : int {static} + - RENDER_COMPONENTS : Component[] {static} + - numEntities : int + + RenderComponentManager(numEntities : int) + + render() + + start() + } +} +package com.iluwatar.data.locality { + class Application { + - LOGGER : Logger {static} + - NUM_ENTITIES : int {static} + + Application() + + main(args : String[]) {static} + } +} +package com.iluwatar.data.locality.game { + class GameEntity { + - LOGGER : Logger {static} + - aiComponentManager : AiComponentManager + - physicsComponentManager : PhysicsComponentManager + - renderComponentManager : RenderComponentManager + + GameEntity(numEntities : int) + + start() + + update() + } +} +package com.iluwatar.data.locality.game.component { + class AiComponent { + - LOGGER : Logger {static} + + AiComponent() + + render() + + update() + } + interface Component { + + render() {abstract} + + update() {abstract} + } + class PhysicsComponent { + - LOGGER : Logger {static} + + PhysicsComponent() + + render() + + update() + } + class RenderComponent { + - LOGGER : Logger {static} + + RenderComponent() + + render() + + update() + } +} +GameEntity --> "-physicsComponentManager" PhysicsComponentManager +GameEntity --> "-aiComponentManager" AiComponentManager +GameEntity --> "-renderComponentManager" RenderComponentManager +AiComponent ..|> Component +PhysicsComponent ..|> Component +RenderComponent ..|> Component +@enduml \ No newline at end of file diff --git a/etc/data-mapper.png b/etc/data-mapper.png new file mode 100644 index 000000000000..bcda8054aac8 Binary files /dev/null and b/etc/data-mapper.png differ diff --git a/etc/data-mapper.ucls b/etc/data-mapper.ucls new file mode 100644 index 000000000000..2467983ce212 --- /dev/null +++ b/etc/data-mapper.ucls @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/data-mapper.urm.puml b/etc/data-mapper.urm.puml new file mode 100644 index 000000000000..3b32411d11c9 --- /dev/null +++ b/etc/data-mapper.urm.puml @@ -0,0 +1,43 @@ +@startuml +package com.iluwatar.datamapper { + class App { + - STUDENT_STRING : String {static} + - log : Logger {static} + - App() + + main(args : String[]) {static} + } + class Student { + - grade : char + - name : String + - serialVersionUID : long {static} + - studentId : int + + Student(studentId : int, name : String, grade : char) + + equals(inputObject : Object) : boolean + + getGrade() : char + + getName() : String + + getStudentId() : int + + hashCode() : int + + setGrade(grade : char) + + setName(name : String) + + setStudentId(studentId : int) + + toString() : String + } + interface StudentDataMapper { + + delete(Student) {abstract} + + find(int) : Optional {abstract} + + insert(Student) {abstract} + + update(Student) {abstract} + } + class StudentDataMapperImpl { + - students : List + + StudentDataMapperImpl() + + delete(studentToBeDeleted : Student) + + find(studentId : int) : Optional + + getStudents() : List + + insert(studentToBeInserted : Student) + + update(studentToBeUpdated : Student) + } +} +StudentDataMapperImpl --> "-students" Student +StudentDataMapperImpl ..|> StudentDataMapper +@enduml \ No newline at end of file diff --git a/etc/data-transfer-object.ucls b/etc/data-transfer-object.ucls new file mode 100644 index 000000000000..66236f32dd14 --- /dev/null +++ b/etc/data-transfer-object.ucls @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/data-transfer-object.urm.png b/etc/data-transfer-object.urm.png new file mode 100644 index 000000000000..46facff8dee4 Binary files /dev/null and b/etc/data-transfer-object.urm.png differ diff --git a/etc/data-transfer-object.urm.puml b/etc/data-transfer-object.urm.puml new file mode 100644 index 000000000000..ee96c37ca967 --- /dev/null +++ b/etc/data-transfer-object.urm.puml @@ -0,0 +1,27 @@ +@startuml +package com.iluwatar.datatransfer { + class CustomerClientApp { + - LOGGER : Logger {static} + + CustomerClientApp() + + main(args : String[]) {static} + - printCustomerDetails(allCustomers : List) {static} + } + class CustomerDto { + - firstName : String + - id : String + - lastName : String + + CustomerDto(id : String, firstName : String, lastName : String) + + getFirstName() : String + + getId() : String + + getLastName() : String + } + class CustomerResource { + - customers : List + + CustomerResource(customers : List) + + delete(customerId : String) + + getAllCustomers() : List + + save(customer : CustomerDto) + } +} +CustomerResource --> "-customers" CustomerDto +@enduml \ No newline at end of file diff --git a/etc/data/test.txt b/etc/data/test.txt new file mode 100644 index 000000000000..2f10a4d2c5c7 --- /dev/null +++ b/etc/data/test.txt @@ -0,0 +1,27 @@ +==== + This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + + The MIT License + Copyright © 2014-2022 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. +==== + +Test line 1 +Test line 2 \ No newline at end of file diff --git a/etc/decorator.urm.png b/etc/decorator.urm.png new file mode 100644 index 000000000000..141c0563f0c6 Binary files /dev/null and b/etc/decorator.urm.png differ diff --git a/etc/decorator.urm.puml b/etc/decorator.urm.puml new file mode 100644 index 000000000000..edfd927600f5 --- /dev/null +++ b/etc/decorator.urm.puml @@ -0,0 +1,32 @@ +@startuml +package com.iluwatar.decorator { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class ClubbedTroll { + - LOGGER : Logger {static} + - decorated : Troll + + ClubbedTroll(decorated : Troll) + + attack() + + fleeBattle() + + getAttackPower() : int + } + class SimpleTroll { + - LOGGER : Logger {static} + + SimpleTroll() + + attack() + + fleeBattle() + + getAttackPower() : int + } + interface Troll { + + attack() {abstract} + + fleeBattle() {abstract} + + getAttackPower() : int {abstract} + } +} +ClubbedTroll --> "-decorated" Troll +ClubbedTroll ..|> Troll +SimpleTroll ..|> Troll +@enduml \ No newline at end of file diff --git a/etc/delegation.png b/etc/delegation.png new file mode 100644 index 000000000000..375ef4d6b00f Binary files /dev/null and b/etc/delegation.png differ diff --git a/etc/delegation.ucls b/etc/delegation.ucls new file mode 100644 index 000000000000..e3ce088737b2 --- /dev/null +++ b/etc/delegation.ucls @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/delegation.urm.puml b/etc/delegation.urm.puml new file mode 100644 index 000000000000..169f7103f061 --- /dev/null +++ b/etc/delegation.urm.puml @@ -0,0 +1,39 @@ +@startuml +package com.iluwatar.delegation.simple.printers { + class CanonPrinter { + - LOGGER : Logger {static} + + CanonPrinter() + + print(message : String) + } + class EpsonPrinter { + - LOGGER : Logger {static} + + EpsonPrinter() + + print(message : String) + } + class HpPrinter { + - LOGGER : Logger {static} + + HpPrinter() + + print(message : String) + } +} +package com.iluwatar.delegation.simple { + class App { + - MESSAGE_TO_PRINT : String {static} + + App() + + main(args : String[]) {static} + } + interface Printer { + + print(String) {abstract} + } + class PrinterController { + - printer : Printer + + PrinterController(printer : Printer) + + print(message : String) + } +} +PrinterController --> "-printer" Printer +PrinterController ..|> Printer +CanonPrinter ..|> Printer +EpsonPrinter ..|> Printer +HpPrinter ..|> Printer +@enduml \ No newline at end of file diff --git a/etc/dependency-injection.png b/etc/dependency-injection.png new file mode 100644 index 000000000000..2a92c9eb228b Binary files /dev/null and b/etc/dependency-injection.png differ diff --git a/etc/dependency-injection.ucls b/etc/dependency-injection.ucls new file mode 100644 index 000000000000..d44c91e5717e --- /dev/null +++ b/etc/dependency-injection.ucls @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/dependency-injection.urm.puml b/etc/dependency-injection.urm.puml new file mode 100644 index 000000000000..84ed3c6dd321 --- /dev/null +++ b/etc/dependency-injection.urm.puml @@ -0,0 +1,57 @@ +@startuml +package com.iluwatar.dependency.injection { + class AdvancedSorceress { + - tobacco : Tobacco + + AdvancedSorceress() + + setTobacco(tobacco : Tobacco) + + smoke() + } + class AdvancedWizard { + - tobacco : Tobacco + + AdvancedWizard(tobacco : Tobacco) + + smoke() + } + class App { + + App() + + main(args : String[]) {static} + } + class GuiceWizard { + - tobacco : Tobacco + + GuiceWizard(tobacco : Tobacco) + + smoke() + } + class OldTobyTobacco { + + OldTobyTobacco() + } + class RivendellTobacco { + + RivendellTobacco() + } + class SecondBreakfastTobacco { + + SecondBreakfastTobacco() + } + class SimpleWizard { + - tobacco : OldTobyTobacco + + SimpleWizard() + + smoke() + } + abstract class Tobacco { + - LOGGER : Logger {static} + + Tobacco() + + smoke(wizard : Wizard) + } + interface Wizard { + + smoke() {abstract} + } +} +AdvancedSorceress --> "-tobacco" Tobacco +SimpleWizard --> "-tobacco" OldTobyTobacco +AdvancedWizard --> "-tobacco" Tobacco +GuiceWizard --> "-tobacco" Tobacco +AdvancedSorceress ..|> Wizard +AdvancedWizard ..|> Wizard +GuiceWizard ..|> Wizard +OldTobyTobacco --|> Tobacco +RivendellTobacco --|> Tobacco +SecondBreakfastTobacco --|> Tobacco +SimpleWizard ..|> Wizard +@enduml \ No newline at end of file diff --git a/etc/dirty-flag.png b/etc/dirty-flag.png new file mode 100644 index 000000000000..98d4f679d17c Binary files /dev/null and b/etc/dirty-flag.png differ diff --git a/etc/dirty-flag.ucls b/etc/dirty-flag.ucls new file mode 100644 index 000000000000..760d456f731d --- /dev/null +++ b/etc/dirty-flag.ucls @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/dirty-flag.urm.puml b/etc/dirty-flag.urm.puml new file mode 100644 index 000000000000..9685d3fdfbe4 --- /dev/null +++ b/etc/dirty-flag.urm.puml @@ -0,0 +1,25 @@ +@startuml +package com.iluwatar.dirtyflag { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + + run() + } + class DataFetcher { + - LOGGER : Logger {static} + - filename : String + - lastFetched : long + + DataFetcher() + + fetch() : List + - isDirty(fileLastModified : long) : boolean + } + class World { + - countries : List + - df : DataFetcher + + World() + + fetch() : List + } +} +World --> "-df" DataFetcher +@enduml \ No newline at end of file diff --git a/etc/domain-model.urm.png b/etc/domain-model.urm.png new file mode 100644 index 000000000000..9ba7e0ca484a Binary files /dev/null and b/etc/domain-model.urm.png differ diff --git a/etc/domain-model.urm.puml b/etc/domain-model.urm.puml new file mode 100644 index 000000000000..03a6a65dfea5 --- /dev/null +++ b/etc/domain-model.urm.puml @@ -0,0 +1,87 @@ +@startuml +package com.iluwatar.domainmodel { + class App { + + CREATE_SCHEMA_SQL : String {static} + + DELETE_SCHEMA_SQL : String {static} + + H2_DB_URL : String {static} + + App() + - createDataSource() : DataSource {static} + - createSchema(dataSource : DataSource) {static} + - deleteSchema(dataSource : DataSource) {static} + + main(args : String[]) {static} + } + class Customer { + - customerDao : CustomerDao + - money : Money + - name : String + - purchases : List + ~ Customer(customerDao : CustomerDao, purchases : List, name : String, money : Money) + + builder() : CustomerBuilder {static} + + buyProduct(product : Product) + + getCustomerDao() : CustomerDao + + getMoney() : Money + + getName() : String + + getPurchases() : List + - receiveMoney(amount : Money) + + returnProduct(product : Product) + + save() + + setMoney(money : Money) + + setName(name : String) + + setPurchases(purchases : List) + + showBalance() + + showPurchases() + - withdraw(amount : Money) + } + interface CustomerDao { + + addProduct(Product, Customer) {abstract} + + deleteProduct(Product, Customer) {abstract} + + findByName(String) : Optional {abstract} + + save(Customer) {abstract} + + update(Customer) {abstract} + } + class CustomerDaoImpl { + - dataSource : DataSource + + CustomerDaoImpl(userDataSource : DataSource) + + addProduct(product : Product, customer : Customer) + + deleteProduct(product : Product, customer : Customer) + + findByName(name : String) : Optional + + save(customer : Customer) + + update(customer : Customer) + } + class Product { + - expirationDate : LocalDate + - name : String + - price : Money + - productDao : ProductDao + + Product(productDao : ProductDao, name : String, price : Money, expirationDate : LocalDate) + + builder() : ProductBuilder {static} + - calculateDiscount() : Money + + getExpirationDate() : LocalDate + + getName() : String + + getPrice() : Money + + getProductDao() : ProductDao + + getSalePrice() : Money + + save() + + setExpirationDate(expirationDate : LocalDate) + + setName(name : String) + + setPrice(price : Money) + } + interface ProductDao { + + findByName(String) : Optional {abstract} + + save(Product) {abstract} + + update(Product) {abstract} + } + class ProductDaoImpl { + - dataSource : DataSource + + ProductDaoImpl(userDataSource : DataSource) + + findByName(name : String) : Optional + + save(product : Product) + + update(product : Product) + } +} +Product --> ProductDao +Customer --> CustomerDao +Customer --> Product +CustomerDaoImpl ..|> CustomerDao +ProductDaoImpl ..|> ProductDao +@enduml \ No newline at end of file diff --git a/etc/double-buffer.urm.png b/etc/double-buffer.urm.png new file mode 100644 index 000000000000..072ec4dad8be Binary files /dev/null and b/etc/double-buffer.urm.png differ diff --git a/etc/double-buffer.urm.puml b/etc/double-buffer.urm.puml new file mode 100644 index 000000000000..7555c972b5ed --- /dev/null +++ b/etc/double-buffer.urm.puml @@ -0,0 +1,45 @@ +@startuml +package com.iluwatar.doublebuffer { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + - printBlackPixelCoordinate(buffer : Buffer) {static} + } + interface Buffer { + + clear(int, int) {abstract} + + clearAll() {abstract} + + draw(int, int) {abstract} + + getPixels() : Pixel[] {abstract} + } + class FrameBuffer { + + HEIGHT : int {static} + + WIDTH : int {static} + - pixels : Pixel[] + + FrameBuffer() + + clear(x : int, y : int) + + clearAll() + + draw(x : int, y : int) + - getIndex(x : int, y : int) : int + + getPixels() : Pixel[] + } + enum Pixel { + + BLACK {static} + + WHITE {static} + - color : int + + valueOf(name : String) : Pixel {static} + + values() : Pixel[] {static} + } + class Scene { + - LOGGER : Logger {static} + - current : int + - frameBuffers : Buffer[] + - next : int + + Scene() + + draw(coordinateList : List>) + + getBuffer() : Buffer + - swap() + } +} +FrameBuffer ..|> Buffer +@enduml \ No newline at end of file diff --git a/etc/double-checked-locking.png b/etc/double-checked-locking.png new file mode 100644 index 000000000000..4c652e27aa67 Binary files /dev/null and b/etc/double-checked-locking.png differ diff --git a/etc/double-checked-locking.ucls b/etc/double-checked-locking.ucls new file mode 100644 index 000000000000..3ec1792287a6 --- /dev/null +++ b/etc/double-checked-locking.ucls @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/double-checked-locking.urm.puml b/etc/double-checked-locking.urm.puml new file mode 100644 index 000000000000..242519fce77c --- /dev/null +++ b/etc/double-checked-locking.urm.puml @@ -0,0 +1,22 @@ +@startuml +package com.iluwatar.doublechecked.locking { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Inventory { + - LOGGER : Logger {static} + - inventorySize : int + - items : List + - lock : Lock + + Inventory(inventorySize : int) + + addItem(item : Item) : boolean + + getItems() : List + } + class Item { + + Item() + } +} +Inventory --> "-items" Item +@enduml \ No newline at end of file diff --git a/etc/double-dispatch.png b/etc/double-dispatch.png new file mode 100644 index 000000000000..9ee77b499cd8 Binary files /dev/null and b/etc/double-dispatch.png differ diff --git a/etc/double-dispatch.ucls b/etc/double-dispatch.ucls new file mode 100644 index 000000000000..498f77bfc382 --- /dev/null +++ b/etc/double-dispatch.ucls @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/double-dispatch.urm.puml b/etc/double-dispatch.urm.puml new file mode 100644 index 000000000000..17bcb1431bd6 --- /dev/null +++ b/etc/double-dispatch.urm.puml @@ -0,0 +1,74 @@ +@startuml +package com.iluwatar.doubledispatch.constants { + class AppConstants { + + HITS : String {static} + + AppConstants() + } +} +package com.iluwatar.doubledispatch { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class FlamingAsteroid { + + FlamingAsteroid(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + } + abstract class GameObject { + - damaged : boolean + - onFire : boolean + + GameObject(left : int, top : int, right : int, bottom : int) + + collision(GameObject) {abstract} + + collisionResolve(FlamingAsteroid) {abstract} + + collisionResolve(Meteoroid) {abstract} + + collisionResolve(SpaceStationIss) {abstract} + + collisionResolve(SpaceStationMir) {abstract} + + isDamaged() : boolean + + isOnFire() : boolean + + setDamaged(damaged : boolean) + + setOnFire(onFire : boolean) + + toString() : String + } + class Meteoroid { + - LOGGER : Logger {static} + + Meteoroid(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + + collisionResolve(asteroid : FlamingAsteroid) + + collisionResolve(iss : SpaceStationIss) + + collisionResolve(meteoroid : Meteoroid) + + collisionResolve(mir : SpaceStationMir) + } + class Rectangle { + - bottom : int + - left : int + - right : int + - top : int + + Rectangle(left : int, top : int, right : int, bottom : int) + + getBottom() : int + + getLeft() : int + + getRight() : int + + getTop() : int + ~ intersectsWith(r : Rectangle) : boolean + + toString() : String + } + class SpaceStationIss { + + SpaceStationIss(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + } + class SpaceStationMir { + - LOGGER : Logger {static} + + SpaceStationMir(left : int, top : int, right : int, bottom : int) + + collision(gameObject : GameObject) + + collisionResolve(asteroid : FlamingAsteroid) + + collisionResolve(iss : SpaceStationIss) + + collisionResolve(meteoroid : Meteoroid) + + collisionResolve(mir : SpaceStationMir) + } +} +FlamingAsteroid --|> Meteoroid +GameObject --|> Rectangle +Meteoroid --|> GameObject +SpaceStationIss --|> SpaceStationMir +SpaceStationMir --|> GameObject +@enduml \ No newline at end of file diff --git a/etc/double_checked_locking_1.png b/etc/double_checked_locking_1.png new file mode 100644 index 000000000000..cced091b9d67 Binary files /dev/null and b/etc/double_checked_locking_1.png differ diff --git a/etc/eda.png b/etc/eda.png new file mode 100644 index 000000000000..743726451802 Binary files /dev/null and b/etc/eda.png differ diff --git a/etc/eda.ucls b/etc/eda.ucls new file mode 100644 index 000000000000..776bedc81920 --- /dev/null +++ b/etc/eda.ucls @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/eip-aggregator.urm.puml b/etc/eip-aggregator.urm.puml new file mode 100644 index 000000000000..4d8661e210c2 --- /dev/null +++ b/etc/eip-aggregator.urm.puml @@ -0,0 +1,14 @@ +@startuml +package com.iluwatar.eip.aggregator { + class App { + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.eip.aggregator.routes { + class MessageAggregationStrategy { + + MessageAggregationStrategy() + + aggregate(oldExchange : Exchange, newExchange : Exchange) : Exchange + } +} +@enduml \ No newline at end of file diff --git a/etc/eip-message-channel.urm.puml b/etc/eip-message-channel.urm.puml new file mode 100644 index 000000000000..38e2369ce562 --- /dev/null +++ b/etc/eip-message-channel.urm.puml @@ -0,0 +1,9 @@ +@startuml +package com.iluwatar.eip.message.channel { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/eip-publish-subscribe.urm.puml b/etc/eip-publish-subscribe.urm.puml new file mode 100644 index 000000000000..a201f59bba67 --- /dev/null +++ b/etc/eip-publish-subscribe.urm.puml @@ -0,0 +1,9 @@ +@startuml +package com.iluwatar.eip.publish.subscribe { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/eip-splitter.urm.puml b/etc/eip-splitter.urm.puml new file mode 100644 index 000000000000..ad063b709c3d --- /dev/null +++ b/etc/eip-splitter.urm.puml @@ -0,0 +1,8 @@ +@startuml +package com.iluwatar.eip.splitter { + class App { + + App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/eip-wire-tap.urm.puml b/etc/eip-wire-tap.urm.puml new file mode 100644 index 000000000000..51ee99723cc8 --- /dev/null +++ b/etc/eip-wire-tap.urm.puml @@ -0,0 +1,8 @@ +@startuml +package com.iluwatar.eip.wiretap { + class App { + + App() + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/event-aggregator.urm.puml b/etc/event-aggregator.urm.puml new file mode 100644 index 000000000000..341d7d65e02c --- /dev/null +++ b/etc/event-aggregator.urm.puml @@ -0,0 +1,74 @@ +@startuml +package com.iluwatar.event.aggregator { + class App { + + App() + + main(args : String[]) {static} + } + enum Event { + + STARK_SIGHTED {static} + + TRAITOR_DETECTED {static} + + WARSHIPS_APPROACHING {static} + - description : String + + toString() : String + + valueOf(name : String) : Event {static} + + values() : Event[] {static} + } + abstract class EventEmitter { + - observers : List + + EventEmitter() + + EventEmitter(obs : EventObserver) + # notifyObservers(e : Event) + + registerObserver(obs : EventObserver) + + timePasses(Weekday) {abstract} + } + interface EventObserver { + + onEvent(Event) {abstract} + } + class KingJoffrey { + - LOGGER : Logger {static} + + KingJoffrey() + + onEvent(e : Event) + } + class KingsHand { + + KingsHand() + + KingsHand(obs : EventObserver) + + onEvent(e : Event) + + timePasses(day : Weekday) + } + class LordBaelish { + + LordBaelish() + + LordBaelish(obs : EventObserver) + + timePasses(day : Weekday) + } + class LordVarys { + + LordVarys() + + LordVarys(obs : EventObserver) + + timePasses(day : Weekday) + } + class Scout { + + Scout() + + Scout(obs : EventObserver) + + timePasses(day : Weekday) + } + enum Weekday { + + FRIDAY {static} + + MONDAY {static} + + SATURDAY {static} + + SUNDAY {static} + + THURSDAY {static} + + TUESDAY {static} + + WEDNESDAY {static} + - description : String + + toString() : String + + valueOf(name : String) : Weekday {static} + + values() : Weekday[] {static} + } +} +EventEmitter --> "-observers" EventObserver +KingJoffrey ..|> EventObserver +KingsHand ..|> EventObserver +KingsHand --|> EventEmitter +LordBaelish --|> EventEmitter +LordVarys --|> EventEmitter +Scout --|> EventEmitter +@enduml \ No newline at end of file diff --git a/etc/event-asynchronous.png b/etc/event-asynchronous.png new file mode 100644 index 000000000000..76cb1b626972 Binary files /dev/null and b/etc/event-asynchronous.png differ diff --git a/etc/event-asynchronous.ucls b/etc/event-asynchronous.ucls new file mode 100644 index 000000000000..1327b7104459 --- /dev/null +++ b/etc/event-asynchronous.ucls @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/event-asynchronous.urm.puml b/etc/event-asynchronous.urm.puml new file mode 100644 index 000000000000..3a896c32f59f --- /dev/null +++ b/etc/event-asynchronous.urm.puml @@ -0,0 +1,70 @@ +@startuml +package com.iluwatar.event.asynchronous { + class App { + - LOGGER : Logger {static} + + PROP_FILE_NAME : String {static} + ~ interactiveMode : boolean + + App() + + main(args : String[]) {static} + - processOption1(eventManager : EventManager, s : Scanner) + - processOption2(eventManager : EventManager, s : Scanner) + - processOption3(eventManager : EventManager, s : Scanner) + + quickRun() + + run() + + runInteractiveMode() + + setUp() + } + class Event { + - LOGGER : Logger {static} + - eventId : int + - eventListener : ThreadCompleteListener + - eventTime : int + - isComplete : boolean + - isSynchronous : boolean + - thread : Thread + + Event(eventId : int, eventTime : int, isSynchronous : boolean) + + addListener(listener : ThreadCompleteListener) + - completed() + + isSynchronous() : boolean + + removeListener(listener : ThreadCompleteListener) + + run() + + start() + + status() + + stop() + } + class EventManager { + - DOES_NOT_EXIST : String {static} + + MAX_EVENT_TIME : int {static} + + MAX_ID : int {static} + + MAX_RUNNING_EVENTS : int {static} + + MIN_ID : int {static} + - currentlyRunningSyncEvent : int + - eventPool : Map + - rand : Random + + EventManager() + + cancel(eventId : int) + + completedEventHandler(eventId : int) + + create(eventTime : int) : int + + createAsync(eventTime : int) : int + - createEvent(eventTime : int, isSynchronous : boolean) : int + - generateId() : int + + getEventPool() : Map + + numOfCurrentlyRunningSyncEvent() : int + + shutdown() + + start(eventId : int) + + status(eventId : int) + + statusOfAllEvents() + } + interface IEvent { + + start() {abstract} + + status() {abstract} + + stop() {abstract} + } + interface ThreadCompleteListener { + + completedEventHandler(int) {abstract} + } +} +Event --> "-eventListener" ThreadCompleteListener +Event ..|> IEvent +EventManager ..|> ThreadCompleteListener +@enduml \ No newline at end of file diff --git a/etc/event-driven-architecture.urm.puml b/etc/event-driven-architecture.urm.puml new file mode 100644 index 000000000000..6b67f0a0e569 --- /dev/null +++ b/etc/event-driven-architecture.urm.puml @@ -0,0 +1,64 @@ +@startuml +package com.iluwatar.eda.handler { + class UserCreatedEventHandler { + - LOGGER : Logger {static} + + UserCreatedEventHandler() + + onEvent(event : UserCreatedEvent) + } + class UserUpdatedEventHandler { + - LOGGER : Logger {static} + + UserUpdatedEventHandler() + + onEvent(event : UserUpdatedEvent) + } +} +package com.iluwatar.eda.event { + abstract class AbstractEvent { + + AbstractEvent() + + getType() : Class + } + class UserCreatedEvent { + - user : User + + UserCreatedEvent(user : User) + + getUser() : User + } + class UserUpdatedEvent { + - user : User + + UserUpdatedEvent(user : User) + + getUser() : User + } +} +package com.iluwatar.eda.framework { + interface Event { + + getType() : Class {abstract} + } + class EventDispatcher { + - handlers : Map, Handler> + + EventDispatcher() + + dispatch(event : E extends Event) + + registerHandler(eventType : Class, handler : Handler) + } + interface Handler { + + onEvent(E extends Event) {abstract} + } +} +package com.iluwatar.eda.model { + class User { + - username : String + + User(username : String) + + getUsername() : String + } +} +package com.iluwatar.eda { + class App { + + App() + + main(args : String[]) {static} + } +} +UserCreatedEvent --> "-user" User +UserUpdatedEvent --> "-user" User +AbstractEvent ..|> Event +UserCreatedEvent --|> AbstractEvent +UserUpdatedEvent --|> AbstractEvent +UserCreatedEventHandler ..|> Handler +UserUpdatedEventHandler ..|> Handler +@enduml \ No newline at end of file diff --git a/etc/event-queue-model.png b/etc/event-queue-model.png new file mode 100644 index 000000000000..c3f9c4ddb3d7 Binary files /dev/null and b/etc/event-queue-model.png differ diff --git a/etc/event-queue.urm.puml b/etc/event-queue.urm.puml new file mode 100644 index 000000000000..de4390e4e599 --- /dev/null +++ b/etc/event-queue.urm.puml @@ -0,0 +1,38 @@ +@startuml +package com.iluwatar.event.queue { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Audio { + - INSTANCE : Audio {static} + - LOGGER : Logger {static} + - MAX_PENDING : int {static} + - headIndex : int + - pendingAudio : PlayMessage[] + - tailIndex : int + - updateThread : Thread + ~ Audio() + + getAudioStream(filePath : String) : AudioInputStream + + getInstance() : Audio {static} + + getPendingAudio() : PlayMessage[] + + init() + + isServiceRunning() : boolean + + playSound(stream : AudioInputStream, volume : float) + - startThread() + + stopService() + - update() + } + class PlayMessage { + - stream : AudioInputStream + - volume : float + + PlayMessage(stream : AudioInputStream, volume : float) + + getStream() : AudioInputStream + + getVolume() : float + - setStream(stream : AudioInputStream) + + setVolume(volume : float) + } +} +Audio --> "-INSTANCE" Audio +@enduml \ No newline at end of file diff --git a/etc/event-sourcing.png b/etc/event-sourcing.png new file mode 100644 index 000000000000..0b0098546300 Binary files /dev/null and b/etc/event-sourcing.png differ diff --git a/etc/event-sourcing.ucls b/etc/event-sourcing.ucls new file mode 100644 index 000000000000..2df56a4796da --- /dev/null +++ b/etc/event-sourcing.ucls @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/event-sourcing.urm.puml b/etc/event-sourcing.urm.puml new file mode 100644 index 000000000000..363af9967012 --- /dev/null +++ b/etc/event-sourcing.urm.puml @@ -0,0 +1,107 @@ +@startuml +package com.iluwatar.event.sourcing.processor { + class DomainEventProcessor { + - processorJournal : JsonFileJournal + + DomainEventProcessor() + + process(domainEvent : DomainEvent) + + recover() + + reset() + } + class JsonFileJournal { + - events : List + - file : File + - index : int + + JsonFileJournal() + + readNext() : DomainEvent + + reset() + + write(domainEvent : DomainEvent) + } +} +package com.iluwatar.event.sourcing.event { + class AccountCreateEvent { + - accountNo : int + - owner : String + + AccountCreateEvent(sequenceId : long, createdTime : long, accountNo : int, owner : String) + + getAccountNo() : int + + getOwner() : String + + process() + } + abstract class DomainEvent { + - createdTime : long + - eventClassName : String + - realTime : boolean + - sequenceId : long + + DomainEvent(sequenceId : long, createdTime : long, eventClassName : String) + + getCreatedTime() : long + + getEventClassName() : String + + getSequenceId() : long + + isRealTime() : boolean + + process() {abstract} + + setRealTime(realTime : boolean) + } + class MoneyDepositEvent { + - accountNo : int + - money : BigDecimal + + MoneyDepositEvent(sequenceId : long, createdTime : long, accountNo : int, money : BigDecimal) + + getAccountNo() : int + + getMoney() : BigDecimal + + process() + } + class MoneyTransferEvent { + - accountNoFrom : int + - accountNoTo : int + - money : BigDecimal + + MoneyTransferEvent(sequenceId : long, createdTime : long, money : BigDecimal, accountNoFrom : int, accountNoTo : int) + + getAccountNoFrom() : int + + getAccountNoTo() : int + + getMoney() : BigDecimal + + process() + } +} +package com.iluwatar.event.sourcing.app { + class App { + + ACCOUNT_OF_DAENERYS : int {static} + + ACCOUNT_OF_JON : int {static} + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.event.sourcing.state { + class AccountAggregate { + - accounts : Map {static} + - AccountAggregate() + + getAccount(accountNo : int) : Account {static} + + putAccount(account : Account) {static} + + resetState() {static} + } +} +package com.iluwatar.event.sourcing.domain { + class Account { + - LOGGER : Logger {static} + - MSG : String {static} + - accountNo : int + - money : BigDecimal + - owner : String + + Account(accountNo : int, owner : String) + + copy() : Account + - depositMoney(money : BigDecimal) + + getAccountNo() : int + + getMoney() : BigDecimal + + getOwner() : String + - handleDeposit(money : BigDecimal, realTime : boolean) + + handleEvent(accountCreateEvent : AccountCreateEvent) + + handleEvent(moneyDepositEvent : MoneyDepositEvent) + + handleTransferFromEvent(moneyTransferEvent : MoneyTransferEvent) + + handleTransferToEvent(moneyTransferEvent : MoneyTransferEvent) + - handleWithdrawal(money : BigDecimal, realTime : boolean) + + setMoney(money : BigDecimal) + + toString() : String + - withdrawMoney(money : BigDecimal) + } +} +DomainEventProcessor --> "-processorJournal" JsonFileJournal +AccountCreateEvent --|> DomainEvent +MoneyDepositEvent --|> DomainEvent +MoneyTransferEvent --|> DomainEvent +@enduml \ No newline at end of file diff --git a/etc/execute-around.png b/etc/execute-around.png new file mode 100644 index 000000000000..fc048919d10e Binary files /dev/null and b/etc/execute-around.png differ diff --git a/etc/execute-around.ucls b/etc/execute-around.ucls new file mode 100644 index 000000000000..680334e9bf5a --- /dev/null +++ b/etc/execute-around.ucls @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/execute-around.urm.puml b/etc/execute-around.urm.puml new file mode 100644 index 000000000000..fd01a5fe1fe9 --- /dev/null +++ b/etc/execute-around.urm.puml @@ -0,0 +1,14 @@ +@startuml +package com.iluwatar.execute.around { + class App { + + App() + + main(args : String[]) {static} + } + interface FileWriterAction { + + writeFile(FileWriter) {abstract} + } + class SimpleFileWriter { + + SimpleFileWriter(filename : String, action : FileWriterAction) + } +} +@enduml \ No newline at end of file diff --git a/etc/extension-objects.urm.puml b/etc/extension-objects.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/etc/extension-objects.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/etc/extension_obj.png b/etc/extension_obj.png new file mode 100644 index 000000000000..a2b750e9dedd Binary files /dev/null and b/etc/extension_obj.png differ diff --git a/etc/extension_obj.ucls b/etc/extension_obj.ucls new file mode 100644 index 000000000000..9471caa83dad --- /dev/null +++ b/etc/extension_obj.ucls @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/facade.urm.png b/etc/facade.urm.png new file mode 100644 index 000000000000..8e3ec7aca45e Binary files /dev/null and b/etc/facade.urm.png differ diff --git a/etc/facade.urm.puml b/etc/facade.urm.puml new file mode 100644 index 000000000000..477f9eee7e47 --- /dev/null +++ b/etc/facade.urm.puml @@ -0,0 +1,60 @@ +@startuml +package com.iluwatar.facade { + class App { + + App() + + main(args : String[]) {static} + } + class DwarvenCartOperator { + - LOGGER : Logger {static} + + DwarvenCartOperator() + + name() : String + + work() + } + class DwarvenGoldDigger { + - LOGGER : Logger {static} + + DwarvenGoldDigger() + + name() : String + + work() + } + class DwarvenGoldmineFacade { + - workers : List + + DwarvenGoldmineFacade() + + digOutGold() + + endDay() + - makeActions(workers : Collection, actions : Action[]) {static} + + startNewDay() + } + abstract class DwarvenMineWorker { + - LOGGER : Logger {static} + + DwarvenMineWorker() + - action(action : Action) + + action(actions : Action[]) + + goHome() + + goToMine() + + goToSleep() + + name() : String {abstract} + + wakeUp() + + work() {abstract} + } + ~enum Action { + + GO_HOME {static} + + GO_TO_MINE {static} + + GO_TO_SLEEP {static} + + WAKE_UP {static} + + WORK {static} + + valueOf(name : String) : Action {static} + + values() : Action[] {static} + } + class DwarvenTunnelDigger { + - LOGGER : Logger {static} + + DwarvenTunnelDigger() + + name() : String + + work() + } +} +DwarvenGoldmineFacade --> "-workers" DwarvenMineWorker +Action ..+ DwarvenMineWorker +DwarvenCartOperator --|> DwarvenMineWorker +DwarvenGoldDigger --|> DwarvenMineWorker +DwarvenTunnelDigger --|> DwarvenMineWorker +@enduml \ No newline at end of file diff --git a/etc/factory-kit.png b/etc/factory-kit.png new file mode 100644 index 000000000000..7093193cb8d0 Binary files /dev/null and b/etc/factory-kit.png differ diff --git a/etc/factory-kit.ucls b/etc/factory-kit.ucls new file mode 100644 index 000000000000..403fb7e279e4 --- /dev/null +++ b/etc/factory-kit.ucls @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/etc/factory-kit.urm.puml b/etc/factory-kit.urm.puml new file mode 100644 index 000000000000..23cf658f467e --- /dev/null +++ b/etc/factory-kit.urm.puml @@ -0,0 +1,46 @@ +@startuml +package com.iluwatar.factorykit { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Axe { + + Axe() + + toString() : String + } + class Bow { + + Bow() + + toString() : String + } + interface Builder { + + add(WeaponType, Supplier) {abstract} + } + class Spear { + + Spear() + + toString() : String + } + class Sword { + + Sword() + + toString() : String + } + interface Weapon { + } + interface WeaponFactory { + + create(WeaponType) : Weapon {abstract} + + factory(consumer : Consumer) : WeaponFactory {static} + } + enum WeaponType { + + AXE {static} + + BOW {static} + + SPEAR {static} + + SWORD {static} + + valueOf(name : String) : WeaponType {static} + + values() : WeaponType[] {static} + } +} +Axe ..|> Weapon +Bow ..|> Weapon +Spear ..|> Weapon +Sword ..|> Weapon +@enduml \ No newline at end of file diff --git a/etc/factory-method.urm.png b/etc/factory-method.urm.png new file mode 100644 index 000000000000..7c97aff91ee6 Binary files /dev/null and b/etc/factory-method.urm.png differ diff --git a/etc/factory-method.urm.puml b/etc/factory-method.urm.puml new file mode 100644 index 000000000000..a5d8d4e22f7c --- /dev/null +++ b/etc/factory-method.urm.puml @@ -0,0 +1,56 @@ +@startuml +package com.iluwatar.factory.method { + class App { + - LOGGER : Logger {static} + - blacksmith : Blacksmith + + App(blacksmith : Blacksmith) + + main(args : String[]) {static} + - manufactureWeapons() + } + interface Blacksmith { + + manufactureWeapon(WeaponType) : Weapon {abstract} + } + class ElfBlacksmith { + - ELFARSENAL : Map {static} + + ElfBlacksmith() + + manufactureWeapon(weaponType : WeaponType) : Weapon + } + class ElfWeapon { + - weaponType : WeaponType + + ElfWeapon(weaponType : WeaponType) + + getWeaponType() : WeaponType + + toString() : String + } + class OrcBlacksmith { + - ORCARSENAL : Map {static} + + OrcBlacksmith() + + manufactureWeapon(weaponType : WeaponType) : Weapon + } + class OrcWeapon { + - weaponType : WeaponType + + OrcWeapon(weaponType : WeaponType) + + getWeaponType() : WeaponType + + toString() : String + } + interface Weapon { + + getWeaponType() : WeaponType {abstract} + } + enum WeaponType { + + AXE {static} + + SHORT_SWORD {static} + + SPEAR {static} + + UNDEFINED {static} + - title : String + + toString() : String + + valueOf(name : String) : WeaponType {static} + + values() : WeaponType[] {static} + } +} +ElfWeapon --> "-weaponType" WeaponType +OrcWeapon --> "-weaponType" WeaponType +App --> "-blacksmith" Blacksmith +ElfBlacksmith ..|> Blacksmith +ElfWeapon ..|> Weapon +OrcBlacksmith ..|> Blacksmith +OrcWeapon ..|> Weapon +@enduml \ No newline at end of file diff --git a/etc/factory.urm.png b/etc/factory.urm.png new file mode 100644 index 000000000000..4b3420792e06 Binary files /dev/null and b/etc/factory.urm.png differ diff --git a/etc/factory.urm.puml b/etc/factory.urm.puml new file mode 100644 index 000000000000..eb08a4596cb4 --- /dev/null +++ b/etc/factory.urm.puml @@ -0,0 +1,36 @@ +@startuml +package com.iluwatar.factory { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + interface Coin { + + getDescription() : String {abstract} + } + class CoinFactory { + + CoinFactory() + + getCoin(type : CoinType) : Coin {static} + } + enum CoinType { + + COPPER {static} + + GOLD {static} + - constructor : Supplier + + getConstructor() : Supplier + + valueOf(name : String) : CoinType {static} + + values() : CoinType[] {static} + } + class CopperCoin { + ~ DESCRIPTION : String {static} + + CopperCoin() + + getDescription() : String + } + class GoldCoin { + ~ DESCRIPTION : String {static} + + GoldCoin() + + getDescription() : String + } +} +CopperCoin ..|> Coin +GoldCoin ..|> Coin +@enduml \ No newline at end of file diff --git a/etc/fanout-fanin.png b/etc/fanout-fanin.png new file mode 100644 index 000000000000..e4b85006cf1c Binary files /dev/null and b/etc/fanout-fanin.png differ diff --git a/etc/fanout-fanin.urm.puml b/etc/fanout-fanin.urm.puml new file mode 100644 index 000000000000..57b741335962 --- /dev/null +++ b/etc/fanout-fanin.urm.puml @@ -0,0 +1,39 @@ +@startuml +package com.iluwatar.fanout.fanin { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Consumer { + - sumOfSquaredNumbers : AtomicLong + ~ Consumer(init : Long) + + add(num : Long) : Long + + getSumOfSquaredNumbers() : AtomicLong + } + class FanOutFanIn { + + FanOutFanIn() + + fanOutFanIn(requests : List, consumer : Consumer) : Long {static} + } + class SquareNumberRequest { + - LOGGER : Logger {static} + - number : Long + + SquareNumberRequest(number : Long) + + delayedSquaring(consumer : Consumer) + } + + object SquareNumberRequest1 + object SquareNumberRequest2 + object SquareNumberRequest3 + diamond dia +} + +App --> FanOutFanIn +FanOutFanIn --> "fan out - running in parallel" SquareNumberRequest1 +FanOutFanIn --> "fan out" SquareNumberRequest2 +FanOutFanIn --> "fan out" SquareNumberRequest3 +SquareNumberRequest1 --> "fan in - aggregate using callback" dia +SquareNumberRequest2 --> "fan in" dia +SquareNumberRequest3 --> "fan in" dia +dia --> Consumer +@enduml \ No newline at end of file diff --git a/etc/feature-toggle.png b/etc/feature-toggle.png new file mode 100644 index 000000000000..5c118e57e44e Binary files /dev/null and b/etc/feature-toggle.png differ diff --git a/etc/feature-toggle.ucls b/etc/feature-toggle.ucls new file mode 100644 index 000000000000..538d3f416330 --- /dev/null +++ b/etc/feature-toggle.ucls @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/feature-toggle.urm.puml b/etc/feature-toggle.urm.puml new file mode 100644 index 000000000000..0febb26319d1 --- /dev/null +++ b/etc/feature-toggle.urm.puml @@ -0,0 +1,48 @@ +@startuml +package com.iluwatar.featuretoggle.pattern { + interface Service { + + getWelcomeMessage(User) : String {abstract} + + isEnhanced() : boolean {abstract} + } +} +package com.iluwatar.featuretoggle.user { + class User { + - name : String + + User(name : String) + + toString() : String + } + class UserGroup { + - freeGroup : List {static} + - paidGroup : List {static} + + UserGroup() + + addUserToFreeGroup(user : User) {static} + + addUserToPaidGroup(user : User) {static} + + isPaid(user : User) : boolean {static} + } +} +package com.iluwatar.featuretoggle.pattern.tieredversion { + class TieredFeatureToggleVersion { + + TieredFeatureToggleVersion() + + getWelcomeMessage(user : User) : String + + isEnhanced() : boolean + } +} +package com.iluwatar.featuretoggle.pattern.propertiesversion { + class PropertiesFeatureToggleVersion { + - isEnhanced : boolean + + PropertiesFeatureToggleVersion(properties : Properties) + + getWelcomeMessage(user : User) : String + + isEnhanced() : boolean + } +} +package com.iluwatar.featuretoggle { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } +} +UserGroup --> "-freeGroup" User +PropertiesFeatureToggleVersion ..|> Service +TieredFeatureToggleVersion ..|> Service +@enduml \ No newline at end of file diff --git a/etc/filterer.png b/etc/filterer.png new file mode 100644 index 000000000000..6a6eb059b92d Binary files /dev/null and b/etc/filterer.png differ diff --git a/etc/filterer.urm.puml b/etc/filterer.urm.puml new file mode 100644 index 000000000000..c0bb0b54d0ec --- /dev/null +++ b/etc/filterer.urm.puml @@ -0,0 +1,96 @@ +@startuml +package com.iluwatar.filterer.domain { + interface Filterer { + + by(Predicate) : G {abstract} + } +} +package com.iluwatar.filterer { + class App { + - LOGGER : Logger {static} + + App() + - filteringSimpleProbableThreats() {static} + - filteringSimpleThreats() {static} + + main(args : String[]) {static} + } +} +package com.iluwatar.filterer.threat { + interface ProbabilisticThreatAwareSystem { + + filtered() : Filterer {abstract} + + threats() : List {abstract} + } + interface ProbableThreat { + + probability() : double {abstract} + } + class SimpleProbabilisticThreatAwareSystem { + - systemId : String + - threats : ImmutableList + + SimpleProbabilisticThreatAwareSystem(systemId : String, threats : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ProbabilisticThreatAwareSystem + - filteredItems(predicate : Predicate) : List + + hashCode() : int + + systemId() : String + + threats() : List + + toString() : String + } + class SimpleProbableThreat { + - probability : double + + SimpleProbableThreat(name : String, id : int, threatType : ThreatType, probability : double) + + equals(o : Object) : boolean + + hashCode() : int + + probability() : double + + toString() : String + } + class SimpleThreat { + - id : int + - name : String + - threatType : ThreatType + + SimpleThreat(threatType : ThreatType, id : int, name : String) + + id() : int + + name() : String + + toString() : String + + type() : ThreatType + } + class SimpleThreatAwareSystem { + - issues : ImmutableList + - systemId : String + + SimpleThreatAwareSystem(systemId : String, issues : List) + + equals(o : Object) : boolean + + filtered() : Filterer + - filteredGroup(predicate : Predicate) : ThreatAwareSystem + - filteredItems(predicate : Predicate) : List + + hashCode() : int + + systemId() : String + + threats() : List + + toString() : String + } + interface Threat { + + id() : int {abstract} + + name() : String {abstract} + + type() : ThreatType {abstract} + } + interface ThreatAwareSystem { + + filtered() : Filterer {abstract} + + systemId() : String {abstract} + + threats() : List {abstract} + } + enum ThreatType { + + ROOTKIT {static} + + TROJAN {static} + + WORM {static} + + valueOf(name : String) : ThreatType {static} + + values() : ThreatType[] {static} + } +} +SimpleThreatAwareSystem --> "-issues" Threat +SimpleThreat --> "-threatType" ThreatType +SimpleProbabilisticThreatAwareSystem --> "-threats" ProbableThreat +ProbabilisticThreatAwareSystem --|> ThreatAwareSystem +ProbableThreat --|> Threat +SimpleProbabilisticThreatAwareSystem ..|> ProbabilisticThreatAwareSystem +SimpleProbableThreat ..|> ProbableThreat +SimpleProbableThreat --|> SimpleThreat +SimpleThreat ..|> Threat +SimpleThreatAwareSystem ..|> ThreatAwareSystem +@enduml \ No newline at end of file diff --git a/etc/fluentinterface.png b/etc/fluentinterface.png new file mode 100644 index 000000000000..611fec7c6e7d Binary files /dev/null and b/etc/fluentinterface.png differ diff --git a/etc/fluentinterface.ucls b/etc/fluentinterface.ucls new file mode 100644 index 000000000000..e30c45bb2432 --- /dev/null +++ b/etc/fluentinterface.ucls @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/fluentinterface.urm.puml b/etc/fluentinterface.urm.puml new file mode 100644 index 000000000000..ef71a0f4bace --- /dev/null +++ b/etc/fluentinterface.urm.puml @@ -0,0 +1,72 @@ +@startuml +package com.iluwatar.fluentinterface.fluentiterable.simple { + class SimpleFluentIterable { + - iterable : Iterable + # SimpleFluentIterable(iterable : Iterable) + + asList() : List + + filter(predicate : Predicate) : FluentIterable + + first() : Optional + + first(count : int) : FluentIterable + + forEach(action : Consumer) + + from(iterable : Iterable) : FluentIterable {static} + + fromCopyOf(iterable : Iterable) : FluentIterable {static} + + getRemainingElementsCount() : int + + iterator() : Iterator + + last() : Optional + + last(count : int) : FluentIterable + + map(function : Function) : FluentIterable + + spliterator() : Spliterator + + toList(iterator : Iterator) : List {static} + } +} +package com.iluwatar.fluentinterface.app { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + - negatives() : Predicate {static} + - positives() : Predicate {static} + - prettyPrint(delimiter : String, prefix : String, iterable : Iterable) {static} + - prettyPrint(prefix : String, iterable : Iterable) {static} + - transformToString() : Function {static} + } +} +package com.iluwatar.fluentinterface.fluentiterable.lazy { + abstract class DecoratingIterator { + # fromIterator : Iterator + - next : E + + DecoratingIterator(fromIterator : Iterator) + + computeNext() : E {abstract} + + hasNext() : boolean + + next() : E + } + class LazyFluentIterable { + - iterable : Iterable + # LazyFluentIterable() + # LazyFluentIterable(iterable : Iterable) + + asList() : List + + filter(predicate : Predicate) : FluentIterable + + first() : Optional + + first(count : int) : FluentIterable + + from(iterable : Iterable) : FluentIterable {static} + + iterator() : Iterator + + last() : Optional + + last(count : int) : FluentIterable + + map(function : Function) : FluentIterable + } +} +package com.iluwatar.fluentinterface.fluentiterable { + interface FluentIterable { + + asList() : List {abstract} + + copyToList(iterable : Iterable) : List {static} + + filter(Predicate) : FluentIterable {abstract} + + first() : Optional {abstract} + + first(int) : FluentIterable {abstract} + + last() : Optional {abstract} + + last(int) : FluentIterable {abstract} + + map(Function) : FluentIterable {abstract} + } +} +LazyFluentIterable ..|> FluentIterable +SimpleFluentIterable ..|> FluentIterable +@enduml \ No newline at end of file diff --git a/etc/flux.png b/etc/flux.png new file mode 100644 index 000000000000..9cb596eaf03d Binary files /dev/null and b/etc/flux.png differ diff --git a/etc/flux.ucls b/etc/flux.ucls new file mode 100644 index 000000000000..eb376eb5a3dc --- /dev/null +++ b/etc/flux.ucls @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/flux.urm.puml b/etc/flux.urm.puml new file mode 100644 index 000000000000..300f179764cb --- /dev/null +++ b/etc/flux.urm.puml @@ -0,0 +1,117 @@ +@startuml +package com.iluwatar.flux.view { + class ContentView { + - LOGGER : Logger {static} + - content : Content + + ContentView() + + render() + + storeChanged(store : Store) + } + class MenuView { + - LOGGER : Logger {static} + - selected : MenuItem + + MenuView() + + itemClicked(item : MenuItem) + + render() + + storeChanged(store : Store) + } + interface View { + + render() {abstract} + + storeChanged(Store) {abstract} + } +} +package com.iluwatar.flux.action { + abstract class Action { + - type : ActionType + + Action(type : ActionType) + + getType() : ActionType + } + enum ActionType { + + CONTENT_CHANGED {static} + + MENU_ITEM_SELECTED {static} + + valueOf(name : String) : ActionType {static} + + values() : ActionType[] {static} + } + enum Content { + + COMPANY {static} + + PRODUCTS {static} + - title : String + + toString() : String + + valueOf(name : String) : Content {static} + + values() : Content[] {static} + } + class ContentAction { + - content : Content + + ContentAction(content : Content) + + getContent() : Content + } + class MenuAction { + - menuItem : MenuItem + + MenuAction(menuItem : MenuItem) + + getMenuItem() : MenuItem + } + enum MenuItem { + + COMPANY {static} + + HOME {static} + + PRODUCTS {static} + - title : String + + toString() : String + + valueOf(name : String) : MenuItem {static} + + values() : MenuItem[] {static} + } +} +package com.iluwatar.flux.app { + class App { + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.flux.store { + class ContentStore { + - content : Content + + ContentStore() + + getContent() : Content + + onAction(action : Action) + } + class MenuStore { + - selected : MenuItem + + MenuStore() + + getSelected() : MenuItem + + onAction(action : Action) + } + abstract class Store { + - views : List + + Store() + # notifyChange() + + onAction(Action) {abstract} + + registerView(view : View) + } +} +package com.iluwatar.flux.dispatcher { + class Dispatcher { + - instance : Dispatcher {static} + - stores : List + - Dispatcher() + - dispatchAction(action : Action) + + getInstance() : Dispatcher {static} + + menuItemSelected(menuItem : MenuItem) + + registerStore(store : Store) + } +} +MenuAction --> "-menuItem" MenuItem +Action --> "-type" ActionType +MenuStore --> "-selected" MenuItem +Dispatcher --> "-instance" Dispatcher +ContentView --> "-content" Content +Dispatcher --> "-stores" Store +MenuView --> "-selected" MenuItem +Store --> "-views" View +ContentStore --> "-content" Content +ContentAction --> "-content" Content +ContentAction --|> Action +MenuAction --|> Action +ContentStore --|> Store +MenuStore --|> Store +ContentView ..|> View +MenuView ..|> View +@enduml \ No newline at end of file diff --git a/etc/flyweight.urm.png b/etc/flyweight.urm.png new file mode 100644 index 000000000000..299cdb7bdf86 Binary files /dev/null and b/etc/flyweight.urm.png differ diff --git a/etc/flyweight.urm.puml b/etc/flyweight.urm.puml new file mode 100644 index 000000000000..61f2aa696eaf --- /dev/null +++ b/etc/flyweight.urm.puml @@ -0,0 +1,65 @@ +@startuml +package com.iluwatar.flyweight { + class AlchemistShop { + - LOGGER : Logger {static} + - bottomShelf : List + - topShelf : List + + AlchemistShop() + + enumerate() + + getBottomShelf() : List + + getTopShelf() : List + } + class App { + + App() + + main(args : String[]) {static} + } + class HealingPotion { + - LOGGER : Logger {static} + + HealingPotion() + + drink() + } + class HolyWaterPotion { + - LOGGER : Logger {static} + + HolyWaterPotion() + + drink() + } + class InvisibilityPotion { + - LOGGER : Logger {static} + + InvisibilityPotion() + + drink() + } + class PoisonPotion { + - LOGGER : Logger {static} + + PoisonPotion() + + drink() + } + interface Potion { + + drink() {abstract} + } + class PotionFactory { + - potions : Map + + PotionFactory() + ~ createPotion(type : PotionType) : Potion + } + enum PotionType { + + HEALING {static} + + HOLY_WATER {static} + + INVISIBILITY {static} + + POISON {static} + + STRENGTH {static} + + valueOf(name : String) : PotionType {static} + + values() : PotionType[] {static} + } + class StrengthPotion { + - LOGGER : Logger {static} + + StrengthPotion() + + drink() + } +} +AlchemistShop --> "-topShelf" Potion +HealingPotion ..|> Potion +HolyWaterPotion ..|> Potion +InvisibilityPotion ..|> Potion +PoisonPotion ..|> Potion +StrengthPotion ..|> Potion +@enduml \ No newline at end of file diff --git a/etc/front-controller.png b/etc/front-controller.png new file mode 100644 index 000000000000..77c14ef019cc Binary files /dev/null and b/etc/front-controller.png differ diff --git a/etc/front-controller.ucls b/etc/front-controller.ucls new file mode 100644 index 000000000000..11cdf66ec073 --- /dev/null +++ b/etc/front-controller.ucls @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/front-controller.urm.puml b/etc/front-controller.urm.puml new file mode 100644 index 000000000000..d2c21fc015a0 --- /dev/null +++ b/etc/front-controller.urm.puml @@ -0,0 +1,53 @@ +@startuml +package com.iluwatar.front.controller { + class App { + + App() + + main(args : String[]) {static} + } + class ArcherCommand { + + ArcherCommand() + + process() + } + class ArcherView { + - LOGGER : Logger {static} + + ArcherView() + + display() + } + class CatapultCommand { + + CatapultCommand() + + process() + } + class CatapultView { + - LOGGER : Logger {static} + + CatapultView() + + display() + } + interface Command { + + process() {abstract} + } + class ErrorView { + - LOGGER : Logger {static} + + ErrorView() + + display() + } + class FrontController { + + FrontController() + - getCommand(request : String) : Command + - getCommandClass(request : String) : Class {static} + + handleRequest(request : String) + } + class UnknownCommand { + + UnknownCommand() + + process() + } + interface View { + + display() {abstract} + } +} +ArcherCommand ..|> Command +ArcherView ..|> View +CatapultCommand ..|> Command +CatapultView ..|> View +ErrorView ..|> View +UnknownCommand ..|> Command +@enduml \ No newline at end of file diff --git a/etc/game-loop.urm.png b/etc/game-loop.urm.png new file mode 100644 index 000000000000..b7ffc11d2659 Binary files /dev/null and b/etc/game-loop.urm.png differ diff --git a/etc/game-loop.urm.puml b/etc/game-loop.urm.puml new file mode 100644 index 000000000000..d0704096f11e --- /dev/null +++ b/etc/game-loop.urm.puml @@ -0,0 +1,63 @@ +@startuml +package com.iluwatar.gameloop { + class App { + - GAME_LOOP_DURATION_TIME : int {static} + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Bullet { + - position : float + + Bullet() + + getPosition() : float + + setPosition(position : float) + } + class FixedStepGameLoop { + - MS_PER_FRAME : long {static} + + FixedStepGameLoop() + # processGameLoop() + # update() + } + class FrameBasedGameLoop { + + FrameBasedGameLoop() + # processGameLoop() + # update() + } + class GameController { + # bullet : Bullet + + GameController() + + getBulletPosition() : float + + moveBullet(offset : float) + } + abstract class GameLoop { + # controller : GameController + - gameThread : Thread + # logger : Logger + # status : GameStatus + + GameLoop() + + isGameRunning() : boolean + # processGameLoop() {abstract} + # processInput() + # render() + + run() + + stop() + } + enum GameStatus { + + RUNNING {static} + + STOPPED {static} + + valueOf(name : String) : GameStatus {static} + + values() : GameStatus[] {static} + } + class VariableStepGameLoop { + + VariableStepGameLoop() + # processGameLoop() + # update(elapsedTime : Long) + } +} +GameLoop --> "-status" GameStatus +GameController --> "-bullet" Bullet +GameLoop --> "-controller" GameController +FixedStepGameLoop --|> GameLoop +FrameBasedGameLoop --|> GameLoop +VariableStepGameLoop --|> GameLoop +@enduml \ No newline at end of file diff --git a/etc/gcf-black.png b/etc/gcf-black.png new file mode 100644 index 000000000000..b4e22982c8e2 Binary files /dev/null and b/etc/gcf-black.png differ diff --git a/etc/guarded-suspension.png b/etc/guarded-suspension.png new file mode 100644 index 000000000000..bd3fa5661fab Binary files /dev/null and b/etc/guarded-suspension.png differ diff --git a/etc/guarded-suspension.ucls b/etc/guarded-suspension.ucls new file mode 100644 index 000000000000..2e46325e44c4 --- /dev/null +++ b/etc/guarded-suspension.ucls @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/guarded-suspension.urm.puml b/etc/guarded-suspension.urm.puml new file mode 100644 index 000000000000..45a7d37904cb --- /dev/null +++ b/etc/guarded-suspension.urm.puml @@ -0,0 +1,15 @@ +@startuml +package com.iluwatar.guarded.suspension { + class App { + + App() + + main(args : String[]) {static} + } + class GuardedQueue { + - LOGGER : Logger {static} + - sourceList : Queue + + GuardedQueue() + + get() : Integer + + put(e : Integer) + } +} +@enduml \ No newline at end of file diff --git a/etc/half-sync-half-async.png b/etc/half-sync-half-async.png new file mode 100644 index 000000000000..84658dfdeafc Binary files /dev/null and b/etc/half-sync-half-async.png differ diff --git a/etc/half-sync-half-async.ucls b/etc/half-sync-half-async.ucls new file mode 100644 index 000000000000..5b9941872447 --- /dev/null +++ b/etc/half-sync-half-async.ucls @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/half-sync-half-async.urm.puml b/etc/half-sync-half-async.urm.puml new file mode 100644 index 000000000000..64d8a5f8d87d --- /dev/null +++ b/etc/half-sync-half-async.urm.puml @@ -0,0 +1,33 @@ +@startuml +package com.iluwatar.halfsynchalfasync { + class App { + - LOGGER : Logger {static} + + App() + - ap(i : long) : long {static} + + main(args : String[]) {static} + } + ~class ArithmeticSumTask { + - numberOfElements : long + + ArithmeticSumTask(numberOfElements : long) + + call() : Long + + onError(throwable : Throwable) + + onPostCall(result : Long) + + onPreCall() + } + interface AsyncTask { + + call() : O {abstract} + + onError(Throwable) {abstract} + + onPostCall(O) {abstract} + + onPreCall() {abstract} + } + class AsynchronousService { + - LOGGER : Logger {static} + - service : ExecutorService + + AsynchronousService(workQueue : BlockingQueue) + + close() + + execute(task : AsyncTask) + } +} +ArithmeticSumTask ..+ App +ArithmeticSumTask ..|> AsyncTask +@enduml \ No newline at end of file diff --git a/etc/hexagonal.png b/etc/hexagonal.png new file mode 100644 index 000000000000..1ad077fd4fd0 Binary files /dev/null and b/etc/hexagonal.png differ diff --git a/etc/hexagonal.ucls b/etc/hexagonal.ucls new file mode 100644 index 000000000000..d3b46b23d08e --- /dev/null +++ b/etc/hexagonal.ucls @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/hexagonal.urm.puml b/etc/hexagonal.urm.puml new file mode 100644 index 000000000000..10fcc7f6d71e --- /dev/null +++ b/etc/hexagonal.urm.puml @@ -0,0 +1,305 @@ +@startuml +package com.iluwatar.hexagonal.sampledata { + class SampleData { + - PLAYERS : List {static} + - RANDOM : Random {static} + + SampleData() + - getRandomPlayerDetails() : PlayerDetails {static} + + submitTickets(lotteryService : LotteryService, numTickets : int) {static} + } +} +package com.iluwatar.hexagonal.service { + class ConsoleLottery { + - LOGGER : Logger {static} + + ConsoleLottery() + + main(args : String[]) {static} + - printMainMenu() {static} + - readString(scanner : Scanner) : String {static} + } + interface LotteryConsoleService { + + addFundsToLotteryAccount(WireTransfers, Scanner) {abstract} + + checkTicket(LotteryService, Scanner) {abstract} + + queryLotteryAccountFunds(WireTransfers, Scanner) {abstract} + + submitTicket(LotteryService, Scanner) {abstract} + } + class LotteryConsoleServiceImpl { + - logger : Logger + + LotteryConsoleServiceImpl(logger : Logger) + + addFundsToLotteryAccount(bank : WireTransfers, scanner : Scanner) + + checkTicket(service : LotteryService, scanner : Scanner) + + queryLotteryAccountFunds(bank : WireTransfers, scanner : Scanner) + - readString(scanner : Scanner) : String + + submitTicket(service : LotteryService, scanner : Scanner) + } +} +package com.iluwatar.hexagonal.mongo { + class MongoConnectionPropertiesLoader { + - DEFAULT_HOST : String {static} + - DEFAULT_PORT : int {static} + + MongoConnectionPropertiesLoader() + + load() {static} + } +} +package com.iluwatar.hexagonal.domain { + class LotteryAdministration { + - notifications : LotteryEventLog + - repository : LotteryTicketRepository + - wireTransfers : WireTransfers + + LotteryAdministration(repository : LotteryTicketRepository, notifications : LotteryEventLog, wireTransfers : WireTransfers) + + getAllSubmittedTickets() : Map + + performLottery() : LotteryNumbers + + resetLottery() + } + class LotteryConstants { + + PLAYER_MAX_BALANCE : int {static} + + PRIZE_AMOUNT : int {static} + + SERVICE_BANK_ACCOUNT : String {static} + + SERVICE_BANK_ACCOUNT_BALANCE : int {static} + + TICKET_PRIZE : int {static} + - LotteryConstants() + } + class LotteryNumbers { + + MAX_NUMBER : int {static} + + MIN_NUMBER : int {static} + + NUM_NUMBERS : int {static} + - numbers : Set + - LotteryNumbers() + - LotteryNumbers(givenNumbers : Set) + + create(givenNumbers : Set) : LotteryNumbers {static} + + createRandom() : LotteryNumbers {static} + + equals(obj : Object) : boolean + - generateRandomNumbers() + + getNumbers() : Set + + getNumbersAsString() : String + + hashCode() : int + + toString() : String + } + -class RandomNumberGenerator { + - randomIterator : OfInt + + RandomNumberGenerator(min : int, max : int) + + nextInt() : int + } + class LotteryService { + - notifications : LotteryEventLog + - repository : LotteryTicketRepository + - wireTransfers : WireTransfers + + LotteryService(repository : LotteryTicketRepository, notifications : LotteryEventLog, wireTransfers : WireTransfers) + + checkTicketForPrize(id : LotteryTicketId, winningNumbers : LotteryNumbers) : LotteryTicketCheckResult + + submitTicket(ticket : LotteryTicket) : Optional + } + class LotteryTicket { + - id : LotteryTicketId + - lotteryNumbers : LotteryNumbers + - playerDetails : PlayerDetails + + LotteryTicket(id : LotteryTicketId, details : PlayerDetails, numbers : LotteryNumbers) + + equals(obj : Object) : boolean + + getId() : LotteryTicketId + + getNumbers() : LotteryNumbers + + getPlayerDetails() : PlayerDetails + + hashCode() : int + + setId(id : LotteryTicketId) + + toString() : String + } + class LotteryTicketCheckResult { + - checkResult : CheckResult + - prizeAmount : int + + LotteryTicketCheckResult(result : CheckResult) + + LotteryTicketCheckResult(result : CheckResult, amount : int) + + equals(obj : Object) : boolean + + getPrizeAmount() : int + + getResult() : CheckResult + + hashCode() : int + } + enum CheckResult { + + NO_PRIZE {static} + + TICKET_NOT_SUBMITTED {static} + + WIN_PRIZE {static} + + valueOf(name : String) : CheckResult {static} + + values() : CheckResult[] {static} + } + class LotteryTicketId { + - id : int + - numAllocated : AtomicInteger {static} + + LotteryTicketId() + + LotteryTicketId(id : int) + + equals(o : Object) : boolean + + getId() : int + + hashCode() : int + + toString() : String + } + class LotteryUtils { + - LotteryUtils() + + checkTicketForPrize(repository : LotteryTicketRepository, id : LotteryTicketId, winningNumbers : LotteryNumbers) : LotteryTicketCheckResult {static} + } + class PlayerDetails { + - bankAccountNumber : String + - emailAddress : String + - phoneNumber : String + + PlayerDetails(email : String, bankAccount : String, phone : String) + + equals(obj : Object) : boolean + + getBankAccount() : String + + getEmail() : String + + getPhoneNumber() : String + + hashCode() : int + + toString() : String + } +} +package com.iluwatar.hexagonal.banking { + class InMemoryBank { + - accounts : Map {static} + + InMemoryBank() + + getFunds(bankAccount : String) : int + + setFunds(bankAccount : String, amount : int) + + transferFunds(amount : int, sourceAccount : String, destinationAccount : String) : boolean + } + class MongoBank { + - DEFAULT_ACCOUNTS_COLLECTION : String {static} + - DEFAULT_DB : String {static} + - accountsCollection : MongoCollection + - database : MongoDatabase + - mongoClient : MongoClient + + MongoBank() + + MongoBank(dbName : String, accountsCollectionName : String) + + connect() + + connect(dbName : String, accountsCollectionName : String) + + getAccountsCollection() : MongoCollection + + getFunds(bankAccount : String) : int + + getMongoClient() : MongoClient + + getMongoDatabase() : MongoDatabase + + setFunds(bankAccount : String, amount : int) + + transferFunds(amount : int, sourceAccount : String, destinationAccount : String) : boolean + } + interface WireTransfers { + + getFunds(String) : int {abstract} + + setFunds(String, int) {abstract} + + transferFunds(int, String, String) : boolean {abstract} + } +} +package com.iluwatar.hexagonal.database { + class InMemoryTicketRepository { + - tickets : Map {static} + + InMemoryTicketRepository() + + deleteAll() + + findAll() : Map + + findById(id : LotteryTicketId) : Optional + + save(ticket : LotteryTicket) : Optional + } + interface LotteryTicketRepository { + + deleteAll() {abstract} + + findAll() : Map {abstract} + + findById(LotteryTicketId) : Optional {abstract} + + save(LotteryTicket) : Optional {abstract} + } + class MongoTicketRepository { + - DEFAULT_COUNTERS_COLLECTION : String {static} + - DEFAULT_DB : String {static} + - DEFAULT_TICKETS_COLLECTION : String {static} + - countersCollection : MongoCollection + - database : MongoDatabase + - mongoClient : MongoClient + - ticketsCollection : MongoCollection + + MongoTicketRepository() + + MongoTicketRepository(dbName : String, ticketsCollectionName : String, countersCollectionName : String) + + connect() + + connect(dbName : String, ticketsCollectionName : String, countersCollectionName : String) + + deleteAll() + - docToTicket(doc : Document) : LotteryTicket + + findAll() : Map + + findById(id : LotteryTicketId) : Optional + + getCountersCollection() : MongoCollection + + getNextId() : int + + getTicketsCollection() : MongoCollection + - initCounters() + + save(ticket : LotteryTicket) : Optional + } +} +package com.iluwatar.hexagonal { + class App { + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.hexagonal.administration { + class ConsoleAdministration { + - LOGGER : Logger {static} + + ConsoleAdministration() + + main(args : String[]) {static} + - printMainMenu() {static} + - readString(scanner : Scanner) : String {static} + } + interface ConsoleAdministrationSrv { + + getAllSubmittedTickets() {abstract} + + performLottery() {abstract} + + resetLottery() {abstract} + } + class ConsoleAdministrationSrvImpl { + - administration : LotteryAdministration + - logger : Logger + + ConsoleAdministrationSrvImpl(administration : LotteryAdministration, logger : Logger) + + getAllSubmittedTickets() + + performLottery() + + resetLottery() + } +} +package com.iluwatar.hexagonal.eventlog { + interface LotteryEventLog { + + prizeError(PlayerDetails, int) {abstract} + + ticketDidNotWin(PlayerDetails) {abstract} + + ticketSubmitError(PlayerDetails) {abstract} + + ticketSubmitted(PlayerDetails) {abstract} + + ticketWon(PlayerDetails, int) {abstract} + } + class MongoEventLog { + - DEFAULT_DB : String {static} + - DEFAULT_EVENTS_COLLECTION : String {static} + - database : MongoDatabase + - eventsCollection : MongoCollection + - mongoClient : MongoClient + - stdOutEventLog : StdOutEventLog + + MongoEventLog() + + MongoEventLog(dbName : String, eventsCollectionName : String) + + connect() + + connect(dbName : String, eventsCollectionName : String) + + getEventsCollection() : MongoCollection + + getMongoClient() : MongoClient + + getMongoDatabase() : MongoDatabase + + prizeError(details : PlayerDetails, prizeAmount : int) + + ticketDidNotWin(details : PlayerDetails) + + ticketSubmitError(details : PlayerDetails) + + ticketSubmitted(details : PlayerDetails) + + ticketWon(details : PlayerDetails, prizeAmount : int) + } + class StdOutEventLog { + - LOGGER : Logger {static} + + StdOutEventLog() + + prizeError(details : PlayerDetails, prizeAmount : int) + + ticketDidNotWin(details : PlayerDetails) + + ticketSubmitError(details : PlayerDetails) + + ticketSubmitted(details : PlayerDetails) + + ticketWon(details : PlayerDetails, prizeAmount : int) + } +} +LotteryTicket --> "-playerDetails" PlayerDetails +MongoEventLog --> "-stdOutEventLog" StdOutEventLog +LotteryService --> "-wireTransfers" WireTransfers +LotteryAdministration --> "-notifications" LotteryEventLog +LotteryAdministration --> "-wireTransfers" WireTransfers +LotteryTicket --> "-id" LotteryTicketId +LotteryAdministration --> "-repository" LotteryTicketRepository +LotteryService --> "-notifications" LotteryEventLog +LotteryTicket --> "-lotteryNumbers" LotteryNumbers +SampleData --> "-PLAYERS" PlayerDetails +ConsoleAdministrationSrvImpl --> "-administration" LotteryAdministration +RandomNumberGenerator ..+ LotteryNumbers +LotteryService --> "-repository" LotteryTicketRepository +CheckResult ..+ LotteryTicketCheckResult +LotteryTicketCheckResult --> "-checkResult" CheckResult +ConsoleAdministrationSrvImpl ..|> ConsoleAdministrationSrv +InMemoryBank ..|> WireTransfers +MongoBank ..|> WireTransfers +InMemoryTicketRepository ..|> LotteryTicketRepository +MongoTicketRepository ..|> LotteryTicketRepository +MongoEventLog ..|> LotteryEventLog +StdOutEventLog ..|> LotteryEventLog +LotteryConsoleServiceImpl ..|> LotteryConsoleService +@enduml \ No newline at end of file diff --git a/etc/identity-map.urm.puml b/etc/identity-map.urm.puml new file mode 100644 index 000000000000..cdbdbd8f23a8 --- /dev/null +++ b/etc/identity-map.urm.puml @@ -0,0 +1,67 @@ +@startuml +package com.iluwatar.identitymap { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class IdentityMap { + - LOGGER : Logger {static} + - personMap : Map + + IdentityMap() + + addPerson(person : Person) + + getPerson(id : int) : Person + + getPersonMap() : Map + + size() : int + } + class Person { + - name : String + - personNationalId : int + - phoneNum : long + - serialVersionUID : long {static} + + Person(personNationalId : int, name : String, phoneNum : long) + + equals(o : Object) : boolean + + getName() : String + + getPersonNationalId() : int + + getPhoneNum() : long + + hashCode() : int + + setName(name : String) + + setPersonNationalId(personNationalId : int) + + setPhoneNum(phoneNum : long) + + toString() : String + } + interface PersonDbSimulator { + + delete(int) {abstract} + + find(int) : Person {abstract} + + insert(Person) {abstract} + + update(Person) {abstract} + } + class PersonDbSimulatorImplementation { + ~ ID_STR : String {static} + - LOGGER : Logger {static} + ~ NOT_IN_DATA_BASE : String {static} + - personList : List + + PersonDbSimulatorImplementation() + + delete(id : int) + + find(personNationalID : int) : Person + + insert(person : Person) + + size() : int + + update(person : Person) + } + class PersonFinder { + - LOGGER : Logger {static} + - db : PersonDbSimulatorImplementation + - identityMap : IdentityMap + + PersonFinder() + + getDB() : PersonDbSimulatorImplementation + + getIdentityMap() : IdentityMap + + getPerson(key : int) : Person + + setDb(db : PersonDbSimulatorImplementation) + + setIdentityMap(identityMap : IdentityMap) + } +} +PersonFinder --> "-db" PersonDbSimulatorImplementation +PersonFinder --> "-identityMap" IdentityMap +PersonDbSimulatorImplementation --> "-personList" Person +PersonDbSimulatorImplementation ..|> PersonDbSimulator +@enduml \ No newline at end of file diff --git a/etc/images/noparam.png b/etc/images/noparam.png new file mode 100644 index 000000000000..2979cf2bc657 Binary files /dev/null and b/etc/images/noparam.png differ diff --git a/etc/images/threeparams.png b/etc/images/threeparams.png new file mode 100644 index 000000000000..9338dedb8885 Binary files /dev/null and b/etc/images/threeparams.png differ diff --git a/etc/intercepting-filter.png b/etc/intercepting-filter.png new file mode 100644 index 000000000000..ec792639eab5 Binary files /dev/null and b/etc/intercepting-filter.png differ diff --git a/etc/intercepting-filter.ucls b/etc/intercepting-filter.ucls new file mode 100644 index 000000000000..9cf8d3c00f0d --- /dev/null +++ b/etc/intercepting-filter.ucls @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/intercepting-filter.urm.puml b/etc/intercepting-filter.urm.puml new file mode 100644 index 000000000000..6e565fd668c9 --- /dev/null +++ b/etc/intercepting-filter.urm.puml @@ -0,0 +1,88 @@ +@startuml +package com.iluwatar.intercepting.filter { + abstract class AbstractFilter { + - next : Filter + + AbstractFilter() + + AbstractFilter(next : Filter) + + execute(order : Order) : String + + getLast() : Filter + + getNext() : Filter + + setNext(filter : Filter) + } + class AddressFilter { + + AddressFilter() + + execute(order : Order) : String + } + class App { + + App() + + main(args : String[]) {static} + } + class ContactFilter { + + ContactFilter() + + execute(order : Order) : String + } + class DepositFilter { + + DepositFilter() + + execute(order : Order) : String + } + interface Filter { + + execute(Order) : String {abstract} + + getLast() : Filter {abstract} + + getNext() : Filter {abstract} + + setNext(Filter) {abstract} + } + class FilterChain { + - chain : Filter + + FilterChain() + + addFilter(filter : Filter) + + execute(order : Order) : String + } + class FilterManager { + - filterChain : FilterChain + + FilterManager() + + addFilter(filter : Filter) + + filterRequest(order : Order) : String + } + class NameFilter { + + NameFilter() + + execute(order : Order) : String + } + class Order { + - address : String + - contactNumber : String + - depositNumber : String + - name : String + - orderItem : String + + Order() + + Order(name : String, contactNumber : String, address : String, depositNumber : String, order : String) + + getAddress() : String + + getContactNumber() : String + + getDepositNumber() : String + + getName() : String + + getOrderItem() : String + + setAddress(address : String) + + setContactNumber(contactNumber : String) + + setDepositNumber(depositNumber : String) + + setName(name : String) + + setOrderItem(order : String) + } + class OrderFilter { + + OrderFilter() + + execute(order : Order) : String + } + ~class DListener { + ~ DListener() + + actionPerformed(e : ActionEvent) + } +} +AbstractFilter --> "-next" Filter +DListener --+ Target +FilterManager --> "-filterChain" FilterChain +FilterChain --> "-chain" Filter +AbstractFilter ..|> Filter +AddressFilter --|> AbstractFilter +ContactFilter --|> AbstractFilter +DepositFilter --|> AbstractFilter +NameFilter --|> AbstractFilter +OrderFilter --|> AbstractFilter +@enduml \ No newline at end of file diff --git a/etc/interpreter.png b/etc/interpreter.png new file mode 100644 index 000000000000..223148e00d8b Binary files /dev/null and b/etc/interpreter.png differ diff --git a/etc/interpreter.ucls b/etc/interpreter.ucls new file mode 100644 index 000000000000..84dc79a3e922 --- /dev/null +++ b/etc/interpreter.ucls @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/interpreter.urm.puml b/etc/interpreter.urm.puml new file mode 100644 index 000000000000..e79ad1989588 --- /dev/null +++ b/etc/interpreter.urm.puml @@ -0,0 +1,51 @@ +@startuml +package com.iluwatar.interpreter { + class App { + - LOGGER : Logger {static} + + App() + + getOperatorInstance(s : String, left : Expression, right : Expression) : Expression {static} + + isOperator(s : String) : boolean {static} + + main(args : String[]) {static} + } + abstract class Expression { + + Expression() + + interpret() : int {abstract} + + toString() : String {abstract} + } + class MinusExpression { + - leftExpression : Expression + - rightExpression : Expression + + MinusExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } + class MultiplyExpression { + - leftExpression : Expression + - rightExpression : Expression + + MultiplyExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } + class NumberExpression { + - number : int + + NumberExpression(number : int) + + NumberExpression(s : String) + + interpret() : int + + toString() : String + } + class PlusExpression { + - leftExpression : Expression + - rightExpression : Expression + + PlusExpression(leftExpression : Expression, rightExpression : Expression) + + interpret() : int + + toString() : String + } +} +MultiplyExpression --> "-leftExpression" Expression +MinusExpression --> "-leftExpression" Expression +PlusExpression --> "-leftExpression" Expression +MinusExpression --|> Expression +MultiplyExpression --|> Expression +NumberExpression --|> Expression +PlusExpression --|> Expression +@enduml \ No newline at end of file diff --git a/etc/interpreter_1.png b/etc/interpreter_1.png new file mode 100644 index 000000000000..f10342a1df90 Binary files /dev/null and b/etc/interpreter_1.png differ diff --git a/etc/iterator.png b/etc/iterator.png new file mode 100644 index 000000000000..f70340951409 Binary files /dev/null and b/etc/iterator.png differ diff --git a/etc/iterator.ucls b/etc/iterator.ucls new file mode 100644 index 000000000000..d36dad95d48b --- /dev/null +++ b/etc/iterator.ucls @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/iterator.urm.puml b/etc/iterator.urm.puml new file mode 100644 index 000000000000..59cb93be26b6 --- /dev/null +++ b/etc/iterator.urm.puml @@ -0,0 +1,85 @@ +@startuml +package com.iluwatar.iterator { + class App { + - LOGGER : Logger {static} + - TREASURE_CHEST : TreasureChest {static} + + App() + - buildIntegerBst() : TreeNode {static} + - demonstrateBstIterator() {static} + - demonstrateTreasureChestIteratorForType(itemType : ItemType) {static} + + main(args : String[]) {static} + } + interface Iterator { + + hasNext() : boolean {abstract} + + next() : T {abstract} + } +} +package com.iluwatar.iterator.bst { + class BstIterator> { + - pathStack : ArrayDeque>> + + BstIterator>(root : TreeNode>) + + hasNext() : boolean + + next() : TreeNode> + - pushPathToNextSmallest(node : TreeNode>) + } + class TreeNode> { + - left : TreeNode> + - right : TreeNode> + - val : T extends Comparable + + TreeNode>(val : T extends Comparable) + + getLeft() : TreeNode> + - getParentNodeOfValueToBeInserted(valToInsert : T extends Comparable) : TreeNode> + + getRight() : TreeNode> + + getVal() : T extends Comparable + + insert(valToInsert : T extends Comparable) + - insertNewChild(valToInsert : T extends Comparable) + - isGreaterThan(val : T extends Comparable) : boolean + - isLessThanOrEqualTo(val : T extends Comparable) : boolean + - setLeft(left : TreeNode>) + - setRight(right : TreeNode>) + + toString() : String + - traverseOneLevelDown(value : T extends Comparable) : TreeNode> + } +} +package com.iluwatar.iterator.list { + class Item { + - name : String + - type : ItemType + + Item(type : ItemType, name : String) + + getType() : ItemType + + setType(type : ItemType) + + toString() : String + } + enum ItemType { + + ANY {static} + + POTION {static} + + RING {static} + + WEAPON {static} + + valueOf(name : String) : ItemType {static} + + values() : ItemType[] {static} + } + class TreasureChest { + - items : List + + TreasureChest() + + getItems() : List + + iterator(itemType : ItemType) : Iterator + } + class TreasureChestItemIterator { + - chest : TreasureChest + - idx : int + - type : ItemType + + TreasureChestItemIterator(chest : TreasureChest, type : ItemType) + - findNextIdx() : int + + hasNext() : boolean + + next() : Item + } +} +TreasureChestItemIterator --> "-type" ItemType +TreeNode --> "-left" TreeNode +TreasureChestItemIterator --> "-chest" TreasureChest +TreasureChest --> "-items" Item +Item --> "-type" ItemType +App --> "-TREASURE_CHEST" TreasureChest +BstIterator ..|> Iterator +TreasureChestItemIterator ..|> Iterator +@enduml \ No newline at end of file diff --git a/etc/iterator_1.png b/etc/iterator_1.png new file mode 100644 index 000000000000..d8313bc5881f Binary files /dev/null and b/etc/iterator_1.png differ diff --git a/etc/kubeless-logos-black.png b/etc/kubeless-logos-black.png new file mode 100644 index 000000000000..dd6523c51099 Binary files /dev/null and b/etc/kubeless-logos-black.png differ diff --git a/etc/layers.png b/etc/layers.png new file mode 100644 index 000000000000..a4bd8b19ddad Binary files /dev/null and b/etc/layers.png differ diff --git a/etc/layers.ucls b/etc/layers.ucls new file mode 100644 index 000000000000..a3cac547a033 --- /dev/null +++ b/etc/layers.ucls @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/layers.urm.puml b/etc/layers.urm.puml new file mode 100644 index 000000000000..f73b7964a0b4 --- /dev/null +++ b/etc/layers.urm.puml @@ -0,0 +1,136 @@ +@startuml +package com.iluwatar.layers.dto { + class CakeInfo { + + cakeLayerInfos : List + + cakeToppingInfo : CakeToppingInfo + + id : Optional + + CakeInfo(cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) + + CakeInfo(id : Long, cakeToppingInfo : CakeToppingInfo, cakeLayerInfos : List) + + calculateTotalCalories() : int + + toString() : String + } + class CakeLayerInfo { + + calories : int + + id : Optional + + name : String + + CakeLayerInfo(id : Long, name : String, calories : int) + + CakeLayerInfo(name : String, calories : int) + + toString() : String + } + class CakeToppingInfo { + + calories : int + + id : Optional + + name : String + + CakeToppingInfo(id : Long, name : String, calories : int) + + CakeToppingInfo(name : String, calories : int) + + toString() : String + } +} +package com.iluwatar.layers.entity { + class Cake { + - id : Long + - layers : Set + - topping : CakeTopping + + Cake() + + addLayer(layer : CakeLayer) + + getId() : Long + + getLayers() : Set + + getTopping() : CakeTopping + + setId(id : Long) + + setLayers(layers : Set) + + setTopping(topping : CakeTopping) + + toString() : String + } + class CakeLayer { + - cake : Cake + - calories : int + - id : Long + - name : String + + CakeLayer() + + CakeLayer(name : String, calories : int) + + getCake() : Cake + + getCalories() : int + + getId() : Long + + getName() : String + + setCake(cake : Cake) + + setCalories(calories : int) + + setId(id : Long) + + setName(name : String) + + toString() : String + } + class CakeTopping { + - cake : Cake + - calories : int + - id : Long + - name : String + + CakeTopping() + + CakeTopping(name : String, calories : int) + + getCake() : Cake + + getCalories() : int + + getId() : Long + + getName() : String + + setCake(cake : Cake) + + setCalories(calories : int) + + setId(id : Long) + + setName(name : String) + + toString() : String + } +} +package com.iluwatar.layers.view { + class CakeViewImpl { + - LOGGER : Logger {static} + - cakeBakingService : CakeBakingService + + CakeViewImpl(cakeBakingService : CakeBakingService) + + render() + } + interface View { + + render() {abstract} + } +} +package com.iluwatar.layers.app { + class App { + - cakeBakingService : CakeBakingService {static} + + App() + - initializeData(cakeBakingService : CakeBakingService) {static} + + main(args : String[]) {static} + } +} +package com.iluwatar.layers.dao { + interface CakeDao { + } + interface CakeLayerDao { + } + interface CakeToppingDao { + } +} +package com.iluwatar.layers.service { + interface CakeBakingService { + + bakeNewCake(CakeInfo) {abstract} + + getAllCakes() : List {abstract} + + getAvailableLayers() : List {abstract} + + getAvailableToppings() : List {abstract} + + saveNewLayer(CakeLayerInfo) {abstract} + + saveNewTopping(CakeToppingInfo) {abstract} + } + class CakeBakingServiceImpl { + - context : AbstractApplicationContext + + CakeBakingServiceImpl() + + bakeNewCake(cakeInfo : CakeInfo) + + getAllCakes() : List + - getAvailableLayerEntities() : List + + getAvailableLayers() : List + - getAvailableToppingEntities() : List + + getAvailableToppings() : List + + saveNewLayer(layerInfo : CakeLayerInfo) + + saveNewTopping(toppingInfo : CakeToppingInfo) + } +} +CakeInfo --> "-cakeLayerInfos" CakeLayerInfo +CakeInfo --> "-cakeToppingInfo" CakeToppingInfo +CakeViewImpl --> "-cakeBakingService" CakeBakingService +App --> "-cakeBakingService" CakeBakingService +Cake --> "-topping" CakeTopping +CakeLayer --> "-cake" Cake +CakeBakingServiceImpl ..|> CakeBakingService +CakeViewImpl ..|> View +@enduml \ No newline at end of file diff --git a/etc/lazy-loading.png b/etc/lazy-loading.png new file mode 100644 index 000000000000..bec0a7afbefe Binary files /dev/null and b/etc/lazy-loading.png differ diff --git a/etc/lazy-loading.ucls b/etc/lazy-loading.ucls new file mode 100644 index 000000000000..9f4ccd1a446d --- /dev/null +++ b/etc/lazy-loading.ucls @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/lazy-loading.urm.puml b/etc/lazy-loading.urm.puml new file mode 100644 index 000000000000..aaf49f1df941 --- /dev/null +++ b/etc/lazy-loading.urm.puml @@ -0,0 +1,40 @@ +@startuml +package com.iluwatar.lazy.loading { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Heavy { + - LOGGER : Logger {static} + + Heavy() + } + class HolderNaive { + - LOGGER : Logger {static} + - heavy : Heavy + + HolderNaive() + + getHeavy() : Heavy + } + class HolderThreadSafe { + - LOGGER : Logger {static} + - heavy : Heavy + + HolderThreadSafe() + + getHeavy() : Heavy + } + class Java8Holder { + - LOGGER : Logger {static} + - heavy : Supplier + + Java8Holder() + - createAndCacheHeavy() : Heavy + + getHeavy() : Heavy + } + ~class HeavyFactory { + - heavyInstance : Heavy + ~ HeavyFactory() + + get() : Heavy + } +} +HolderThreadSafe --> "-heavy" Heavy +HolderNaive --> "-heavy" Heavy +HeavyFactory --> "-heavyInstance" Heavy +@enduml \ No newline at end of file diff --git a/etc/leader-election.urm.png b/etc/leader-election.urm.png new file mode 100644 index 000000000000..85a90b75b636 Binary files /dev/null and b/etc/leader-election.urm.png differ diff --git a/etc/leader-election.urm.puml b/etc/leader-election.urm.puml new file mode 100644 index 000000000000..c28066f31566 --- /dev/null +++ b/etc/leader-election.urm.puml @@ -0,0 +1,120 @@ +@startuml +package com.iluwatar.leaderelection.ring { + class RingApp { + + RingApp() + + main(args : String[]) {static} + } + class RingInstance { + - LOGGER : Logger {static} + + RingInstance(messageManager : MessageManager, localId : int, leaderId : int) + # handleElectionInvokeMessage() + # handleElectionMessage(message : Message) + # handleHeartbeatInvokeMessage() + # handleHeartbeatMessage(message : Message) + # handleLeaderInvokeMessage() + # handleLeaderMessage(message : Message) + } + class RingMessageManager { + + RingMessageManager(instanceMap : Map) + + sendElectionMessage(currentId : int, content : String) : boolean + + sendHeartbeatInvokeMessage(currentId : int) + + sendHeartbeatMessage(leaderId : int) : boolean + + sendLeaderMessage(currentId : int, leaderId : int) : boolean + } +} +package com.iluwatar.leaderelection { + abstract class AbstractInstance { + # HEARTBEAT_INTERVAL : int {static} + - LOGGER : Logger {static} + # alive : boolean + # leaderId : int + # localId : int + # messageManager : MessageManager + # messageQueue : Queue + + AbstractInstance(messageManager : MessageManager, localId : int, leaderId : int) + # handleElectionInvokeMessage() {abstract} + # handleElectionMessage(Message) {abstract} + # handleHeartbeatInvokeMessage() {abstract} + # handleHeartbeatMessage(Message) {abstract} + # handleLeaderInvokeMessage() {abstract} + # handleLeaderMessage(Message) {abstract} + + isAlive() : boolean + + onMessage(message : Message) + - processMessage(message : Message) + + run() + + setAlive(alive : boolean) + } + abstract class AbstractMessageManager { + # instanceMap : Map + + AbstractMessageManager(instanceMap : Map) + # findNextInstance(currentId : int) : Instance + } + interface Instance { + + isAlive() : boolean {abstract} + + onMessage(Message) {abstract} + + setAlive(boolean) {abstract} + } + class Message { + - content : String + - type : MessageType + + Message() + + Message(type : MessageType, content : String) + + equals(o : Object) : boolean + + getContent() : String + + getType() : MessageType + + hashCode() : int + + setContent(content : String) + + setType(type : MessageType) + } + interface MessageManager { + + sendElectionMessage(int, String) : boolean {abstract} + + sendHeartbeatInvokeMessage(int) {abstract} + + sendHeartbeatMessage(int) : boolean {abstract} + + sendLeaderMessage(int, int) : boolean {abstract} + } + enum MessageType { + + ELECTION {static} + + ELECTION_INVOKE {static} + + HEARTBEAT {static} + + HEARTBEAT_INVOKE {static} + + LEADER {static} + + LEADER_INVOKE {static} + + valueOf(name : String) : MessageType {static} + + values() : MessageType[] {static} + } +} +package com.iluwatar.leaderelection.bully { + class BullyApp { + + BullyApp() + + main(args : String[]) {static} + } + class BullyInstance { + - LOGGER : Logger {static} + + BullyInstance(messageManager : MessageManager, localId : int, leaderId : int) + # handleElectionInvokeMessage() + # handleElectionMessage(message : Message) + # handleHeartbeatInvokeMessage() + # handleHeartbeatMessage(message : Message) + # handleLeaderInvokeMessage() + # handleLeaderMessage(message : Message) + - isLeader() : boolean + } + class BullyMessageManager { + + BullyMessageManager(instanceMap : Map) + - findElectionCandidateInstanceList(currentId : int) : List + + sendElectionMessage(currentId : int, content : String) : boolean + + sendHeartbeatInvokeMessage(currentId : int) + + sendHeartbeatMessage(leaderId : int) : boolean + + sendLeaderMessage(currentId : int, leaderId : int) : boolean + } +} +AbstractInstance --> "-messageQueue" Message +Message --> "-type" MessageType +AbstractInstance --> "-messageManager" MessageManager +AbstractInstance ..|> Instance +AbstractMessageManager ..|> MessageManager +BullyInstance --|> AbstractInstance +BullyMessageManager --|> AbstractMessageManager +RingInstance --|> AbstractInstance +RingMessageManager --|> AbstractMessageManager +@enduml \ No newline at end of file diff --git a/etc/leader-followers.png b/etc/leader-followers.png new file mode 100644 index 000000000000..de8efd9f0b6b Binary files /dev/null and b/etc/leader-followers.png differ diff --git a/etc/leader-followers.urm.puml b/etc/leader-followers.urm.puml new file mode 100644 index 000000000000..fc674a518aa8 --- /dev/null +++ b/etc/leader-followers.urm.puml @@ -0,0 +1,54 @@ +@startuml +package com.iluwatar.leaderfollowers { + class App { + + App() + - addTasks(taskSet : TaskSet) {static} + - execute(workCenter : WorkCenter, taskSet : TaskSet) {static} + + main(args : String[]) {static} + } + class Task { + - finished : boolean + - time : int + + Task(time : int) + + getTime() : int + + isFinished() : boolean + + setFinished() + } + class TaskHandler { + + TaskHandler() + + handleTask(task : Task) + } + class TaskSet { + - queue : BlockingQueue + + TaskSet() + + addTask(task : Task) + + getSize() : int + + getTask() : Task + } + class WorkCenter { + - leader : Worker + - workers : List + + WorkCenter() + + addWorker(worker : Worker) + + createWorkers(numberOfWorkers : int, taskSet : TaskSet, taskHandler : TaskHandler) + + getLeader() : Worker + + getWorkers() : List + + promoteLeader() + + removeWorker(worker : Worker) + } + class Worker { + - id : long + - taskHandler : TaskHandler + - taskSet : TaskSet + - workCenter : WorkCenter + + Worker(id : long, workCenter : WorkCenter, taskSet : TaskSet, taskHandler : TaskHandler) + + equals(o : Object) : boolean + + hashCode() : int + + run() + } +} +Worker --> "-taskSet" TaskSet +Worker --> "-taskHandler" TaskHandler +TaskSet --> "-queue" Task +Worker --> "-workCenter" WorkCenter +@enduml \ No newline at end of file diff --git a/etc/lockable-object.urm.png b/etc/lockable-object.urm.png new file mode 100644 index 000000000000..431244f2b314 Binary files /dev/null and b/etc/lockable-object.urm.png differ diff --git a/etc/lockable-object.urm.puml b/etc/lockable-object.urm.puml new file mode 100644 index 000000000000..646cc3bc5a06 --- /dev/null +++ b/etc/lockable-object.urm.puml @@ -0,0 +1,94 @@ +@startuml +package com.iluwatar.lockableobject.domain { + abstract class Creature { + - LOGGER : Logger {static} + - damage : int + - health : int + ~ instruments : Set + - name : String + - type : CreatureType + + Creature(name : String) + + acquire(lockable : Lockable) : boolean + + attack(creature : Creature) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getDamage() : int + + getHealth() : int + + getInstruments() : Set + + getName() : String + + getType() : CreatureType + + hashCode() : int + + hit(damage : int) + + isAlive() : boolean + + kill() + + setDamage(damage : int) + + setHealth(health : int) + + setInstruments(instruments : Set) + + setName(name : String) + + setType(type : CreatureType) + + toString() : String + } + enum CreatureType { + + ELF {static} + + HUMAN {static} + + ORC {static} + + valueOf(name : String) : CreatureType {static} + + values() : CreatureType[] {static} + } + class Elf { + + Elf(name : String) + } + class Feind { + - LOGGER : Logger {static} + - feind : Creature + - target : Lockable + + Feind(feind : Creature, target : Lockable) + - fightForTheSword(reacher : Creature, holder : Creature, sword : Lockable) + + run() + } + class Human { + + Human(name : String) + } + class Orc { + + Orc(name : String) + } +} +package com.iluwatar.lockableobject { + class App { + - LOGGER : Logger {static} + - MULTIPLICATION_FACTOR : int {static} + - WAIT_TIME : int {static} + - WORKERS : int {static} + + App() + + main(args : String[]) {static} + } + interface Lockable { + + getLocker() : Creature {abstract} + + getName() : String {abstract} + + isLocked() : boolean {abstract} + + lock(Creature) : boolean {abstract} + + unlock(Creature) {abstract} + } + class SwordOfAragorn { + - LOGGER : Logger {static} + - NAME : String {static} + - locker : Creature + - synchronizer : Object + + SwordOfAragorn() + + getLocker() : Creature + + getName() : String + + isLocked() : boolean + + lock(creature : Creature) : boolean + + unlock(creature : Creature) + } +} +Creature --> "-type" CreatureType +Creature --> "-instruments" Lockable +Feind --> "-feind" Creature +Feind --> "-target" Lockable +SwordOfAragorn --> "-locker" Creature +SwordOfAragorn ..|> Lockable +Elf --|> Creature +Human --|> Creature +Orc --|> Creature +@enduml \ No newline at end of file diff --git a/etc/marker.urm.puml b/etc/marker.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/etc/marker.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/etc/master-worker-pattern.urm.png b/etc/master-worker-pattern.urm.png new file mode 100644 index 000000000000..a4c7a16d3ac9 Binary files /dev/null and b/etc/master-worker-pattern.urm.png differ diff --git a/etc/master-worker-pattern.urm.puml b/etc/master-worker-pattern.urm.puml new file mode 100644 index 000000000000..b3b5add30671 --- /dev/null +++ b/etc/master-worker-pattern.urm.puml @@ -0,0 +1,78 @@ +@startuml +package com.iluwatar.masterworker.system.systemmaster { + class ArrayTransposeMaster { + + ArrayTransposeMaster(numOfWorkers : int) + ~ aggregateData() : ArrayResult + ~ setWorkers(num : int) : ArrayList + } + abstract class Master { + - allResultData : Hashtable> + - expectedNumResults : int + - finalResult : Result + - numOfWorkers : int + - workers : ArrayList + ~ Master(numOfWorkers : int) + ~ aggregateData() : Result {abstract} + - collectResult(data : Result, workerId : int) + - divideWork(input : Input) + + doWork(input : Input) + ~ getAllResultData() : Hashtable> + ~ getExpectedNumResults() : int + + getFinalResult() : Result + ~ getWorkers() : ArrayList + + receiveData(data : Result, w : Worker) + ~ setWorkers(int) : ArrayList {abstract} + } +} +package com.iluwatar.masterworker.system { + class ArrayTransposeMasterWorker { + + ArrayTransposeMasterWorker() + ~ setMaster(numOfWorkers : int) : Master + } + abstract class MasterWorker { + - master : Master + + MasterWorker(numOfWorkers : int) + + getResult(input : Input) : Result + ~ setMaster(int) : Master {abstract} + } +} +package com.iluwatar.masterworker { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class ArrayInput { + + ArrayInput(data : int[][]) + + divideData(num : int) : ArrayList> + ~ makeDivisions(data : int[][], num : int) : int[] {static} + } + class ArrayResult { + + ArrayResult(data : int[][]) + } + class ArrayUtilityMethods { + - LOGGER : Logger {static} + - RANDOM : Random {static} + + ArrayUtilityMethods() + + arraysSame(a1 : int[], a2 : int[]) : boolean {static} + + createRandomIntMatrix(rows : int, columns : int) : int[][] {static} + + matricesSame(m1 : int[][], m2 : int[][]) : boolean {static} + + printMatrix(matrix : int[][]) {static} + } + abstract class Input { + + data : T + + Input(data : T) + + divideData(int) : ArrayList> {abstract} + } + abstract class Result { + + data : T + + Result(data : T) + } +} +Master --> "-finalResult" Result +MasterWorker --> "-master" Master +ArrayInput --|> Input +ArrayResult --|> Result +ArrayTransposeMasterWorker --|> MasterWorker +ArrayTransposeMaster --|> Master +@enduml \ No newline at end of file diff --git a/etc/mediator.png b/etc/mediator.png new file mode 100644 index 000000000000..1ba1984ee1a8 Binary files /dev/null and b/etc/mediator.png differ diff --git a/etc/mediator.ucls b/etc/mediator.ucls new file mode 100644 index 000000000000..1f3ead9fa40e --- /dev/null +++ b/etc/mediator.ucls @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/mediator.urm.puml b/etc/mediator.urm.puml new file mode 100644 index 000000000000..04e75d2b8841 --- /dev/null +++ b/etc/mediator.urm.puml @@ -0,0 +1,69 @@ +@startuml +package com.iluwatar.mediator { + enum Action { + + ENEMY {static} + + GOLD {static} + + HUNT {static} + + NONE {static} + + TALE {static} + - description : String + - title : String + + getDescription() : String + + toString() : String + + valueOf(name : String) : Action {static} + + values() : Action[] {static} + } + class App { + + App() + + main(args : String[]) {static} + } + class Hobbit { + + Hobbit() + + toString() : String + } + class Hunter { + + Hunter() + + toString() : String + } + interface Party { + + act(PartyMember, Action) {abstract} + + addMember(PartyMember) {abstract} + } + class PartyImpl { + - members : List + + PartyImpl() + + act(actor : PartyMember, action : Action) + + addMember(member : PartyMember) + } + interface PartyMember { + + act(Action) {abstract} + + joinedParty(Party) {abstract} + + partyAction(Action) {abstract} + } + abstract class PartyMemberBase { + - LOGGER : Logger {static} + # party : Party + + PartyMemberBase() + + act(action : Action) + + joinedParty(party : Party) + + partyAction(action : Action) + + toString() : String {abstract} + } + class Rogue { + + Rogue() + + toString() : String + } + class Wizard { + + Wizard() + + toString() : String + } +} +PartyImpl --> "-members" PartyMember +PartyMemberBase --> "-party" Party +Hobbit --|> PartyMemberBase +Hunter --|> PartyMemberBase +PartyImpl ..|> Party +PartyMemberBase ..|> PartyMember +Rogue --|> PartyMemberBase +Wizard --|> PartyMemberBase +@enduml \ No newline at end of file diff --git a/etc/mediator_1.png b/etc/mediator_1.png new file mode 100644 index 000000000000..0b48ffdbaee7 Binary files /dev/null and b/etc/mediator_1.png differ diff --git a/etc/memento.png b/etc/memento.png new file mode 100644 index 000000000000..dcfe7a749b04 Binary files /dev/null and b/etc/memento.png differ diff --git a/etc/memento.ucls b/etc/memento.ucls new file mode 100644 index 000000000000..a9455cbbe382 --- /dev/null +++ b/etc/memento.ucls @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/memento.urm.puml b/etc/memento.urm.puml new file mode 100644 index 000000000000..319227ad242c --- /dev/null +++ b/etc/memento.urm.puml @@ -0,0 +1,49 @@ +@startuml +package com.iluwatar.memento { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Star { + - ageYears : int + - massTons : int + - type : StarType + + Star(startType : StarType, startAge : int, startMass : int) + ~ getMemento() : StarMemento + ~ setMemento(memento : StarMemento) + + timePasses() + + toString() : String + } + -class StarMementoInternal { + - ageYears : int + - massTons : int + - type : StarType + - StarMementoInternal() + + getAgeYears() : int + + getMassTons() : int + + getType() : StarType + + setAgeYears(ageYears : int) + + setMassTons(massTons : int) + + setType(type : StarType) + } + interface StarMemento { + } + enum StarType { + + DEAD {static} + + RED_GIANT {static} + + SUN {static} + + SUPERNOVA {static} + + UNDEFINED {static} + + WHITE_DWARF {static} + - title : String + + toString() : String + + valueOf(name : String) : StarType {static} + + values() : StarType[] {static} + } +} +StarMementoInternal --> "-type" StarType +Star --> "-type" StarType +StarMementoInternal ..+ Star +StarMementoInternal ..|> StarMemento +@enduml \ No newline at end of file diff --git a/etc/message-channel.png b/etc/message-channel.png new file mode 100644 index 000000000000..7db473281aff Binary files /dev/null and b/etc/message-channel.png differ diff --git a/etc/message-channel.ucls b/etc/message-channel.ucls new file mode 100644 index 000000000000..3ef0ed4bc8fd --- /dev/null +++ b/etc/message-channel.ucls @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/metadata-mapping.urm.puml b/etc/metadata-mapping.urm.puml new file mode 100644 index 000000000000..41c097a81f18 --- /dev/null +++ b/etc/metadata-mapping.urm.puml @@ -0,0 +1,55 @@ +@startuml +package com.iluwatar.metamapping.model { + class User { + - id : Integer + - password : String + - username : String + + User() + + User(username : String, password : String) + + getId() : Integer + + getPassword() : String + + getUsername() : String + + setId(id : Integer) + + setPassword(password : String) + + setUsername(username : String) + + toString() : String + } +} +package com.iluwatar.metamapping.utils { + class DatabaseUtil { + - CREATE_SCHEMA_SQL : String {static} + - DB_URL : String {static} + - LOGGER : Logger {static} + - DatabaseUtil() + } + class HibernateUtil { + - LOGGER : Logger {static} + - sessionFactory : SessionFactory {static} + - HibernateUtil() + - buildSessionFactory() : SessionFactory {static} + + getSessionFactory() : SessionFactory {static} + + shutdown() {static} + } +} +package com.iluwatar.metamapping { + class App { + - LOGGER : Logger {static} + + App() + + generateSampleUsers() : List {static} + + main(args : String[]) {static} + } +} +package com.iluwatar.metamapping.service { + class UserService { + - LOGGER : Logger {static} + - factory : SessionFactory {static} + + UserService() + + close() + + createUser(user : User) : int + + deleteUser(id : Integer) + + getUser(id : Integer) : User + + listUser() : List + + updateUser(id : Integer, user : User) + } +} +@enduml \ No newline at end of file diff --git a/etc/metamapping.png b/etc/metamapping.png new file mode 100644 index 000000000000..b1e89f8af56f Binary files /dev/null and b/etc/metamapping.png differ diff --git a/etc/metamapping.puml b/etc/metamapping.puml new file mode 100644 index 000000000000..daa8c37de36e --- /dev/null +++ b/etc/metamapping.puml @@ -0,0 +1,32 @@ +@startuml +interface com.iluwatar.metamapping.service.UserService { ++ List listUser() ++ int createUser(User) ++ void updateUser(Integer,User) ++ void deleteUser(Integer) ++ User getUser(Integer) ++ void close() +} +class com.iluwatar.metamapping.utils.DatabaseUtil { ++ {static} void createDataSource() +} +class com.iluwatar.metamapping.model.User { +- Integer id +- String username +- String password ++ User(String username, String password) +} +class com.iluwatar.metamapping.utils.HibernateUtil { ++ {static} SessionFactory getSessionFactory() ++ {static} void shutdown() +} +class com.iluwatar.metamapping.App { ++ {static} void main(String[]) ++ {static} List generateSampleUsers() +} + +com.iluwatar.metamapping.service.UserService <.. com.iluwatar.metamapping.App +com.iluwatar.metamapping.model.User <.. com.iluwatar.metamapping.service.UserService +com.iluwatar.metamapping.utils.HibernateUtil <.. com.iluwatar.metamapping.service.UserService +com.iluwatar.metamapping.utils.DatabaseUtil <-- com.iluwatar.metamapping.utils.HibernateUtil +@enduml \ No newline at end of file diff --git a/etc/model-view-controller.png b/etc/model-view-controller.png new file mode 100644 index 000000000000..90071bfc1345 Binary files /dev/null and b/etc/model-view-controller.png differ diff --git a/etc/model-view-controller.ucls b/etc/model-view-controller.ucls new file mode 100644 index 000000000000..80e05a7302a5 --- /dev/null +++ b/etc/model-view-controller.ucls @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/model-view-controller.urm.puml b/etc/model-view-controller.urm.puml new file mode 100644 index 000000000000..92ec1e949d83 --- /dev/null +++ b/etc/model-view-controller.urm.puml @@ -0,0 +1,70 @@ +@startuml +package com.iluwatar.model.view.controller { + class App { + + App() + + main(args : String[]) {static} + } + enum Fatigue { + + ALERT {static} + + SLEEPING {static} + + TIRED {static} + - title : String + + toString() : String + + valueOf(name : String) : Fatigue {static} + + values() : Fatigue[] {static} + } + class GiantController { + - giant : GiantModel + - view : GiantView + + GiantController(giant : GiantModel, view : GiantView) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + updateView() + } + class GiantModel { + - fatigue : Fatigue + - health : Health + - nourishment : Nourishment + ~ GiantModel(health : Health, fatigue : Fatigue, nourishment : Nourishment) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + toString() : String + } + class GiantView { + - LOGGER : Logger {static} + + GiantView() + + displayGiant(giant : GiantModel) + } + enum Health { + + DEAD {static} + + HEALTHY {static} + + WOUNDED {static} + - title : String + + toString() : String + + valueOf(name : String) : Health {static} + + values() : Health[] {static} + } + enum Nourishment { + + HUNGRY {static} + + SATURATED {static} + + STARVING {static} + - title : String + + toString() : String + + valueOf(name : String) : Nourishment {static} + + values() : Nourishment[] {static} + } +} +GiantModel --> "-nourishment" Nourishment +GiantController --> "-giant" GiantModel +GiantModel --> "-fatigue" Fatigue +GiantModel --> "-health" Health +GiantController --> "-view" GiantView +@enduml \ No newline at end of file diff --git a/etc/model-view-presenter.png b/etc/model-view-presenter.png new file mode 100644 index 000000000000..71e18c4318e5 Binary files /dev/null and b/etc/model-view-presenter.png differ diff --git a/etc/model-view-presenter.ucls b/etc/model-view-presenter.ucls new file mode 100644 index 000000000000..70e905d3f537 --- /dev/null +++ b/etc/model-view-presenter.ucls @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/model-view-presenter.urm.puml b/etc/model-view-presenter.urm.puml new file mode 100644 index 000000000000..bedb232cb5a7 --- /dev/null +++ b/etc/model-view-presenter.urm.puml @@ -0,0 +1,90 @@ +@startuml +package com.iluwatar.model.view.presenter { + class App { + + App() + + main(args : String[]) {static} + } + class FileLoader { + - LOGGER : Logger {static} + - fileName : String + - loaded : boolean + - serialVersionUID : long {static} + + FileLoader() + + fileExists() : boolean + + getFileName() : String + + isLoaded() : boolean + + loadData() : String + + setFileName(fileName : String) + } + class FileSelectorJFrame { + - area : JTextArea + - cancel : JButton + - contents : JLabel + - fileName : String + - info : JLabel + - input : JTextField + - ok : JButton + - panel : JPanel + - presenter : FileSelectorPresenter + - serialVersionUID : long {static} + + FileSelectorJFrame() + + actionPerformed(e : ActionEvent) + + close() + + displayData(data : String) + + getFileName() : String + + getPresenter() : FileSelectorPresenter + + isOpened() : boolean + + open() + + setFileName(name : String) + + setPresenter(presenter : FileSelectorPresenter) + + showMessage(message : String) + } + class FileSelectorPresenter { + - loader : FileLoader + - serialVersionUID : long {static} + - view : FileSelectorView + + FileSelectorPresenter(view : FileSelectorView) + + cancelled() + + confirmed() + + fileNameChanged() + + setLoader(loader : FileLoader) + + start() + } + class FileSelectorStub { + - dataDisplayed : boolean + - name : String + - numOfMessageSent : int + - opened : boolean + - presenter : FileSelectorPresenter + + FileSelectorStub() + + close() + + dataDisplayed() : boolean + + displayData(data : String) + + getFileName() : String + + getMessagesSent() : int + + getPresenter() : FileSelectorPresenter + + isOpened() : boolean + + open() + + setFileName(name : String) + + setPresenter(presenter : FileSelectorPresenter) + + showMessage(message : String) + } + interface FileSelectorView { + + close() {abstract} + + displayData(String) {abstract} + + getFileName() : String {abstract} + + getPresenter() : FileSelectorPresenter {abstract} + + isOpened() : boolean {abstract} + + open() {abstract} + + setFileName(String) {abstract} + + setPresenter(FileSelectorPresenter) {abstract} + + showMessage(String) {abstract} + } +} +FileSelectorJFrame --> "-presenter" FileSelectorPresenter +FileSelectorStub --> "-presenter" FileSelectorPresenter +FileSelectorPresenter --> "-view" FileSelectorView +FileSelectorPresenter --> "-loader" FileLoader +FileSelectorJFrame ..|> FileSelectorView +FileSelectorStub ..|> FileSelectorView +@enduml \ No newline at end of file diff --git a/etc/model-view-presenter_1.png b/etc/model-view-presenter_1.png new file mode 100644 index 000000000000..6ede7bbe2fae Binary files /dev/null and b/etc/model-view-presenter_1.png differ diff --git a/etc/model-view-viewmodel.png b/etc/model-view-viewmodel.png new file mode 100644 index 000000000000..a775ec49fe5e Binary files /dev/null and b/etc/model-view-viewmodel.png differ diff --git a/etc/model-view-viewmodel.urm.puml b/etc/model-view-viewmodel.urm.puml new file mode 100644 index 000000000000..8cd7cb4b82b2 --- /dev/null +++ b/etc/model-view-viewmodel.urm.puml @@ -0,0 +1,43 @@ +@startuml +package com.iluwatar.model.view.viewmodel { + class Book { + - author : String + - description : String + - name : String + + Book(name : String, author : String, description : String) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getAuthor() : String + + getDescription() : String + + getName() : String + + hashCode() : int + + setAuthor(author : String) + + setDescription(description : String) + + setName(name : String) + + toString() : String + } + interface BookService { + + load() : List {abstract} + } + class BookServiceImpl { + - designPatternBooks : List + + BookServiceImpl() + + load() : List + } + class BookViewModel { + - bookList : List + - bookService : BookService + - selectedBook : Book + + BookViewModel() + + deleteBook() + + getBookList() : List + + getSelectedBook() : Book + + setSelectedBook(selectedBook : Book) + } +} +BookViewModel --> "-bookService" BookService +BookServiceImpl --> "-designPatternBooks" Book +BookViewModel --> "-bookList" Book +BookViewModel --> "-selectedBook" Book +BookServiceImpl ..|> BookService +@enduml \ No newline at end of file diff --git a/etc/model.png b/etc/model.png new file mode 100644 index 000000000000..925308ecd36a Binary files /dev/null and b/etc/model.png differ diff --git a/etc/model.ucls b/etc/model.ucls new file mode 100644 index 000000000000..ed923014b40c --- /dev/null +++ b/etc/model.ucls @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/module.png b/etc/module.png new file mode 100644 index 000000000000..a26807d290c0 Binary files /dev/null and b/etc/module.png differ diff --git a/etc/module.ucls b/etc/module.ucls new file mode 100644 index 000000000000..d2519b856ae5 --- /dev/null +++ b/etc/module.ucls @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/module.urm.puml b/etc/module.urm.puml new file mode 100644 index 000000000000..b92446ca14e7 --- /dev/null +++ b/etc/module.urm.puml @@ -0,0 +1,43 @@ +@startuml +package com.iluwatar.module { + class App { + + consoleLoggerModule : ConsoleLoggerModule {static} + + fileLoggerModule : FileLoggerModule {static} + + App() + + execute(args : String[]) {static} + + main(args : String[]) {static} + + prepare() {static} + + unprepare() {static} + } + class ConsoleLoggerModule { + - LOGGER : Logger {static} + + error : PrintStream + + output : PrintStream + - singleton : ConsoleLoggerModule {static} + - ConsoleLoggerModule() + + getSingleton() : ConsoleLoggerModule {static} + + prepare() : ConsoleLoggerModule + + printErrorString(value : String) + + printString(value : String) + + unprepare() + } + class FileLoggerModule { + - ERROR_FILE : String {static} + - LOGGER : Logger {static} + - OUTPUT_FILE : String {static} + + error : PrintStream + + output : PrintStream + - singleton : FileLoggerModule {static} + - FileLoggerModule() + + getSingleton() : FileLoggerModule {static} + + prepare() : FileLoggerModule + + printErrorString(value : String) + + printString(value : String) + + unprepare() + } +} +FileLoggerModule --> "-singleton" FileLoggerModule +App --> "-consoleLoggerModule" ConsoleLoggerModule +ConsoleLoggerModule --> "-singleton" ConsoleLoggerModule +App --> "-fileLoggerModule" FileLoggerModule +@enduml \ No newline at end of file diff --git a/etc/monad.png b/etc/monad.png new file mode 100644 index 000000000000..f82e7a3e45cc Binary files /dev/null and b/etc/monad.png differ diff --git a/etc/monad.ucls b/etc/monad.ucls new file mode 100644 index 000000000000..9c98df7c6331 --- /dev/null +++ b/etc/monad.ucls @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/monad.urm.puml b/etc/monad.urm.puml new file mode 100644 index 000000000000..709ef269f66a --- /dev/null +++ b/etc/monad.urm.puml @@ -0,0 +1,36 @@ +@startuml +package com.iluwatar.monad { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + enum Sex { + + FEMALE {static} + + MALE {static} + + valueOf(name : String) : Sex {static} + + values() : Sex[] {static} + } + class User { + - age : int + - email : String + - name : String + - sex : Sex + + User(name : String, age : int, sex : Sex, email : String) + + getAge() : int + + getEmail() : String + + getName() : String + + getSex() : Sex + } + class Validator { + - exceptions : List + - obj : T + - Validator(obj : T) + + get() : T + + of(t : T) : Validator {static} + + validate(projection : Function, validation : Predicate, message : String) : Validator + + validate(validation : Predicate, message : String) : Validator + } +} +User --> "-sex" Sex +@enduml \ No newline at end of file diff --git a/etc/monitor.urm.png b/etc/monitor.urm.png new file mode 100644 index 000000000000..c00e70e3fd12 Binary files /dev/null and b/etc/monitor.urm.png differ diff --git a/etc/monitor.urm.puml b/etc/monitor.urm.puml new file mode 100644 index 000000000000..075ef85200bb --- /dev/null +++ b/etc/monitor.urm.puml @@ -0,0 +1,12 @@ +@startuml +Main - Bank : use +class Main{ + + main(args : String[]) : void +} +class Bank{ + - accounts : int[] + + Bank (accountNum : int , baseAccount : int) + + transfer(accountA : int , accountB : int , amount : int) : void {synchronized} + - getBalance() : void {synchronized} +} +@enduml diff --git a/etc/monostate.png b/etc/monostate.png new file mode 100644 index 000000000000..273fa95459d4 Binary files /dev/null and b/etc/monostate.png differ diff --git a/etc/monostate.urm.puml b/etc/monostate.urm.puml new file mode 100644 index 000000000000..c078fb7e712c --- /dev/null +++ b/etc/monostate.urm.puml @@ -0,0 +1,32 @@ +@startuml +package com.iluwatar.monostate { + class App { + + App() + + main(args : String[]) {static} + } + class LoadBalancer { + - SERVERS : List {static} + - lastServedId : int {static} + + LoadBalancer() + + addServer(server : Server) + + getLastServedId() : int + + getNoOfServers() : int + + serverRequest(request : Request) + } + class Request { + + value : String + + Request(value : String) + } + class Server { + - LOGGER : Logger {static} + + host : String + + id : int + + port : int + + Server(host : String, port : int, id : int) + + getHost() : String + + getPort() : int + + serve(request : Request) + } +} +LoadBalancer --> "-SERVERS" Server +@enduml \ No newline at end of file diff --git a/etc/multiton.png b/etc/multiton.png new file mode 100644 index 000000000000..91106463d2b2 Binary files /dev/null and b/etc/multiton.png differ diff --git a/etc/multiton.ucls b/etc/multiton.ucls new file mode 100644 index 000000000000..cfdd34676b37 --- /dev/null +++ b/etc/multiton.ucls @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/multiton.urm.puml b/etc/multiton.urm.puml new file mode 100644 index 000000000000..5380d36c3146 --- /dev/null +++ b/etc/multiton.urm.puml @@ -0,0 +1,43 @@ +@startuml +package com.iluwatar.multiton { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Nazgul { + - name : NazgulName + - nazguls : Map {static} + - Nazgul(name : NazgulName) + + getInstance(name : NazgulName) : Nazgul {static} + + getName() : NazgulName + } + enum NazgulEnum { + + ADUNAPHEL {static} + + AKHORAHIL {static} + + DWAR {static} + + HOARMURATH {static} + + JI_INDUR {static} + + KHAMUL {static} + + MURAZOR {static} + + REN {static} + + UVATHA {static} + + valueOf(name : String) : NazgulEnum {static} + + values() : NazgulEnum[] {static} + } + enum NazgulName { + + ADUNAPHEL {static} + + AKHORAHIL {static} + + DWAR {static} + + HOARMURATH {static} + + JI_INDUR {static} + + KHAMUL {static} + + MURAZOR {static} + + REN {static} + + UVATHA {static} + + valueOf(name : String) : NazgulName {static} + + values() : NazgulName[] {static} + } +} +Nazgul --> "-name" NazgulName +@enduml \ No newline at end of file diff --git a/etc/mute-idiom.png b/etc/mute-idiom.png new file mode 100644 index 000000000000..203bdafc4e68 Binary files /dev/null and b/etc/mute-idiom.png differ diff --git a/etc/mute-idiom.ucls b/etc/mute-idiom.ucls new file mode 100644 index 000000000000..7b4d2f9165e1 --- /dev/null +++ b/etc/mute-idiom.ucls @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/mute-idiom.urm.puml b/etc/mute-idiom.urm.puml new file mode 100644 index 000000000000..32d036bc8144 --- /dev/null +++ b/etc/mute-idiom.urm.puml @@ -0,0 +1,24 @@ +@startuml +package com.iluwatar.mute { + class App { + - LOGGER : Logger {static} + + App() + - acquireResource() : Resource {static} + - closeResource(resource : Resource) {static} + + main(args : String[]) {static} + - useOfLoggedMute() {static} + - useOfMute() {static} + - utilizeResource(resource : Resource) {static} + } + interface CheckedRunnable { + + run() {abstract} + } + class Mute { + - Mute() + + loggedMute(runnable : CheckedRunnable) {static} + + mute(runnable : CheckedRunnable) {static} + } + interface Resource { + } +} +@enduml \ No newline at end of file diff --git a/etc/naked-objects.png b/etc/naked-objects.png new file mode 100644 index 000000000000..eda8439a2896 Binary files /dev/null and b/etc/naked-objects.png differ diff --git a/etc/naked-objects.ucls b/etc/naked-objects.ucls new file mode 100644 index 000000000000..8e9afac6d0af --- /dev/null +++ b/etc/naked-objects.ucls @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/naked-objects.urm.puml b/etc/naked-objects.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/etc/naked-objects.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/etc/null-object.png b/etc/null-object.png new file mode 100644 index 000000000000..cb0a5409c735 Binary files /dev/null and b/etc/null-object.png differ diff --git a/etc/null-object.ucls b/etc/null-object.ucls new file mode 100644 index 000000000000..71eb0bfa6748 --- /dev/null +++ b/etc/null-object.ucls @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/null-object.urm.puml b/etc/null-object.urm.puml new file mode 100644 index 000000000000..a937a2b178e2 --- /dev/null +++ b/etc/null-object.urm.puml @@ -0,0 +1,41 @@ +@startuml +package com.iluwatar.nullobject { + class App { + + App() + + main(args : String[]) {static} + } + interface Node { + + getLeft() : Node {abstract} + + getName() : String {abstract} + + getRight() : Node {abstract} + + getTreeSize() : int {abstract} + + walk() {abstract} + } + class NodeImpl { + - LOGGER : Logger {static} + - left : Node + - name : String + - right : Node + + NodeImpl(name : String, left : Node, right : Node) + + getLeft() : Node + + getName() : String + + getRight() : Node + + getTreeSize() : int + + walk() + } + class NullNode { + - instance : NullNode {static} + - NullNode() + + getInstance() : NullNode {static} + + getLeft() : Node + + getName() : String + + getRight() : Node + + getTreeSize() : int + + walk() + } +} +NullNode --> "-instance" NullNode +NodeImpl --> "-left" Node +NodeImpl ..|> Node +NullNode ..|> Node +@enduml \ No newline at end of file diff --git a/etc/object-mother.png b/etc/object-mother.png new file mode 100644 index 000000000000..807343d9f9e4 Binary files /dev/null and b/etc/object-mother.png differ diff --git a/etc/object-mother.ucls b/etc/object-mother.ucls new file mode 100644 index 000000000000..ef6cee5eff45 --- /dev/null +++ b/etc/object-mother.ucls @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/object-mother.urm.puml b/etc/object-mother.urm.puml new file mode 100644 index 000000000000..1bb52f2ed6c6 --- /dev/null +++ b/etc/object-mother.urm.puml @@ -0,0 +1,45 @@ +@startuml +package com.iluwatar.objectmother { + class King { + ~ isDrunk : boolean + ~ isHappy : boolean + + King() + + flirt(queen : Queen) + + isHappy() : boolean + + makeDrunk() + + makeHappy() + + makeSober() + + makeUnhappy() + } + class Queen { + - isDrunk : boolean + - isFlirty : boolean + - isHappy : boolean + + Queen() + + getFlirted(king : King) : boolean + + isFlirty() : boolean + + makeDrunk() + + makeHappy() + + makeSober() + + makeUnhappy() + + setFlirtiness(flirtiness : boolean) + } + interface Royalty { + + makeDrunk() {abstract} + + makeHappy() {abstract} + + makeSober() {abstract} + + makeUnhappy() {abstract} + } + class RoyaltyObjectMother { + + RoyaltyObjectMother() + + createDrunkKing() : King {static} + + createFlirtyQueen() : Queen {static} + + createHappyDrunkKing() : King {static} + + createHappyKing() : King {static} + + createNotFlirtyQueen() : Queen {static} + + createSoberUnhappyKing() : King {static} + } +} +King ..|> Royalty +Queen ..|> Royalty +@enduml \ No newline at end of file diff --git a/etc/object-pool.png b/etc/object-pool.png new file mode 100644 index 000000000000..b8ede36c5a47 Binary files /dev/null and b/etc/object-pool.png differ diff --git a/etc/object-pool.ucls b/etc/object-pool.ucls new file mode 100644 index 000000000000..9c924a87d069 --- /dev/null +++ b/etc/object-pool.ucls @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/object-pool.urm.puml b/etc/object-pool.urm.puml new file mode 100644 index 000000000000..7f75ff248267 --- /dev/null +++ b/etc/object-pool.urm.puml @@ -0,0 +1,30 @@ +@startuml +package com.iluwatar.object.pool { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + abstract class ObjectPool { + - available : Set + - inUse : Set + + ObjectPool() + + checkIn(instance : T) + + checkOut() : T + # create() : T {abstract} + + toString() : String + } + class Oliphaunt { + - counter : AtomicInteger {static} + - id : int + + Oliphaunt() + + getId() : int + + toString() : String + } + class OliphauntPool { + + OliphauntPool() + # create() : Oliphaunt + } +} +OliphauntPool --|> ObjectPool +@enduml \ No newline at end of file diff --git a/etc/observer.png b/etc/observer.png new file mode 100644 index 000000000000..f2ab0edfeb21 Binary files /dev/null and b/etc/observer.png differ diff --git a/etc/observer.ucls b/etc/observer.ucls new file mode 100644 index 000000000000..ac1d267f89b8 --- /dev/null +++ b/etc/observer.ucls @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/observer.urm.puml b/etc/observer.urm.puml new file mode 100644 index 000000000000..497ef5fde38a --- /dev/null +++ b/etc/observer.urm.puml @@ -0,0 +1,82 @@ +@startuml +package com.iluwatar.observer { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Hobbits { + - LOGGER : Logger {static} + + Hobbits() + + update(currentWeather : WeatherType) + } + class Orcs { + - LOGGER : Logger {static} + + Orcs() + + update(currentWeather : WeatherType) + } + class Weather { + - LOGGER : Logger {static} + - currentWeather : WeatherType + - observers : List + + Weather() + + addObserver(obs : WeatherObserver) + - notifyObservers() + + removeObserver(obs : WeatherObserver) + + timePasses() + } + interface WeatherObserver { + + update(WeatherType) {abstract} + } + enum WeatherType { + + COLD {static} + + RAINY {static} + + SUNNY {static} + + WINDY {static} + + description String + + toString() : String + + getDescription() : String + + valueOf(name : String) : WeatherType {static} + + values() : WeatherType[] {static} + } +} +package com.iluwatar.observer.generic { + class GHobbits { + - LOGGER : Logger {static} + + GHobbits() + + update(weather : GWeather, weatherType : WeatherType) + } + class GOrcs { + - LOGGER : Logger {static} + + GOrcs() + + update(weather : GWeather, weatherType : WeatherType) + } + class GWeather { + - LOGGER : Logger {static} + - currentWeather : WeatherType + + GWeather() + + timePasses() + } + abstract class Observable, A> { + # observers : List> + + Observable, A>() + + addObserver(observer : O extends Observer) + + notifyObservers(argument : A) + + removeObserver(observer : O extends Observer) + } + interface Observer, O extends Observer, A> { + + update(S extends Observable, A) {abstract} + } + interface Race { + } +} +Weather --> "-currentWeather" WeatherType +GWeather --> "-currentWeather" WeatherType +Weather --> "-observers" WeatherObserver +Hobbits ..|> WeatherObserver +Orcs ..|> WeatherObserver +GHobbits ..|> Race +GOrcs ..|> Race +GWeather --|> Observable +Race --|> Observer +@enduml diff --git a/etc/observer_1.png b/etc/observer_1.png new file mode 100644 index 000000000000..a272eef328ef Binary files /dev/null and b/etc/observer_1.png differ diff --git a/etc/observer_with_generics.png b/etc/observer_with_generics.png new file mode 100644 index 000000000000..06ff0d9cc246 Binary files /dev/null and b/etc/observer_with_generics.png differ diff --git a/etc/openwhisk-black.png b/etc/openwhisk-black.png new file mode 100644 index 000000000000..e70139088b7d Binary files /dev/null and b/etc/openwhisk-black.png differ diff --git a/etc/page-object.png b/etc/page-object.png new file mode 100644 index 000000000000..4240b438efbb Binary files /dev/null and b/etc/page-object.png differ diff --git a/etc/page-object.ucls b/etc/page-object.ucls new file mode 100644 index 000000000000..466c542fd238 --- /dev/null +++ b/etc/page-object.ucls @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/etc/page-object.urm.puml b/etc/page-object.urm.puml new file mode 100644 index 000000000000..02af47ddf261 --- /dev/null +++ b/etc/page-object.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/etc/parameter-object.png b/etc/parameter-object.png new file mode 100644 index 000000000000..661c3488ac49 Binary files /dev/null and b/etc/parameter-object.png differ diff --git a/etc/parameter-object.urm.puml b/etc/parameter-object.urm.puml new file mode 100644 index 000000000000..6cdab214110c --- /dev/null +++ b/etc/parameter-object.urm.puml @@ -0,0 +1,52 @@ +@startuml +package com.iluwatar.parameter.object { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class ParameterObject { + + DEFAULT_SORT_BY : String {static} + + DEFAULT_SORT_ORDER : SortOrder {static} + - sortBy : String + - sortOrder : SortOrder + - type : String + - ParameterObject(builder : Builder) + + getSortBy() : String + + getSortOrder() : SortOrder + + getType() : String + + newBuilder() : Builder {static} + + setSortBy(sortBy : String) + + setSortOrder(sortOrder : SortOrder) + + setType(type : String) + } + class Builder { + - sortBy : String + - sortOrder : SortOrder + - type : String + - Builder() + + build() : ParameterObject + + sortBy(sortBy : String) : Builder + + sortOrder(sortOrder : SortOrder) : Builder + + withType(type : String) : Builder + } + class SearchService { + + SearchService() + - getQuerySummary(type : String, sortBy : String, sortOrder : SortOrder) : String + + search(parameterObject : ParameterObject) : String + + search(type : String, sortBy : String) : String + + search(type : String, sortOrder : SortOrder) : String + } + enum SortOrder { + + ASC {static} + + DESC {static} + - value : String + + getValue() : String + + valueOf(name : String) : SortOrder {static} + + values() : SortOrder[] {static} + } +} +Builder --> "-sortOrder" SortOrder +Builder ..+ ParameterObject +ParameterObject --> "-DEFAULT_SORT_ORDER" SortOrder +@enduml diff --git a/etc/partial-response.ucls b/etc/partial-response.ucls new file mode 100644 index 000000000000..a0b029496352 --- /dev/null +++ b/etc/partial-response.ucls @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/partial-response.urm.png b/etc/partial-response.urm.png new file mode 100644 index 000000000000..17dbd5f1b60d Binary files /dev/null and b/etc/partial-response.urm.png differ diff --git a/etc/partial-response.urm.puml b/etc/partial-response.urm.puml new file mode 100644 index 000000000000..4b041a8a0066 --- /dev/null +++ b/etc/partial-response.urm.puml @@ -0,0 +1,31 @@ +@startuml +package com.iluwatar.partialresponse { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class FieldJsonMapper { + + FieldJsonMapper() + - getString(video : Video, declaredField : Field) : String + + toJson(video : Video, fields : String[]) : String + } + class Video { + - description : String + - director : String + - id : Integer + - language : String + - length : Integer + - title : String + + Video(id : Integer, title : String, len : Integer, desc : String, director : String, lang : String) + + toString() : String + } + class VideoResource { + - fieldJsonMapper : FieldJsonMapper + - videos : Map + + VideoResource(fieldJsonMapper : FieldJsonMapper, videos : Map) + + getDetails(id : Integer, fields : String[]) : String + } +} +VideoResource --> "-fieldJsonMapper" FieldJsonMapper +@enduml \ No newline at end of file diff --git a/etc/pipeline.urm.png b/etc/pipeline.urm.png new file mode 100644 index 000000000000..4110f1624665 Binary files /dev/null and b/etc/pipeline.urm.png differ diff --git a/etc/pipeline.urm.puml b/etc/pipeline.urm.puml new file mode 100644 index 000000000000..50bee48c567e --- /dev/null +++ b/etc/pipeline.urm.puml @@ -0,0 +1,36 @@ +@startuml +package com.iluwatar.pipeline { + class App { + + App() + + main(args : String[]) {static} + } + ~class ConvertToCharArrayHandler { + - LOGGER : Logger {static} + ~ ConvertToCharArrayHandler() + + process(input : String) : char[] + } + ~interface Handler { + + process(I) : O {abstract} + } + ~class Pipeline { + - currentHandler : Handler + ~ Pipeline(currentHandler : Handler) + ~ addHandler(newHandler : Handler) : Pipeline + ~ execute(input : I) : O + } + ~class RemoveAlphabetsHandler { + - LOGGER : Logger {static} + ~ RemoveAlphabetsHandler() + + process(input : String) : String + } + ~class RemoveDigitsHandler { + - LOGGER : Logger {static} + ~ RemoveDigitsHandler() + + process(input : String) : String + } +} +Pipeline --> "-currentHandler" Handler +ConvertToCharArrayHandler ..|> Handler +RemoveAlphabetsHandler ..|> Handler +RemoveDigitsHandler ..|> Handler +@enduml \ No newline at end of file diff --git a/etc/poison-pill.png b/etc/poison-pill.png new file mode 100644 index 000000000000..bfca5848e082 Binary files /dev/null and b/etc/poison-pill.png differ diff --git a/etc/poison-pill.ucls b/etc/poison-pill.ucls new file mode 100644 index 000000000000..6d20b1974dfc --- /dev/null +++ b/etc/poison-pill.ucls @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/poison-pill.urm.puml b/etc/poison-pill.urm.puml new file mode 100644 index 000000000000..923449e10b4a --- /dev/null +++ b/etc/poison-pill.urm.puml @@ -0,0 +1,71 @@ +@startuml +package com.iluwatar.poison.pill { + class App { + + App() + + main(args : String[]) {static} + } + class Consumer { + - LOGGER : Logger {static} + - name : String + - queue : MqSubscribePoint + + Consumer(name : String, queue : MqSubscribePoint) + + consume() + } + interface Message { + + POISON_PILL : Message {static} + + addHeader(Headers, String) {abstract} + + getBody() : String {abstract} + + getHeader(Headers) : String {abstract} + + getHeaders() : Map {abstract} + + setBody(String) {abstract} + } + enum Headers { + + DATE {static} + + SENDER {static} + + valueOf(name : String) : Headers {static} + + values() : Headers[] {static} + } + interface MessageQueue { + } + interface MqPublishPoint { + + put(Message) {abstract} + } + interface MqSubscribePoint { + + take() : Message {abstract} + } + class Producer { + - LOGGER : Logger {static} + - isStopped : boolean + - name : String + - queue : MqPublishPoint + + Producer(name : String, queue : MqPublishPoint) + + send(body : String) + + stop() + } + class SimpleMessage { + - body : String + - headers : Map + + SimpleMessage() + + addHeader(header : Headers, value : String) + + getBody() : String + + getHeader(header : Headers) : String + + getHeaders() : Map + + setBody(body : String) + } + class SimpleMessageQueue { + - queue : BlockingQueue + + SimpleMessageQueue(bound : int) + + put(msg : Message) + + take() : Message + } +} +SimpleMessageQueue --> "-queue" Message +Headers ..+ Message +Consumer --> "-queue" MqSubscribePoint +Producer --> "-queue" MqPublishPoint +Message --> "-POISON_PILL" Message +MessageQueue --|> MqPublishPoint +MessageQueue --|> MqSubscribePoint +SimpleMessage ..|> Message +SimpleMessageQueue ..|> MessageQueue +@enduml \ No newline at end of file diff --git a/etc/presentation-model.urm.png b/etc/presentation-model.urm.png new file mode 100644 index 000000000000..46690641cb82 Binary files /dev/null and b/etc/presentation-model.urm.png differ diff --git a/etc/presentation-model.urm.puml b/etc/presentation-model.urm.puml new file mode 100644 index 000000000000..8e7bc46a0793 --- /dev/null +++ b/etc/presentation-model.urm.puml @@ -0,0 +1,59 @@ +@startuml +package com.iluwatar.presentationmodel { + class Album { + ~ artist : String + ~ composer : String + ~ isClassical : boolean + ~ rowId : int + ~ title : String + + Album(rowId : int, title : String, artist : String, isClassical : boolean, composer : String) + } + class App { + + App() + + main(args : String[]) {static} + } + class DsAlbum { + + albums : List + + albumsCache : List + + DsAlbum() + + acceptChanges() + + addAlbums(rowId : int, title : String, artist : String, isClassical : boolean, composer : String) + } + class PresentationMod { + - data : DsAlbum + - selectedAlbum : Album + - selectedAlbumNumber : int + + PresentationMod(data : DsAlbum) + + albumDataSet() : DsAlbum {static} + + getAlbumList() : String[] + + getArtist() : String + + getComposer() : String + + getIsClassical() : boolean + + getTitle() : String + + setArtist(value : String) + + setComposer(value : String) + + setIsClassical(value : boolean) + + setSelectedAlbumNumber(selectedAlbumNumber : int) + + setTitle(value : String) + } + class View { + ~ albumList : JList + ~ apply : JButton + ~ cancel : JButton + ~ chkClassical : JCheckBox + ~ model : PresentationMod + ~ notLoadView : boolean + ~ txtArtist : TextField + ~ txtComposer : TextField + ~ txtTitle : TextField + + View() + + createView() + + loadFromPMod() + + saveToPMod() + } +} +PresentationMod --> "-selectedAlbum" Album +View --> "-model" PresentationMod +DsAlbum --> "-albums" Album +PresentationMod --> "-data" DsAlbum +@enduml \ No newline at end of file diff --git a/etc/priority-queue.urm.png b/etc/priority-queue.urm.png new file mode 100644 index 000000000000..e0b4295a5986 Binary files /dev/null and b/etc/priority-queue.urm.png differ diff --git a/etc/priority-queue.urm.puml b/etc/priority-queue.urm.puml new file mode 100644 index 000000000000..cee118f57671 --- /dev/null +++ b/etc/priority-queue.urm.puml @@ -0,0 +1,54 @@ +@startuml +package com.iluwatar.priority.queue { + class Application { + + Application() + + main(args : String[]) {static} + } + class Message { + - message : String + - priority : int + + Message(message : String, priority : int) + + compareTo(o : Message) : int + + toString() : String + } + class PriorityMessageQueue { + - LOGGER : Logger {static} + - capacity : int + - queue : T[] + - size : int + + PriorityMessageQueue(queue : T[]) + + add(t : T extends Comparable) + - ensureCapacity() + - hasLeftChild(index : int) : boolean + - hasParent(index : int) : boolean + - hasRightChild(index : int) : boolean + + isEmpty() : boolean + - left(parentIndex : int) : T extends Comparable + - leftChildIndex(parentPos : int) : int + - maxHeapifyDown() + - maxHeapifyUp() + - parent(childIndex : int) : T extends Comparable + - parentIndex(pos : int) : int + + print() + + remove() : T extends Comparable + - right(parentIndex : int) : T extends Comparable + - rightChildIndex(parentPos : int) : int + - swap(fpos : int, tpos : int) + } + class QueueManager { + - messagePriorityMessageQueue : PriorityMessageQueue + + QueueManager(initialCapacity : int) + + publishMessage(message : Message) + + receiveMessage() : Message + } + class Worker { + - LOGGER : Logger {static} + - queueManager : QueueManager + + Worker(queueManager : QueueManager) + - processMessage(message : Message) + + run() + } +} +QueueManager --> "-messagePriorityMessageQueue" PriorityMessageQueue +Worker --> "-queueManager" QueueManager +@enduml \ No newline at end of file diff --git a/etc/private-class-data.png b/etc/private-class-data.png new file mode 100644 index 000000000000..65c343a5faf9 Binary files /dev/null and b/etc/private-class-data.png differ diff --git a/etc/private-class-data.ucls b/etc/private-class-data.ucls new file mode 100644 index 000000000000..5d1f43d93a06 --- /dev/null +++ b/etc/private-class-data.ucls @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/private-class-data.urm.puml b/etc/private-class-data.urm.puml new file mode 100644 index 000000000000..990b53342521 --- /dev/null +++ b/etc/private-class-data.urm.puml @@ -0,0 +1,36 @@ +@startuml +package com.iluwatar.privateclassdata { + class App { + + App() + + main(args : String[]) {static} + } + class ImmutableStew { + - LOGGER : Logger {static} + - data : StewData + + ImmutableStew(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) + + mix() + } + class Stew { + - LOGGER : Logger {static} + - numCarrots : int + - numMeat : int + - numPeppers : int + - numPotatoes : int + + Stew(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) + + mix() + + taste() + } + class StewData { + - numCarrots : int + - numMeat : int + - numPeppers : int + - numPotatoes : int + + StewData(numPotatoes : int, numCarrots : int, numMeat : int, numPeppers : int) + + getNumCarrots() : int + + getNumMeat() : int + + getNumPeppers() : int + + getNumPotatoes() : int + } +} +ImmutableStew --> "-data" StewData +@enduml \ No newline at end of file diff --git a/etc/producer-consumer.png b/etc/producer-consumer.png new file mode 100644 index 000000000000..e8bc573b388f Binary files /dev/null and b/etc/producer-consumer.png differ diff --git a/etc/producer-consumer.ucls b/etc/producer-consumer.ucls new file mode 100644 index 000000000000..aa1ee80c05d7 --- /dev/null +++ b/etc/producer-consumer.ucls @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/producer-consumer.urm.puml b/etc/producer-consumer.urm.puml new file mode 100644 index 000000000000..e36374b2fdd2 --- /dev/null +++ b/etc/producer-consumer.urm.puml @@ -0,0 +1,40 @@ +@startuml +package com.iluwatar.producer.consumer { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Consumer { + - LOGGER : Logger {static} + - name : String + - queue : ItemQueue + + Consumer(name : String, queue : ItemQueue) + + consume() + } + class Item { + - id : int + - producer : String + + Item(producer : String, id : int) + + getId() : int + + getProducer() : String + } + class ItemQueue { + - queue : BlockingQueue + + ItemQueue() + + put(item : Item) + + take() : Item + } + class Producer { + - RANDOM : Random {static} + - itemId : int + - name : String + - queue : ItemQueue + + Producer(name : String, queue : ItemQueue) + + produce() + } +} +Consumer --> "-queue" ItemQueue +Producer --> "-queue" ItemQueue +ItemQueue --> "-queue" Item +@enduml \ No newline at end of file diff --git a/etc/promise.png b/etc/promise.png new file mode 100644 index 000000000000..cdb43eb6b49a Binary files /dev/null and b/etc/promise.png differ diff --git a/etc/promise.ucls b/etc/promise.ucls new file mode 100644 index 000000000000..79a11e7d5012 --- /dev/null +++ b/etc/promise.ucls @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/promise.urm.puml b/etc/promise.urm.puml new file mode 100644 index 000000000000..f3a28718e43b --- /dev/null +++ b/etc/promise.urm.puml @@ -0,0 +1,79 @@ +@startuml +package com.iluwatar.promise { + class App { + - DEFAULT_URL : String {static} + - LOGGER : Logger {static} + - executor : ExecutorService + - stopLatch : CountDownLatch + - App() + - calculateLineCount() + - calculateLowestFrequencyChar() + - characterFrequency() : Promise> + - countLines() : Promise + - download(urlString : String) : Promise + - lowestFrequencyChar() : Promise + + main(args : String[]) {static} + - promiseUsage() + - stop() + - taskCompleted() + } + class Promise { + - exceptionHandler : Consumer + - fulfillmentAction : Runnable + + Promise() + + fulfill(value : T) + + fulfillExceptionally(exception : Exception) + + fulfillInAsync(task : Callable, executor : Executor) : Promise + - handleException(exception : Exception) + + onError(exceptionHandler : Consumer) : Promise + - postFulfillment() + + thenAccept(action : Consumer) : Promise + + thenApply(func : Function) : Promise + } + -class ConsumeAction { + - action : Consumer + - dest : Promise + - src : Promise + - ConsumeAction(src : Promise, dest : Promise, action : Consumer) + + run() + } + -class TransformAction { + - dest : Promise + - func : Function + - src : Promise + - TransformAction(src : Promise, dest : Promise, func : Function) + + run() + } + ~class PromiseSupport { + - COMPLETED : int {static} + - FAILED : int {static} + - LOGGER : Logger {static} + - RUNNING : int {static} + - exception : Exception + - lock : Object + - state : int + - value : T + ~ PromiseSupport() + + cancel(mayInterruptIfRunning : boolean) : boolean + ~ fulfill(value : T) + ~ fulfillExceptionally(exception : Exception) + + get() : T + + get(timeout : long, unit : TimeUnit) : T + + isCancelled() : boolean + + isDone() : boolean + } + class Utility { + - LOGGER : Logger {static} + + Utility() + + characterFrequency(fileLocation : String) : Map {static} + + countLines(fileLocation : String) : Integer {static} + + downloadFile(urlString : String) : String {static} + + lowestFrequencyChar(charFrequency : Map) : Character {static} + } +} +TransformAction --+ Promise +TransformAction --> "-src" Promise +ConsumeAction --+ Promise +ConsumeAction --> "-src" Promise +Promise --|> PromiseSupport +@enduml \ No newline at end of file diff --git a/etc/property.png b/etc/property.png new file mode 100644 index 000000000000..98c0cbe3720c Binary files /dev/null and b/etc/property.png differ diff --git a/etc/property.ucls b/etc/property.ucls new file mode 100644 index 000000000000..8d50cb99d845 --- /dev/null +++ b/etc/property.ucls @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/property.urm.puml b/etc/property.urm.puml new file mode 100644 index 000000000000..f281cd87319f --- /dev/null +++ b/etc/property.urm.puml @@ -0,0 +1,54 @@ +@startuml +package com.iluwatar.property { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Character { + - name : String + - properties : Map + - prototype : Prototype + - type : Type + + Character() + + Character(name : String, prototype : Character) + + Character(type : Type, prototype : Prototype) + + get(stat : Stats) : Integer + + has(stat : Stats) : boolean + + name() : String + + remove(stat : Stats) + + set(stat : Stats, val : Integer) + + toString() : String + + type() : Type + } + enum Type { + + MAGE {static} + + ROGUE {static} + + WARRIOR {static} + + valueOf(name : String) : Type {static} + + values() : Type[] {static} + } + interface Prototype { + + get(Stats) : Integer {abstract} + + has(Stats) : boolean {abstract} + + remove(Stats) {abstract} + + set(Stats, Integer) {abstract} + } + enum Stats { + + AGILITY {static} + + ARMOR {static} + + ATTACK_POWER {static} + + ENERGY {static} + + INTELLECT {static} + + RAGE {static} + + SPIRIT {static} + + STRENGTH {static} + + valueOf(name : String) : Stats {static} + + values() : Stats[] {static} + } +} +Character --> "-prototype" Prototype +Type ..+ Character +Character --> "-type" Type +Character ..|> Prototype +@enduml \ No newline at end of file diff --git a/etc/prototype.urm.png b/etc/prototype.urm.png new file mode 100644 index 000000000000..b23c6d1cfb85 Binary files /dev/null and b/etc/prototype.urm.png differ diff --git a/etc/prototype.urm.puml b/etc/prototype.urm.puml new file mode 100644 index 000000000000..bd1576f3bfe2 --- /dev/null +++ b/etc/prototype.urm.puml @@ -0,0 +1,105 @@ +@startuml +package com.iluwatar.prototype { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + abstract class Beast { + + Beast() + + Beast(source : Beast) + + copy() : Beast {abstract} + + equals(obj : Object) : boolean + } + class ElfBeast { + - helpType : String + + ElfBeast(elfBeast : ElfBeast) + + ElfBeast(helpType : String) + + copy() : ElfBeast + + equals(obj : Object) : boolean + + toString() : String + } + class ElfMage { + - helpType : String + + ElfMage(elfMage : ElfMage) + + ElfMage(helpType : String) + + copy() : ElfMage + + equals(obj : Object) : boolean + + toString() : String + } + class ElfWarlord { + - helpType : String + + ElfWarlord(elfWarlord : ElfWarlord) + + ElfWarlord(helpType : String) + + copy() : ElfWarlord + + equals(obj : Object) : boolean + + toString() : String + } + interface HeroFactory { + + createBeast() : Beast {abstract} + + createMage() : Mage {abstract} + + createWarlord() : Warlord {abstract} + } + class HeroFactoryImpl { + - beast : Beast + - mage : Mage + - warlord : Warlord + + HeroFactoryImpl(mage : Mage, warlord : Warlord, beast : Beast) + + createBeast() : Beast + + createMage() : Mage + + createWarlord() : Warlord + } + abstract class Mage { + + Mage() + + Mage(source : Mage) + + copy() : Mage {abstract} + + equals(obj : Object) : boolean + } + class OrcBeast { + - weapon : String + + OrcBeast(orcBeast : OrcBeast) + + OrcBeast(weapon : String) + + copy() : OrcBeast + + equals(obj : Object) : boolean + + toString() : String + } + class OrcMage { + - weapon : String + + OrcMage(orcMage : OrcMage) + + OrcMage(weapon : String) + + copy() : OrcMage + + equals(obj : Object) : boolean + + toString() : String + } + class OrcWarlord { + - weapon : String + + OrcWarlord(orcWarlord : OrcWarlord) + + OrcWarlord(weapon : String) + + copy() : OrcWarlord + + equals(obj : Object) : boolean + + toString() : String + } + interface Prototype { + + copy() : Object {abstract} + } + abstract class Warlord { + + Warlord() + + Warlord(source : Warlord) + + copy() : Warlord {abstract} + + equals(obj : Object) : boolean + } +} +HeroFactoryImpl --> "-beast" Beast +HeroFactoryImpl --> "-warlord" Warlord +HeroFactoryImpl --> "-mage" Mage +Beast ..|> Prototype +ElfBeast --|> Beast +ElfMage --|> Mage +ElfWarlord --|> Warlord +HeroFactoryImpl ..|> HeroFactory +Mage ..|> Prototype +OrcBeast --|> Beast +OrcMage --|> Mage +OrcWarlord --|> Warlord +Warlord ..|> Prototype +@enduml \ No newline at end of file diff --git a/etc/proxy.urm.png b/etc/proxy.urm.png new file mode 100644 index 000000000000..a0c94fc7c717 Binary files /dev/null and b/etc/proxy.urm.png differ diff --git a/etc/proxy.urm.puml b/etc/proxy.urm.puml new file mode 100644 index 000000000000..ffe0fa446074 --- /dev/null +++ b/etc/proxy.urm.puml @@ -0,0 +1,32 @@ +@startuml +package com.iluwatar.proxy { + class App { + + App() + + main(args : String[]) {static} + } + class IvoryTower { + - LOGGER : Logger {static} + + IvoryTower() + + enter(wizard : Wizard) + } + class Wizard { + - name : String + + Wizard(name : String) + + toString() : String + } + interface WizardTower { + + enter(Wizard) {abstract} + } + class WizardTowerProxy { + - LOGGER : Logger {static} + - NUM_WIZARDS_ALLOWED : int {static} + - numWizards : int + - tower : WizardTower + + WizardTowerProxy(tower : WizardTower) + + enter(wizard : Wizard) + } +} +WizardTowerProxy --> "-tower" WizardTower +IvoryTower ..|> WizardTower +WizardTowerProxy ..|> WizardTower +@enduml \ No newline at end of file diff --git a/etc/publish-subscribe.png b/etc/publish-subscribe.png new file mode 100644 index 000000000000..99867da66b54 Binary files /dev/null and b/etc/publish-subscribe.png differ diff --git a/etc/publish-subscribe.ucls b/etc/publish-subscribe.ucls new file mode 100644 index 000000000000..1b121506eed8 --- /dev/null +++ b/etc/publish-subscribe.ucls @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/queue-load-leveling.gif b/etc/queue-load-leveling.gif new file mode 100644 index 000000000000..4f57c3e50701 Binary files /dev/null and b/etc/queue-load-leveling.gif differ diff --git a/etc/queue-load-leveling.ucls b/etc/queue-load-leveling.ucls new file mode 100644 index 000000000000..91440e27652f --- /dev/null +++ b/etc/queue-load-leveling.ucls @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/queue-load-leveling.urm.puml b/etc/queue-load-leveling.urm.puml new file mode 100644 index 000000000000..ca90842d92dd --- /dev/null +++ b/etc/queue-load-leveling.urm.puml @@ -0,0 +1,44 @@ +@startuml +package com.iluwatar.queue.load.leveling { + class App { + - LOGGER : Logger {static} + - SHUTDOWN_TIME : int {static} + + App() + + main(args : String[]) {static} + } + class Message { + - msg : String + + Message(msg : String) + + getMsg() : String + + toString() : String + } + class MessageQueue { + - LOGGER : Logger {static} + - blkQueue : BlockingQueue + + MessageQueue() + + retrieveMsg() : Message + + submitMsg(msg : Message) + } + class ServiceExecutor { + - LOGGER : Logger {static} + - msgQueue : MessageQueue + + ServiceExecutor(msgQueue : MessageQueue) + + run() + } + interface Task { + + submit(Message) {abstract} + } + class TaskGenerator { + - LOGGER : Logger {static} + - msgCount : int + - msgQueue : MessageQueue + + TaskGenerator(msgQueue : MessageQueue, msgCount : int) + + run() + + submit(msg : Message) + } +} +MessageQueue --> "-blkQueue" Message +ServiceExecutor --> "-msgQueue" MessageQueue +TaskGenerator --> "-msgQueue" MessageQueue +TaskGenerator ..|> Task +@enduml \ No newline at end of file diff --git a/etc/reactor.png b/etc/reactor.png new file mode 100644 index 000000000000..abe705682f6c Binary files /dev/null and b/etc/reactor.png differ diff --git a/etc/reactor.ucls b/etc/reactor.ucls new file mode 100644 index 000000000000..90e28cdd7603 --- /dev/null +++ b/etc/reactor.ucls @@ -0,0 +1,235 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/reactor.urm.puml b/etc/reactor.urm.puml new file mode 100644 index 000000000000..cc56eae7a1c8 --- /dev/null +++ b/etc/reactor.urm.puml @@ -0,0 +1,155 @@ +@startuml +package com.iluwatar.reactor.framework { + abstract class AbstractNioChannel { + - channel : SelectableChannel + - channelToPendingWrites : Map> + - handler : ChannelHandler + - reactor : NioReactor + + AbstractNioChannel(handler : ChannelHandler, channel : SelectableChannel) + + bind() {abstract} + # doWrite(Object, SelectionKey) {abstract} + ~ flush(key : SelectionKey) + + getHandler() : ChannelHandler + + getInterestedOps() : int {abstract} + + getJavaChannel() : SelectableChannel + + read(SelectionKey) : Object {abstract} + ~ setReactor(reactor : NioReactor) + + write(data : Object, key : SelectionKey) + } + interface ChannelHandler { + + handleChannelRead(AbstractNioChannel, Object, SelectionKey) {abstract} + } + interface Dispatcher { + + onChannelReadEvent(AbstractNioChannel, Object, SelectionKey) {abstract} + + stop() {abstract} + } + class NioDatagramChannel { + - LOGGER : Logger {static} + - port : int + + NioDatagramChannel(port : int, handler : ChannelHandler) + + bind() + # doWrite(pendingWrite : Object, key : SelectionKey) + + getInterestedOps() : int + + getJavaChannel() : DatagramChannel + + read(key : SelectionKey) : DatagramPacket + + write(data : Object, key : SelectionKey) + } + class DatagramPacket { + - data : ByteBuffer + - receiver : SocketAddress + - sender : SocketAddress + + DatagramPacket(data : ByteBuffer) + + getData() : ByteBuffer + + getReceiver() : SocketAddress + + getSender() : SocketAddress + + setReceiver(receiver : SocketAddress) + + setSender(sender : SocketAddress) + } + class NioReactor { + - LOGGER : Logger {static} + - dispatcher : Dispatcher + - pendingCommands : Queue + - reactorMain : ExecutorService + - selector : Selector + + NioReactor(dispatcher : Dispatcher) + + changeOps(key : SelectionKey, interestedOps : int) + - dispatchReadEvent(key : SelectionKey, readObject : Object) + - eventLoop() + - onChannelAcceptable(key : SelectionKey) + - onChannelReadable(key : SelectionKey) + - onChannelWritable(key : SelectionKey) {static} + - processKey(key : SelectionKey) + - processPendingCommands() + + registerChannel(channel : AbstractNioChannel) : NioReactor + + start() + + stop() + } + ~class ChangeKeyOpsCommand { + - interestedOps : int + - key : SelectionKey + + ChangeKeyOpsCommand(this$0 : SelectionKey, key : int) + + run() + + toString() : String + } + class NioServerSocketChannel { + - LOGGER : Logger {static} + - port : int + + NioServerSocketChannel(port : int, handler : ChannelHandler) + + bind() + # doWrite(pendingWrite : Object, key : SelectionKey) + + getInterestedOps() : int + + getJavaChannel() : ServerSocketChannel + + read(key : SelectionKey) : ByteBuffer + } + class SameThreadDispatcher { + + SameThreadDispatcher() + + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + + stop() + } + class ThreadPoolDispatcher { + - executorService : ExecutorService + + ThreadPoolDispatcher(poolSize : int) + + onChannelReadEvent(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + + stop() + } +} +package com.iluwatar.reactor.app { + class App { + - channels : List + - dispatcher : Dispatcher + - reactor : NioReactor + + App(dispatcher : Dispatcher) + + main(args : String[]) {static} + + start() + + stop() + - tcpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel + - udpChannel(port : int, handler : ChannelHandler) : AbstractNioChannel + } + class AppClient { + - LOGGER : Logger {static} + - service : ExecutorService + + AppClient() + - artificialDelayOf(millis : long) {static} + + main(args : String[]) {static} + + start() + + stop() + } + ~class TcpLoggingClient { + - clientName : String + - serverPort : int + + TcpLoggingClient(clientName : String, serverPort : int) + + run() + - sendLogRequests(writer : PrintWriter, inputStream : InputStream) + } + ~class UdpLoggingClient { + - clientName : String + - remoteAddress : InetSocketAddress + + UdpLoggingClient(clientName : String, port : int) + + run() + } + class LoggingHandler { + - ACK : byte[] {static} + - LOGGER : Logger {static} + + LoggingHandler() + - doLogging(data : ByteBuffer) {static} + + handleChannelRead(channel : AbstractNioChannel, readObject : Object, key : SelectionKey) + - sendReply(channel : AbstractNioChannel, incomingPacket : DatagramPacket, key : SelectionKey) {static} + - sendReply(channel : AbstractNioChannel, key : SelectionKey) {static} + } +} +AbstractNioChannel --> "-handler" ChannelHandler +UdpLoggingClient ..+ AppClient +TcpLoggingClient ..+ AppClient +AbstractNioChannel --> "-reactor" NioReactor +NioReactor --> "-dispatcher" Dispatcher +App --> "-reactor" NioReactor +App --> "-channels" AbstractNioChannel +DatagramPacket ..+ NioDatagramChannel +App --> "-dispatcher" Dispatcher +ChangeKeyOpsCommand --+ NioReactor +LoggingHandler ..|> ChannelHandler +NioDatagramChannel --|> AbstractNioChannel +NioServerSocketChannel --|> AbstractNioChannel +SameThreadDispatcher ..|> Dispatcher +ThreadPoolDispatcher ..|> Dispatcher +@enduml \ No newline at end of file diff --git a/etc/reader-writer-lock.png b/etc/reader-writer-lock.png new file mode 100644 index 000000000000..f7b600530926 Binary files /dev/null and b/etc/reader-writer-lock.png differ diff --git a/etc/reader-writer-lock.ucls b/etc/reader-writer-lock.ucls new file mode 100644 index 000000000000..920904e76843 --- /dev/null +++ b/etc/reader-writer-lock.ucls @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/reader-writer-lock.urm.puml b/etc/reader-writer-lock.urm.puml new file mode 100644 index 000000000000..f0e33ab3cb40 --- /dev/null +++ b/etc/reader-writer-lock.urm.puml @@ -0,0 +1,65 @@ +@startuml +package com.iluwatar.reader.writer.lock { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Reader { + - LOGGER : Logger {static} + - name : String + - readLock : Lock + - readingTime : long + + Reader(name : String, readLock : Lock) + + Reader(name : String, readLock : Lock, readingTime : long) + + read() + + run() + } + class ReaderWriterLock { + - LOGGER : Logger {static} + - currentReaderCount : int + - globalMutex : Set + - readerLock : ReadLock + - readerMutex : Object + - writerLock : WriteLock + + ReaderWriterLock() + - doesWriterOwnThisLock() : boolean + - isLockFree() : boolean + + readLock() : Lock + + writeLock() : Lock + } + -class ReadLock { + - ReadLock() + - acquireForReaders() + + lock() + + lockInterruptibly() + + newCondition() : Condition + + tryLock() : boolean + + tryLock(time : long, unit : TimeUnit) : boolean + + unlock() + } + -class WriteLock { + - WriteLock() + + lock() + + lockInterruptibly() + + newCondition() : Condition + + tryLock() : boolean + + tryLock(time : long, unit : TimeUnit) : boolean + + unlock() + } + class Writer { + - LOGGER : Logger {static} + - name : String + - writeLock : Lock + - writingTime : long + + Writer(name : String, writeLock : Lock) + + Writer(name : String, writeLock : Lock, writingTime : long) + + run() + + write() + } +} +ReaderWriterLock --> "-readerLock" ReadLock +ReadLock --+ ReaderWriterLock +WriteLock --+ ReaderWriterLock +ReaderWriterLock --> "-writerLock" WriteLock +@enduml \ No newline at end of file diff --git a/etc/registry.png b/etc/registry.png new file mode 100644 index 000000000000..6c1c5b986d72 Binary files /dev/null and b/etc/registry.png differ diff --git a/etc/registry.urm.puml b/etc/registry.urm.puml new file mode 100644 index 000000000000..77c6441fe688 --- /dev/null +++ b/etc/registry.urm.puml @@ -0,0 +1,21 @@ +@startuml +package com.iluwatar.registry { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Customer { + - id : String + - name : String + + getId() : String + + getName() : String + + toString() : String + } + class CustomerRegistry { + + addCustomer(customer : Customer) + + getCustomer(id : String) + } +} +Customer --> "-addCustomer" CustomerRegistry +@enduml diff --git a/etc/repository.png b/etc/repository.png new file mode 100644 index 000000000000..08d5d571d0a8 Binary files /dev/null and b/etc/repository.png differ diff --git a/etc/repository.ucls b/etc/repository.ucls new file mode 100644 index 000000000000..894e9434cccc --- /dev/null +++ b/etc/repository.ucls @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/repository.urm.puml b/etc/repository.urm.puml new file mode 100644 index 000000000000..10768260cefc --- /dev/null +++ b/etc/repository.urm.puml @@ -0,0 +1,56 @@ +@startuml +package com.iluwatar.repository { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class AppConfig { + - LOGGER : Logger {static} + + AppConfig() + + dataSource() : DataSource + + entityManagerFactory() : LocalContainerEntityManagerFactoryBean + - jpaProperties() : Properties {static} + + main(args : String[]) {static} + + transactionManager() : JpaTransactionManager + } + class Person { + - age : int + - id : Long + - name : String + - surname : String + + Person() + + Person(name : String, surname : String, age : int) + + equals(obj : Object) : boolean + + getAge() : int + + getId() : Long + + getName() : String + + getSurname() : String + + hashCode() : int + + setAge(age : int) + + setId(id : Long) + + setName(name : String) + + setSurname(surname : String) + + toString() : String + } + interface PersonRepository { + + findByName(String) : Person {abstract} + } + class PersonSpecifications { + + PersonSpecifications() + } + class AgeBetweenSpec { + - from : int + - to : int + + AgeBetweenSpec(from : int, to : int) + + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate + } + class NameEqualSpec { + + name : String + + NameEqualSpec(name : String) + + toPredicate(root : Root, query : CriteriaQuery, cb : CriteriaBuilder) : Predicate + } +} +NameEqualSpec ..+ PersonSpecifications +AgeBetweenSpec ..+ PersonSpecifications +@enduml \ No newline at end of file diff --git a/etc/resource-acquisition-is-initialization.png b/etc/resource-acquisition-is-initialization.png new file mode 100644 index 000000000000..487b97569004 Binary files /dev/null and b/etc/resource-acquisition-is-initialization.png differ diff --git a/etc/resource-acquisition-is-initialization.ucls b/etc/resource-acquisition-is-initialization.ucls new file mode 100644 index 000000000000..32fdb381cd91 --- /dev/null +++ b/etc/resource-acquisition-is-initialization.ucls @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/resource-acquisition-is-initialization.urm.puml b/etc/resource-acquisition-is-initialization.urm.puml new file mode 100644 index 000000000000..11309f0a6230 --- /dev/null +++ b/etc/resource-acquisition-is-initialization.urm.puml @@ -0,0 +1,19 @@ +@startuml +package com.iluwatar.resource.acquisition.is.initialization { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class SlidingDoor { + - LOGGER : Logger {static} + + SlidingDoor() + + close() + } + class TreasureChest { + - LOGGER : Logger {static} + + TreasureChest() + + close() + } +} +@enduml \ No newline at end of file diff --git a/etc/result.png b/etc/result.png new file mode 100644 index 000000000000..6b104968f302 Binary files /dev/null and b/etc/result.png differ diff --git a/etc/retry.png b/etc/retry.png new file mode 100644 index 000000000000..3ef6d3800ee5 Binary files /dev/null and b/etc/retry.png differ diff --git a/etc/retry.urm.puml b/etc/retry.urm.puml new file mode 100644 index 000000000000..ab2f7cf3a65f --- /dev/null +++ b/etc/retry.urm.puml @@ -0,0 +1,54 @@ +@startuml +package com.iluwatar.retry { + class App { + - LOG : Logger {static} + - op : BusinessOperation {static} + + App() + - errorNoRetry() {static} + - errorWithRetry() {static} + - errorWithRetryExponentialBackoff() {static} + + main(args : String[]) {static} + - noErrors() {static} + } + interface BusinessOperation { + + perform() : T {abstract} + } + class FindCustomer { + - customerId : String + - errors : Deque + + FindCustomer(customerId : String, errors : BusinessException[]) + + perform() : String + } + class Retry { + - attempts : AtomicInteger + - delay : long + - errors : List + - maxAttempts : int + - op : BusinessOperation + - test : Predicate + + Retry(op : BusinessOperation, maxAttempts : int, delay : long, ignoreTests : Predicate[]) + + attempts() : int + + errors() : List + + perform() : T + } + class RetryExponentialBackoff { + - RANDOM : Random {static} + - attempts : AtomicInteger + - errors : List + - maxAttempts : int + - maxDelay : long + - op : BusinessOperation + - test : Predicate + + RetryExponentialBackoff(op : BusinessOperation, maxAttempts : int, maxDelay : long, ignoreTests : Predicate[]) + + attempts() : int + + errors() : List + + perform() : T + } +} +RetryExponentialBackoff --> "-op" BusinessOperation +Retry --> "-op" BusinessOperation +App --> "-op" BusinessOperation +FindCustomer ..|> BusinessOperation +Retry ..|> BusinessOperation +RetryExponentialBackoff ..|> BusinessOperation +@enduml \ No newline at end of file diff --git a/etc/role-object.urm.png b/etc/role-object.urm.png new file mode 100644 index 000000000000..65201c68aff4 Binary files /dev/null and b/etc/role-object.urm.png differ diff --git a/etc/role-object.urm.puml b/etc/role-object.urm.puml new file mode 100644 index 000000000000..241a146f0b9f --- /dev/null +++ b/etc/role-object.urm.puml @@ -0,0 +1,60 @@ +@startuml +package com.iluwatar.roleobject { + class ApplicationRoleObject { + - logger : Logger {static} + + ApplicationRoleObject() + + main(args : String[]) {static} + } + class BorrowerRole { + - name : String + + BorrowerRole() + + borrow() : String + + getName() : String + + setName(name : String) + } + abstract class Customer { + + Customer() + + addRole(Role) : boolean {abstract} + + getRole(Role, Class) : Optional {abstract} + + hasRole(Role) : boolean {abstract} + + newCustomer() : Customer {static} + + newCustomer(role : Role[]) : Customer {static} + + remRole(Role) : boolean {abstract} + } + class CustomerCore { + - roles : Map + + CustomerCore() + + addRole(role : Role) : boolean + + getRole(role : Role, expectedRole : Class) : Optional + + hasRole(role : Role) : boolean + + remRole(role : Role) : boolean + + toString() : String + } + abstract class CustomerRole { + + CustomerRole() + } + class InvestorRole { + - amountToInvest : long + - name : String + + InvestorRole() + + getAmountToInvest() : long + + getName() : String + + invest() : String + + setAmountToInvest(amountToInvest : long) + + setName(name : String) + } + enum Role { + + Borrower {static} + + Investor {static} + - logger : Logger {static} + - typeCst : Class + + instance() : Optional + + valueOf(name : String) : Role {static} + + values() : Role[] {static} + } +} +BorrowerRole --|> CustomerRole +CustomerCore --|> Customer +CustomerRole --|> CustomerCore +InvestorRole --|> CustomerRole +@enduml \ No newline at end of file diff --git a/etc/saga.urm.png b/etc/saga.urm.png new file mode 100644 index 000000000000..025be6bbdedf Binary files /dev/null and b/etc/saga.urm.png differ diff --git a/etc/saga.urm.puml b/etc/saga.urm.puml new file mode 100644 index 000000000000..e44b5366b021 --- /dev/null +++ b/etc/saga.urm.puml @@ -0,0 +1,222 @@ +@startuml +package com.iluwatar.saga.orchestration { + class ChapterResult { + - state : State + - value : K + ~ ChapterResult(value : K, state : State) + + failure(val : K) : ChapterResult {static} + + getValue() : K + + isSuccess() : boolean + + success(val : K) : ChapterResult {static} + } + enum State { + + FAILURE {static} + + SUCCESS {static} + + valueOf(name : String) : State {static} + + values() : State[] {static} + } + class FlyBookingService { + + FlyBookingService() + + getName() : String + } + class HotelBookingService { + + HotelBookingService() + + getName() : String + + rollback(value : String) : ChapterResult + } + interface OrchestrationChapter { + + getName() : String {abstract} + + process(K) : ChapterResult {abstract} + + rollback(K) : ChapterResult {abstract} + } + class OrderService { + + OrderService() + + getName() : String + } + class Saga { + - chapters : List + - Saga() + + chapter(name : String) : Saga + + create() : Saga {static} + + get(idx : int) : Chapter + + isPresent(idx : int) : boolean + } + class Chapter { + ~ name : String + + Chapter(name : String) + + getName() : String + } + enum Result { + + CRASHED {static} + + FINISHED {static} + + ROLLBACK {static} + + valueOf(name : String) : Result {static} + + values() : Result[] {static} + } + class SagaApplication { + - LOGGER : Logger {static} + + SagaApplication() + + main(args : String[]) {static} + - newSaga() : Saga {static} + - serviceDiscovery() : ServiceDiscoveryService {static} + } + class SagaOrchestrator { + - LOGGER : Logger {static} + - saga : Saga + - sd : ServiceDiscoveryService + - state : CurrentState + + SagaOrchestrator(saga : Saga, sd : ServiceDiscoveryService) + + execute(value : K) : Result + } + -class CurrentState { + ~ currentNumber : int + ~ isForward : boolean + ~ CurrentState() + ~ back() : int + ~ cleanUp() + ~ current() : int + ~ directionToBack() + ~ forward() : int + ~ isForward() : boolean + } + abstract class Service { + # LOGGER : Logger {static} + + Service() + + getName() : String {abstract} + + process(value : K) : ChapterResult + + rollback(value : K) : ChapterResult + } + class ServiceDiscoveryService { + - services : Map> + + ServiceDiscoveryService() + + discover(orchestrationChapterService : OrchestrationChapter) : ServiceDiscoveryService + + find(service : String) : Optional> + } + class WithdrawMoneyService { + + WithdrawMoneyService() + + getName() : String + + process(value : String) : ChapterResult + } +} +package com.iluwatar.saga.choreography { + interface ChoreographyChapter { + + execute(Saga) : Saga {abstract} + + getName() : String {abstract} + + process(Saga) : Saga {abstract} + + rollback(Saga) : Saga {abstract} + } + class FlyBookingService { + + FlyBookingService(service : ServiceDiscoveryService) + + getName() : String + } + class HotelBookingService { + + HotelBookingService(service : ServiceDiscoveryService) + + getName() : String + } + class OrderService { + + OrderService(service : ServiceDiscoveryService) + + getName() : String + } + class Saga { + - chapters : List + - finished : boolean + - forward : boolean + - pos : int + - Saga() + ~ back() : int + + chapter(name : String) : Saga + + create() : Saga {static} + ~ forward() : int + ~ getCurrent() : Chapter + + getCurrentValue() : Object + + getResult() : SagaResult + ~ isCurrentSuccess() : boolean + ~ isForward() : boolean + ~ isPresent() : boolean + + setCurrentStatus(result : ChapterResult) + + setCurrentValue(value : Object) + ~ setFinished(finished : boolean) + + setInValue(value : Object) : Saga + + toString() : String + } + class Chapter { + - inValue : Object + - name : String + - result : ChapterResult + + Chapter(name : String) + + getInValue() : Object + + getName() : String + + isSuccess() : boolean + + setInValue(object : Object) + + setResult(result : ChapterResult) + } + enum ChapterResult { + + INIT {static} + + ROLLBACK {static} + + SUCCESS {static} + + valueOf(name : String) : ChapterResult {static} + + values() : ChapterResult[] {static} + } + enum SagaResult { + + FINISHED {static} + + PROGRESS {static} + + ROLLBACKED {static} + + valueOf(name : String) : SagaResult {static} + + values() : SagaResult[] {static} + } + class SagaApplication { + - LOGGER : Logger {static} + + SagaApplication() + + main(args : String[]) {static} + - newSaga(value : Object) : Saga {static} + - serviceDiscovery() : ServiceDiscoveryService {static} + } + abstract class Service { + # LOGGER : Logger {static} + - sd : ServiceDiscoveryService + + Service(service : ServiceDiscoveryService) + + execute(saga : Saga) : Saga + - isSagaFinished(saga : Saga) : boolean + + process(saga : Saga) : Saga + + rollback(saga : Saga) : Saga + - serviceNotFoundException(chServiceName : String) : Supplier + } + class ServiceDiscoveryService { + - services : Map + + ServiceDiscoveryService() + + discover(chapterService : ChoreographyChapter) : ServiceDiscoveryService + + find(service : String) : Optional + + findAny() : ChoreographyChapter + } + class WithdrawMoneyService { + + WithdrawMoneyService(service : ServiceDiscoveryService) + + getName() : String + + process(saga : Saga) : Saga + } +} +SagaOrchestrator --> "-saga" Saga +SagaOrchestrator --> "-sd" ServiceDiscoveryService +SagaOrchestrator --> "-state" CurrentState +CurrentState ..+ SagaOrchestrator +Chapter ..+ Saga +Saga --> "-chapters" Chapter +Chapter --> "-result" ChapterResult +ChapterResult ..+ Saga +ChapterResult --> "-state" State +State ..+ ChapterResult +Result ..+ Saga +Service --> "-sd" ServiceDiscoveryService +SagaResult ..+ Saga +Saga --> "-chapters" Chapter +Chapter ..+ Saga +FlyBookingService --|> Service +HotelBookingService --|> Service +OrderService --|> Service +Service ..|> ChoreographyChapter +WithdrawMoneyService --|> Service +FlyBookingService --|> Service +HotelBookingService --|> Service +OrderService --|> Service +Service ..|> OrchestrationChapter +WithdrawMoneyService --|> Service +@enduml \ No newline at end of file diff --git a/etc/separated-interface.urm.puml b/etc/separated-interface.urm.puml new file mode 100644 index 000000000000..eab2ad60c98e --- /dev/null +++ b/etc/separated-interface.urm.puml @@ -0,0 +1,36 @@ +@startuml +package com.iluwatar.separatedinterface { + class App { + - LOGGER : Logger {static} + + PRODUCT_COST : double {static} + + App() + + main(args : String[]) {static} + } +} +package com.iluwatar.separatedinterface.taxes { + class DomesticTaxCalculator { + + TAX_PERCENTAGE : double {static} + + DomesticTaxCalculator() + + calculate(amount : double) : double + } + class ForeignTaxCalculator { + + TAX_PERCENTAGE : double {static} + + ForeignTaxCalculator() + + calculate(amount : double) : double + } +} +package com.iluwatar.separatedinterface.invoice { + class InvoiceGenerator { + - amount : double + - taxCalculator : TaxCalculator + + InvoiceGenerator(amount : double, taxCalculator : TaxCalculator) + + getAmountWithTax() : double + } + interface TaxCalculator { + + calculate(double) : double {abstract} + } +} +InvoiceGenerator --> "-taxCalculator" TaxCalculator +DomesticTaxCalculator ..|> TaxCalculator +ForeignTaxCalculator ..|> TaxCalculator +@enduml \ No newline at end of file diff --git a/etc/sequencer.gif b/etc/sequencer.gif new file mode 100644 index 000000000000..a925fa209877 Binary files /dev/null and b/etc/sequencer.gif differ diff --git a/etc/serialize-entity.urm.puml b/etc/serialize-entity.urm.puml new file mode 100644 index 000000000000..7bf89dbb98af --- /dev/null +++ b/etc/serialize-entity.urm.puml @@ -0,0 +1,56 @@ +@startuml +package com.iluwatar.serializedentity { + class App { + - DB_URL : String {static} + - LOGGER : Logger {static} + + App() + - createDataSource() : DataSource {static} + - createSchema(dataSource : DataSource) {static} + - deleteSchema(dataSource : DataSource) {static} + + main(args : String[]) {static} + } + + class Country { + - code : int + - name : String + - continents : String + - language : String + + serialVersionUID : final Long {static} + ~Country(int, String, String, String) + + getCode() : int + + getName() : String + + getContinents() : String + + getLanguage() : String + + setCode(code : int) + + setName(name : String) + + setContinents(continents : String) + + setLanguage(language : String) + + equals(that: Object) : boolean + + hashCode() : int + + toString() : String + } + + interface CountryDao { + + insertCountry : int {abstract} + + selectCountry : int {abstract} + } + + class CountrySchemaSql { + - CREATE_SCHEMA_SQL : String {static} + - DELETE_SCHEMA_SQL : String {static} + - LOGGER : Logger {static} + - dataSource : DataSource + - country : Country + ~ CountrySchemaSql(country : Country, dataSource : DataSource) + + insertCountry() + + selectCountry() + } + diamond h2db +} + +App --> "Initialize Country objects" Country +App --> "Initialize CountrySchemaSql" CountrySchemaSql +CountrySchemaSql --> "implements" CountryDao +Country --> "Stored in database" h2db +CountrySchemaSql --> "Perform INSERT and SELECT operation after serialize and deserialize Country object" h2db +@enduml \ No newline at end of file diff --git a/etc/servant-pattern.png b/etc/servant-pattern.png new file mode 100644 index 000000000000..a8237775e332 Binary files /dev/null and b/etc/servant-pattern.png differ diff --git a/etc/servant-pattern.ucls b/etc/servant-pattern.ucls new file mode 100644 index 000000000000..54e5ffc005d9 --- /dev/null +++ b/etc/servant-pattern.ucls @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/servant.urm.puml b/etc/servant.urm.puml new file mode 100644 index 000000000000..26ea0c28530d --- /dev/null +++ b/etc/servant.urm.puml @@ -0,0 +1,56 @@ +@startuml +package com.iluwatar.servant { + class App { + - LOGGER : Logger {static} + - jenkins : Servant {static} + - travis : Servant {static} + + App() + + main(args : String[]) {static} + + scenario(servant : Servant, compliment : int) {static} + } + class King { + - complimentReceived : boolean + - isDrunk : boolean + - isHappy : boolean + - isHungry : boolean + + King() + + changeMood() + + getDrink() + + getFed() + + getMood() : boolean + + receiveCompliments() + } + class Queen { + - complimentReceived : boolean + - isDrunk : boolean + - isFlirty : boolean + - isHappy : boolean + - isHungry : boolean + + Queen() + + changeMood() + + getDrink() + + getFed() + + getMood() : boolean + + receiveCompliments() + + setFlirtiness(f : boolean) + } + ~interface Royalty { + + changeMood() {abstract} + + getDrink() {abstract} + + getFed() {abstract} + + getMood() : boolean {abstract} + + receiveCompliments() {abstract} + } + class Servant { + + name : String + + Servant(name : String) + + checkIfYouWillBeHanged(tableGuests : List) : boolean + + feed(r : Royalty) + + giveCompliments(r : Royalty) + + giveWine(r : Royalty) + } +} +App --> "-jenkins" Servant +King ..|> Royalty +Queen ..|> Royalty +@enduml \ No newline at end of file diff --git a/etc/serverless.urm.png b/etc/serverless.urm.png new file mode 100644 index 000000000000..18149d562742 Binary files /dev/null and b/etc/serverless.urm.png differ diff --git a/etc/serverless.urm.puml b/etc/serverless.urm.puml new file mode 100644 index 000000000000..27ff043fd6a8 --- /dev/null +++ b/etc/serverless.urm.puml @@ -0,0 +1,138 @@ +@startuml +package com.iluwatar.serverless.faas.api { + class LambdaInfoApiHandler { + - LOG : Logger {static} + - SUCCESS_STATUS_CODE : Integer {static} + + LambdaInfoApiHandler() + + handleRequest(input : Map, context : Context) : ApiGatewayResponse + - headers() : Map + - lambdaInfo(context : Context) : LambdaInfo + } +} +package com.iluwatar.serverless.baas.model { + class Address { + - addressLineOne : String + - addressLineTwo : String + - city : String + - serialVersionUID : long {static} + - state : String + - zipCode : String + + Address() + + equals(o : Object) : boolean + + getAddressLineOne() : String + + getAddressLineTwo() : String + + getCity() : String + + getState() : String + + getZipCode() : String + + hashCode() : int + + setAddressLineOne(addressLineOne : String) + + setAddressLineTwo(addressLineTwo : String) + + setCity(city : String) + + setState(state : String) + + setZipCode(zipCode : String) + + toString() : String + } + class Person { + - address : Address + - firstName : String + - id : String + - lastName : String + - serialVersionUID : long {static} + + Person() + + equals(o : Object) : boolean + + getAddress() : Address + + getFirstName() : String + + getId() : String + + getLastName() : String + + hashCode() : int + + setAddress(address : Address) + + setFirstName(firstName : String) + + setId(id : String) + + setLastName(lastName : String) + + toString() : String + } +} +package com.iluwatar.serverless.faas { + class ApiGatewayResponse { + - body : String + - headers : Map + - isBase64Encoded : Boolean + - serialVersionUID : long {static} + - statusCode : Integer + + ApiGatewayResponse(statusCode : Integer, body : String, headers : Map, isBase64Encoded : Boolean) + + getBody() : String + + getHeaders() : Map + + getStatusCode() : Integer + + isBase64Encoded() : Boolean + } + class ApiGatewayResponseBuilder { + - OBJECT_MAPPER : ObjectMapper {static} + - body : T extends Serializable + - headers : Map + - isBase64Encoded : Boolean + - statusCode : Integer + + ApiGatewayResponseBuilder() + + base64Encoded(isBase64Encoded : Boolean) : ApiGatewayResponseBuilder + + body(body : T extends Serializable) : ApiGatewayResponseBuilder + + build() : ApiGatewayResponse + + headers(headers : Map) : ApiGatewayResponseBuilder + + statusCode(statusCode : Integer) : ApiGatewayResponseBuilder + } + class LambdaInfo { + - awsRequestId : String + - functionName : String + - functionVersion : String + - logGroupName : String + - logStreamName : String + - memoryLimitInMb : Integer + - serialVersionUID : long {static} + + LambdaInfo() + + equals(o : Object) : boolean + + getAwsRequestId() : String + + getFunctionName() : String + + getFunctionVersion() : String + + getLogGroupName() : String + + getLogStreamName() : String + + getMemoryLimitInMb() : Integer + + hashCode() : int + + setAwsRequestId(awsRequestId : String) + + setFunctionName(functionName : String) + + setFunctionVersion(functionVersion : String) + + setLogGroupName(logGroupName : String) + + setLogStreamName(logStreamName : String) + + setMemoryLimitInMb(memoryLimitInMb : Integer) + + toString() : String + } +} +package com.iluwatar.serverless.baas.api { + abstract class AbstractDynamoDbHandler { + - dynamoDbMapper : DynamoDBMapper + - objectMapper : ObjectMapper + + AbstractDynamoDbHandler() + # apiGatewayProxyResponseEvent(statusCode : Integer, body : T extends Serializable) : APIGatewayProxyResponseEvent + # getDynamoDbMapper() : DynamoDBMapper + # getObjectMapper() : ObjectMapper + # headers() : Map + - initAmazonDynamoDb() + + setDynamoDbMapper(dynamoDbMapper : DynamoDBMapper) + } + class FindPersonApiHandler { + - LOG : Logger {static} + - SUCCESS_STATUS_CODE : Integer {static} + + FindPersonApiHandler() + + handleRequest(apiGatewayProxyRequestEvent : APIGatewayProxyRequestEvent, context : Context) : APIGatewayProxyResponseEvent + } + class SavePersonApiHandler { + - BAD_REQUEST_STATUS_CODE : Integer {static} + - CREATED_STATUS_CODE : Integer {static} + - LOG : Logger {static} + + SavePersonApiHandler() + + handleRequest(apiGatewayProxyRequestEvent : APIGatewayProxyRequestEvent, context : Context) : APIGatewayProxyResponseEvent + } +} +ApiGatewayResponseBuilder ..+ ApiGatewayResponse +Person --> "-address" Address +Access ..+ JsonProperty +FindPersonApiHandler --|> AbstractDynamoDbHandler +SavePersonApiHandler --|> AbstractDynamoDbHandler +@enduml \ No newline at end of file diff --git a/etc/service-layer.png b/etc/service-layer.png new file mode 100644 index 000000000000..31d38361225f Binary files /dev/null and b/etc/service-layer.png differ diff --git a/etc/service-layer.ucls b/etc/service-layer.ucls new file mode 100644 index 000000000000..979ae1204471 --- /dev/null +++ b/etc/service-layer.ucls @@ -0,0 +1,250 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/service-layer.urm.puml b/etc/service-layer.urm.puml new file mode 100644 index 000000000000..e663e6c4a678 --- /dev/null +++ b/etc/service-layer.urm.puml @@ -0,0 +1,159 @@ +@startuml +package com.iluwatar.servicelayer.hibernate { + class HibernateUtil { + - LOGGER : Logger {static} + - sessionFactory : SessionFactory {static} + - HibernateUtil() + + dropSession() {static} + + getSessionFactory() : SessionFactory {static} + } +} +package com.iluwatar.servicelayer.common { + abstract class BaseEntity { + + BaseEntity() + + getId() : Long {abstract} + + getName() : String {abstract} + + setId(Long) {abstract} + + setName(String) {abstract} + } + interface Dao { + + delete(E extends BaseEntity) {abstract} + + find(Long) : E extends BaseEntity {abstract} + + findAll() : List {abstract} + + merge(E extends BaseEntity) : E extends BaseEntity {abstract} + + persist(E extends BaseEntity) {abstract} + } + abstract class DaoBaseImpl { + # persistentClass : Class + + DaoBaseImpl() + + delete(entity : E extends BaseEntity) + + find(id : Long) : E extends BaseEntity + + findAll() : List + # getSessionFactory() : SessionFactory + + merge(entity : E extends BaseEntity) : E extends BaseEntity + + persist(entity : E extends BaseEntity) + } +} +package com.iluwatar.servicelayer.magic { + interface MagicService { + + findAllSpellbooks() : List {abstract} + + findAllSpells() : List {abstract} + + findAllWizards() : List {abstract} + + findWizardsWithSpell(String) : List {abstract} + + findWizardsWithSpellbook(String) : List {abstract} + } + class MagicServiceImpl { + - spellDao : SpellDao + - spellbookDao : SpellbookDao + - wizardDao : WizardDao + + MagicServiceImpl(wizardDao : WizardDao, spellbookDao : SpellbookDao, spellDao : SpellDao) + + findAllSpellbooks() : List + + findAllSpells() : List + + findAllWizards() : List + + findWizardsWithSpell(name : String) : List + + findWizardsWithSpellbook(name : String) : List + } +} +package com.iluwatar.servicelayer.wizard { + class Wizard { + - id : Long + - name : String + - spellbooks : Set + + Wizard() + + Wizard(name : String) + + addSpellbook(spellbook : Spellbook) + + getId() : Long + + getName() : String + + getSpellbooks() : Set + + setId(id : Long) + + setName(name : String) + + setSpellbooks(spellbooks : Set) + + toString() : String + } + interface WizardDao { + + findByName(String) : Wizard {abstract} + } + class WizardDaoImpl { + + WizardDaoImpl() + + findByName(name : String) : Wizard + } +} +package com.iluwatar.servicelayer.spellbook { + class Spellbook { + - id : Long + - name : String + - spells : Set + - wizards : Set + + Spellbook() + + Spellbook(name : String) + + addSpell(spell : Spell) + + getId() : Long + + getName() : String + + getSpells() : Set + + getWizards() : Set + + setId(id : Long) + + setName(name : String) + + setSpells(spells : Set) + + setWizards(wizards : Set) + + toString() : String + } + interface SpellbookDao { + + findByName(String) : Spellbook {abstract} + } + class SpellbookDaoImpl { + + SpellbookDaoImpl() + + findByName(name : String) : Spellbook + } +} +package com.iluwatar.servicelayer.spell { + class Spell { + - id : Long + - name : String + - spellbook : Spellbook + + Spell() + + Spell(name : String) + + getId() : Long + + getName() : String + + getSpellbook() : Spellbook + + setId(id : Long) + + setName(name : String) + + setSpellbook(spellbook : Spellbook) + + toString() : String + } + interface SpellDao { + + findByName(String) : Spell {abstract} + } + class SpellDaoImpl { + + SpellDaoImpl() + + findByName(name : String) : Spell + } +} +package com.iluwatar.servicelayer.app { + class App { + - LOGGER : Logger {static} + + App() + + initData() {static} + + main(args : String[]) {static} + + queryData() {static} + } +} +MagicServiceImpl --> "-wizardDao" WizardDao +MagicServiceImpl --> "-spellbookDao" SpellbookDao +MagicServiceImpl --> "-spellDao" SpellDao +Spellbook --> "-spells" Spell +Spellbook --> "-wizards" Wizard +DaoBaseImpl ..|> Dao +MagicServiceImpl ..|> MagicService +Spell --|> BaseEntity +SpellDao --|> Dao +SpellDaoImpl ..|> SpellDao +SpellDaoImpl --|> DaoBaseImpl +Spellbook --|> BaseEntity +SpellbookDao --|> Dao +SpellbookDaoImpl ..|> SpellbookDao +SpellbookDaoImpl --|> DaoBaseImpl +Wizard --|> BaseEntity +WizardDao --|> Dao +WizardDaoImpl ..|> WizardDao +WizardDaoImpl --|> DaoBaseImpl +@enduml \ No newline at end of file diff --git a/etc/service-locator.png b/etc/service-locator.png new file mode 100644 index 000000000000..d040da2abd3e Binary files /dev/null and b/etc/service-locator.png differ diff --git a/etc/service-locator.ucls b/etc/service-locator.ucls new file mode 100644 index 000000000000..da8b1bec58fb --- /dev/null +++ b/etc/service-locator.ucls @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/service-locator.urm.puml b/etc/service-locator.urm.puml new file mode 100644 index 000000000000..38fe7ea1b0d0 --- /dev/null +++ b/etc/service-locator.urm.puml @@ -0,0 +1,41 @@ +@startuml +package com.iluwatar.servicelocator { + class App { + + App() + + main(args : String[]) {static} + } + class InitContext { + - LOGGER : Logger {static} + + InitContext() + + lookup(serviceName : String) : Object + } + interface Service { + + execute() {abstract} + + getId() : int {abstract} + + getName() : String {abstract} + } + class ServiceCache { + - LOGGER : Logger {static} + - serviceCache : Map + + ServiceCache() + + addService(newService : Service) + + getService(serviceName : String) : Service + } + class ServiceImpl { + - LOGGER : Logger {static} + - id : int + - serviceName : String + + ServiceImpl(serviceName : String) + + execute() + + getId() : int + + getName() : String + } + class ServiceLocator { + - serviceCache : ServiceCache {static} + - ServiceLocator() + + getService(serviceJndiName : String) : Service {static} + } +} +ServiceLocator --> "-serviceCache" ServiceCache +ServiceImpl ..|> Service +@enduml \ No newline at end of file diff --git a/etc/service-to-worker.png b/etc/service-to-worker.png new file mode 100644 index 000000000000..864af5b38968 Binary files /dev/null and b/etc/service-to-worker.png differ diff --git a/etc/service-to-worker.puml b/etc/service-to-worker.puml new file mode 100644 index 000000000000..c96c337a8bd8 --- /dev/null +++ b/etc/service-to-worker.puml @@ -0,0 +1,86 @@ +@startuml +package com.iluwatar.servicetoworker { + class App { + + App() + + main(args : String[]) {static} + } + enum Health { + + DEAD {static} + + HEALTHY {static} + + WOUNDED {static} + - title : String + + toString() : String + } + enum Nourishment { + + HUNGRY {static} + + SATURATED {static} + + STARVING {static} + - title : String + + toString() : String + } + enum Fatigue { + + ALERT {static} + + SLEEPING {static} + + TIRED {static} + - title : String + + toString() : String + } + + class GiantController { + - dispatcher : Dispatcher + + GiantController(dispatcher : Dispatcher) + + setCommand(s : Command, index : int) + + updateView(giantModel : GiantModel) + } + + class GiantModel { + - fatigue : Fatigue + - health : Health + - nourishment : Nourishment + # GiantModel(health : Health, fatigue : Fatigue, nourishment : Nourishment) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + toString() : String + } + class GiantView { + - LOGGER : Logger {static} + + GiantView() + + displayGiant(giant : GiantModel) + } + + class Action{ + - giant : GiantModel + + Action(giant: GiantModel) + + updateModel(command: Command) + + setHealth(health : Health) + + setFatigue(fatigue : Fatigue) + + setNourishment(nourishment : Nourishment) + } + + class Dispatcher{ + - giantView : GiantView + - actions : ArrayList + + Dispatcher(giantView : GiantView) + + addAction(action: Action) + + performAction(s: Command, actionIndex: int) + + updateView(giant : GiantModel) + } +} +GiantModel --> Nourishment +GiantModel --> Fatigue +GiantModel --> Health + +GiantView ..> GiantModel +Dispatcher o-up- Action +GiantController -up-> Dispatcher + +GiantController .up.> GiantModel +Action --> GiantModel +Dispatcher -up-> GiantView +Dispatcher .left.> GiantModel + +@enduml \ No newline at end of file diff --git a/etc/service-to-worker.urm.puml b/etc/service-to-worker.urm.puml new file mode 100644 index 000000000000..eca0acc0a50e --- /dev/null +++ b/etc/service-to-worker.urm.puml @@ -0,0 +1,134 @@ +@startuml +package com.iluwatar.servicetoworker { + class Action { + + giant : GiantModel + + Action(giant : GiantModel) + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + updateModel(command : Command) + } + class App { + + App() + + main(args : String[]) {static} + } + class Command { + - fatigue : Fatigue + - health : Health + - nourishment : Nourishment + + Command(fatigue : Fatigue, health : Health, nourishment : Nourishment) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + } + class Dispatcher { + - actions : List + - giantView : GiantView + + Dispatcher(giantView : GiantView) + ~ addAction(action : Action) + + getGiantView() : GiantView + + performAction(s : Command, actionIndex : int) + + updateView(giantModel : GiantModel) + } + class GiantController { + + dispatcher : Dispatcher + + GiantController(dispatcher : Dispatcher) + + setCommand(s : Command, index : int) + + updateView(giantModel : GiantModel) + } + class GiantModel { + - model : GiantModel + - name : String + ~ GiantModel(name : String, health : Health, fatigue : Fatigue, nourishment : Nourishment) + ~ getFatigue() : Fatigue + ~ getHealth() : Health + + getName() : String + ~ getNourishment() : Nourishment + ~ setFatigue(fatigue : Fatigue) + ~ setHealth(health : Health) + ~ setNourishment(nourishment : Nourishment) + + toString() : String + } + class GiantView { + - LOGGER : Logger {static} + + GiantView() + + displayGiant(giant : GiantModel) + } +} +package com.iluwatar.model.view.controller { + class App { + + App() + + main(args : String[]) {static} + } + enum Fatigue { + + ALERT {static} + + SLEEPING {static} + + TIRED {static} + - title : String + + toString() : String + + valueOf(name : String) : Fatigue {static} + + values() : Fatigue[] {static} + } + class GiantController { + - giant : GiantModel + - view : GiantView + + GiantController(giant : GiantModel, view : GiantView) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + updateView() + } + class GiantModel { + - fatigue : Fatigue + - health : Health + - nourishment : Nourishment + + GiantModel(health : Health, fatigue : Fatigue, nourishment : Nourishment) + + getFatigue() : Fatigue + + getHealth() : Health + + getNourishment() : Nourishment + + setFatigue(fatigue : Fatigue) + + setHealth(health : Health) + + setNourishment(nourishment : Nourishment) + + toString() : String + } + class GiantView { + - LOGGER : Logger {static} + + GiantView() + + displayGiant(giant : GiantModel) + } + enum Health { + + DEAD {static} + + HEALTHY {static} + + WOUNDED {static} + - title : String + + toString() : String + + valueOf(name : String) : Health {static} + + values() : Health[] {static} + } + enum Nourishment { + + HUNGRY {static} + + SATURATED {static} + + STARVING {static} + - title : String + + toString() : String + + valueOf(name : String) : Nourishment {static} + + values() : Nourishment[] {static} + } +} +Command --> "-nourishment" Nourishment +GiantModel --> "-nourishment" Nourishment +GiantController --> "-giant" GiantModel +GiantController --> "-dispatcher" Dispatcher +GiantModel --> "-fatigue" Fatigue +Dispatcher --> "-actions" Action +GiantModel --> "-health" Health +GiantModel --> "-model" GiantModel +Command --> "-fatigue" Fatigue +Command --> "-health" Health +GiantController --> "-view" GiantView +Action --> "-giant" GiantModel +Dispatcher --> "-giantView" GiantView +@enduml \ No newline at end of file diff --git a/etc/sharding.urm.png b/etc/sharding.urm.png new file mode 100644 index 000000000000..e7f412af3f01 Binary files /dev/null and b/etc/sharding.urm.png differ diff --git a/etc/sharding.urm.puml b/etc/sharding.urm.puml new file mode 100644 index 000000000000..a51d027d5d5e --- /dev/null +++ b/etc/sharding.urm.puml @@ -0,0 +1,71 @@ +@startuml +package com.iluwatar.sharding { + class App { + + App() + + main(args : String[]) {static} + } + class Data { + - key : int + - type : DataType + - value : String + + Data(key : int, value : String, type : DataType) + + getKey() : int + + getType() : DataType + + getValue() : String + + setKey(key : int) + + setType(type : DataType) + + setValue(value : String) + + toString() : String + } + ~enum DataType { + + type1 {static} + + type2 {static} + + type3 {static} + + valueOf(name : String) : DataType {static} + + values() : DataType[] {static} + } + class HashShardManager { + - LOGGER : Logger {static} + + HashShardManager() + # allocateShard(data : Data) : int + + storeData(data : Data) : int + } + class LookupShardManager { + - LOGGER : Logger {static} + - lookupMap : Map + + LookupShardManager() + # allocateShard(data : Data) : int + + storeData(data : Data) : int + } + class RangeShardManager { + - LOGGER : Logger {static} + + RangeShardManager() + # allocateShard(data : Data) : int + + storeData(data : Data) : int + } + class Shard { + - dataStore : Map + - id : int + + Shard(id : int) + + clearData() + + getDataById(id : int) : Data + + getId() : int + + storeData(data : Data) + } + abstract class ShardManager { + - LOGGER : Logger {static} + # shardMap : Map + + ShardManager() + + addNewShard(shard : Shard) : boolean + # allocateShard(Data) : int {abstract} + + getShardById(shardId : int) : Shard + + removeShardById(shardId : int) : boolean + + storeData(Data) : int {abstract} + } +} +DataType ..+ Data +Data --> "-type" DataType +HashShardManager --|> ShardManager +LookupShardManager --|> ShardManager +RangeShardManager --|> ShardManager +@enduml \ No newline at end of file diff --git a/etc/singleton.urm.png b/etc/singleton.urm.png new file mode 100644 index 000000000000..46584af40039 Binary files /dev/null and b/etc/singleton.urm.png differ diff --git a/etc/singleton.urm.puml b/etc/singleton.urm.puml new file mode 100644 index 000000000000..371c9e2393d1 --- /dev/null +++ b/etc/singleton.urm.puml @@ -0,0 +1,44 @@ +@startuml +package com.iluwatar.singleton { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + enum EnumIvoryTower { + + INSTANCE {static} + + toString() : String + + valueOf(name : String) : EnumIvoryTower {static} + + values() : EnumIvoryTower[] {static} + } + class InitializingOnDemandHolderIdiom { + - InitializingOnDemandHolderIdiom() + + getInstance() : InitializingOnDemandHolderIdiom {static} + } + -class HelperHolder { + - INSTANCE : InitializingOnDemandHolderIdiom {static} + - HelperHolder() + } + class IvoryTower { + - INSTANCE : IvoryTower {static} + - IvoryTower() + + getInstance() : IvoryTower {static} + } + class ThreadSafeDoubleCheckLocking { + - flag : boolean {static} + - instance : ThreadSafeDoubleCheckLocking {static} + - ThreadSafeDoubleCheckLocking() + + getInstance() : ThreadSafeDoubleCheckLocking {static} + } + class ThreadSafeLazyLoadedIvoryTower { + - instance : ThreadSafeLazyLoadedIvoryTower {static} + - ThreadSafeLazyLoadedIvoryTower() + + getInstance() : ThreadSafeLazyLoadedIvoryTower {static} + } +} +IvoryTower --> "-INSTANCE" IvoryTower +ThreadSafeDoubleCheckLocking --> "-instance" ThreadSafeDoubleCheckLocking +ThreadSafeLazyLoadedIvoryTower --> "-instance" ThreadSafeLazyLoadedIvoryTower +HelperHolder ..+ InitializingOnDemandHolderIdiom +HelperHolder --> "-INSTANCE" InitializingOnDemandHolderIdiom +@enduml \ No newline at end of file diff --git a/etc/spatial-partition.urm.png b/etc/spatial-partition.urm.png new file mode 100644 index 000000000000..5172bdb36a79 Binary files /dev/null and b/etc/spatial-partition.urm.png differ diff --git a/etc/spatial-partition.urm.puml b/etc/spatial-partition.urm.puml new file mode 100644 index 000000000000..5962fcc4baca --- /dev/null +++ b/etc/spatial-partition.urm.puml @@ -0,0 +1,72 @@ +@startuml +package com.iluwatar.spatialpartition { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + ~ noSpatialPartition(height : int, width : int, numOfMovements : int, bubbles : Hashtable) {static} + ~ withSpatialPartition(height : int, width : int, numOfMovements : int, bubbles : Hashtable) {static} + } + class Bubble { + - LOGGER : Logger {static} + - RANDOM : Random {static} + ~ radius : int + ~ Bubble(x : int, y : int, id : int, radius : int) + ~ handleCollision(bubblesToCheck : ArrayList>, allBubbles : Hashtable) + ~ move() + ~ pop(allBubbles : Hashtable) + ~ touches(b : Bubble) : boolean + } + abstract class Point { + + coordinateX : int + + coordinateY : int + + id : int + ~ Point(x : int, y : int, id : int) + ~ handleCollision(ArrayList>, Hashtable) {abstract} + ~ move() {abstract} + ~ touches(T) : boolean {abstract} + } + class QuadTree { + ~ boundary : Rect + ~ capacity : int + ~ divided : boolean + ~ northeast : QuadTree + ~ northwest : QuadTree + ~ points : Hashtable> + ~ southeast : QuadTree + ~ southwest : QuadTree + ~ QuadTree(boundary : Rect, capacity : int) + ~ divide() + ~ insert(p : Point) + ~ query(r : Rect, relevantPoints : ArrayList>) : ArrayList> + } + class Rect { + ~ coordinateX : double + ~ coordinateY : double + ~ height : double + ~ width : double + ~ Rect(x : double, y : double, width : double, height : double) + ~ contains(p : Point) : boolean + ~ intersects(other : Rect) : boolean + } + class SpatialPartitionBubbles { + ~ bubbles : Hashtable + ~ quadTree : QuadTree + ~ SpatialPartitionBubbles(bubbles : Hashtable, quadTree : QuadTree) + ~ handleCollisionsUsingQt(b : Bubble) + } + abstract class SpatialPartitionGeneric { + ~ playerPositions : Hashtable + ~ quadTree : QuadTree + + SpatialPartitionGeneric() + ~ handleCollisionsUsingQt(T) {abstract} + } +} +SpatialPartitionBubbles --> "-quadTree" QuadTree +SpatialPartitionGeneric --> "-quadTree" QuadTree +QuadTree --> "-boundary" Rect +QuadTree --> "-northwest" QuadTree +QuadTree --> "-southwest" QuadTree +Bubble --|> Point +SpatialPartitionBubbles --|> SpatialPartitionGeneric +@enduml \ No newline at end of file diff --git a/etc/special-case.urm.puml b/etc/special-case.urm.puml new file mode 100644 index 000000000000..07bb47eb156a --- /dev/null +++ b/etc/special-case.urm.puml @@ -0,0 +1,119 @@ +@startuml +left to right direction +package com.iluwatar.specialcase { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + interface ApplicationServices { + + loggedInUserPurchase(String, String) : ReceiptViewModel {abstract} + } + class ApplicationServicesImpl { + - domain : DomainServicesImpl + + ApplicationServicesImpl() + - isDownForMaintenance() : boolean + + loggedInUserPurchase(userName : String, itemName : String) : ReceiptViewModel + } + class Db { + - instance : Db {static} + - itemName2Product : Map + - user2Account : Map + - userName2User : Map + + Db() + + findAccountByUser(user : User) : Account + + findProductByItemName(itemName : String) : Product + + findUserByUserName(userName : String) : User + + getInstance() : Db {static} + + seedItem(itemName : String, price : Double) + + seedUser(userName : String, amount : Double) + } + class Account { + - amount : Double + + Account(this$0 : Double) + + getAmount() : Double + + withdraw(price : Double) : MoneyTransaction + } + class Product { + - price : Double + + Product(this$0 : Double) + + getPrice() : Double + } + class User { + - userName : String + + User(this$0 : String) + + getUserName() : String + + purchase(item : Product) : ReceiptDto + } + interface DomainServices { + } + class DomainServicesImpl { + + DomainServicesImpl() + - purchase(user : User, account : Account, itemName : String) : ReceiptViewModel + + purchase(userName : String, itemName : String) : ReceiptViewModel + } + class DownForMaintenance { + - LOGGER : Logger {static} + + DownForMaintenance() + + show() + } + class InsufficientFunds { + - LOGGER : Logger {static} + - amount : Double + - itemName : String + - userName : String + + InsufficientFunds(userName : String, amount : Double, itemName : String) + + show() + } + class InvalidUser { + - LOGGER : Logger {static} + - userName : String + + InvalidUser(userName : String) + + show() + } + class MaintenanceLock { + - LOGGER : Logger {static} + - instance : MaintenanceLock {static} + - lock : boolean + + MaintenanceLock() + + getInstance() : MaintenanceLock {static} + + isLock() : boolean + + setLock(lock : boolean) + } + class MoneyTransaction { + - amount : Double + - price : Double + + MoneyTransaction(amount : Double, price : Double) + } + class OutOfStock { + - LOGGER : Logger {static} + - itemName : String + - userName : String + + OutOfStock(userName : String, itemName : String) + + show() + } + class ReceiptDto { + - LOGGER : Logger {static} + - price : Double + + ReceiptDto(price : Double) + + getPrice() : Double + + show() + } + interface ReceiptViewModel { + + show() {abstract} + } +} +User --+ Db +Product --+ Db +MaintenanceLock --> "-instance" MaintenanceLock +Db --> "-instance" Db +ApplicationServicesImpl --> "-domain" DomainServicesImpl +Account --+ Db +ApplicationServicesImpl ..|> ApplicationServices +DomainServicesImpl ..|> DomainServices +DownForMaintenance ..|> ReceiptViewModel +InsufficientFunds ..|> ReceiptViewModel +InvalidUser ..|> ReceiptViewModel +OutOfStock ..|> ReceiptViewModel +ReceiptDto ..|> ReceiptViewModel +@enduml diff --git a/etc/special_case_urm.png b/etc/special_case_urm.png new file mode 100644 index 000000000000..03ca646f3816 Binary files /dev/null and b/etc/special_case_urm.png differ diff --git a/etc/specification.png b/etc/specification.png new file mode 100644 index 000000000000..60fb0402d8d3 Binary files /dev/null and b/etc/specification.png differ diff --git a/etc/specification.ucls b/etc/specification.ucls new file mode 100644 index 000000000000..54b08cc41d57 --- /dev/null +++ b/etc/specification.ucls @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/specification.urm.puml b/etc/specification.urm.puml new file mode 100644 index 000000000000..21cae1c3c2a4 --- /dev/null +++ b/etc/specification.urm.puml @@ -0,0 +1,177 @@ +@startuml +package com.iluwatar.specification.creature { + abstract class AbstractCreature { + - color : Color + - mass : Mass + - movement : Movement + - name : String + - size : Size + + AbstractCreature(name : String, size : Size, movement : Movement, color : Color, mass : Mass) + + getColor() : Color + + getMass() : Mass + + getMovement() : Movement + + getName() : String + + getSize() : Size + + toString() : String + } + interface Creature { + + getColor() : Color {abstract} + + getMass() : Mass {abstract} + + getMovement() : Movement {abstract} + + getName() : String {abstract} + + getSize() : Size {abstract} + } + class Dragon { + + Dragon() + + Dragon(mass : Mass) + } + class Goblin { + + Goblin() + + Goblin(mass : Mass) + } + class KillerBee { + + KillerBee() + + KillerBee(mass : Mass) + } + class Octopus { + + Octopus() + + Octopus(mass : Mass) + } + class Shark { + + Shark() + + Shark(mass : Mass) + } + class Troll { + + Troll() + + Troll(mass : Mass) + } +} +package com.iluwatar.specification.property { + enum Color { + + DARK {static} + + GREEN {static} + + LIGHT {static} + + RED {static} + - title : String + + toString() : String + + valueOf(name : String) : Color {static} + + values() : Color[] {static} + } + class Mass { + - title : String + - value : double + + Mass(value : double) + + equals(obj : Object) : boolean + + greaterThan(other : Mass) : boolean + + greaterThanOrEq(other : Mass) : boolean + + smallerThan(other : Mass) : boolean + + smallerThanOrEq(other : Mass) : boolean + + toString() : String + } + enum Movement { + + FLYING {static} + + SWIMMING {static} + + WALKING {static} + - title : String + + toString() : String + + valueOf(name : String) : Movement {static} + + values() : Movement[] {static} + } + enum Size { + + LARGE {static} + + NORMAL {static} + + SMALL {static} + - title : String + + toString() : String + + valueOf(name : String) : Size {static} + + values() : Size[] {static} + } +} +package com.iluwatar.specification.selector { + abstract class AbstractSelector { + + AbstractSelector() + + and(other : AbstractSelector) : AbstractSelector + + not() : AbstractSelector + + or(other : AbstractSelector) : AbstractSelector + } + class ColorSelector { + - color : Color + + ColorSelector(c : Color) + + test(t : Creature) : boolean + } + class ConjunctionSelector { + - leafComponents : List> + ~ ConjunctionSelector(selectors : AbstractSelector[]) + + test(t : T) : boolean + } + class DisjunctionSelector { + - leafComponents : List> + ~ DisjunctionSelector(selectors : AbstractSelector[]) + + test(t : T) : boolean + } + class MassEqualSelector { + - mass : Mass + + MassEqualSelector(mass : double) + + test(t : Creature) : boolean + } + class MassGreaterThanSelector { + - mass : Mass + + MassGreaterThanSelector(mass : double) + + test(t : Creature) : boolean + } + class MassSmallerThanOrEqSelector { + - mass : Mass + + MassSmallerThanOrEqSelector(mass : double) + + test(t : Creature) : boolean + } + class MovementSelector { + - movement : Movement + + MovementSelector(m : Movement) + + test(t : Creature) : boolean + } + class NegationSelector { + - component : AbstractSelector + ~ NegationSelector(selector : AbstractSelector) + + test(t : T) : boolean + } + class SizeSelector { + - size : Size + + SizeSelector(s : Size) + + test(t : Creature) : boolean + } +} +package com.iluwatar.specification.app { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } +} +SizeSelector --> "-size" Size +AbstractCreature --> "-mass" Mass +MassEqualSelector --> "-mass" Mass +AbstractCreature --> "-color" Color +MassGreaterThanSelector --> "-mass" Mass +MovementSelector --> "-movement" Movement +NegationSelector --> "-component" AbstractSelector +AbstractCreature --> "-movement" Movement +MassSmallerThanOrEqSelector --> "-mass" Mass +AbstractCreature --> "-size" Size +ColorSelector --> "-color" Color +AbstractCreature ..|> Creature +Dragon --|> AbstractCreature +Goblin --|> AbstractCreature +KillerBee --|> AbstractCreature +Octopus --|> AbstractCreature +Shark --|> AbstractCreature +Troll --|> AbstractCreature +ColorSelector --|> AbstractSelector +ConjunctionSelector --|> AbstractSelector +DisjunctionSelector --|> AbstractSelector +MassEqualSelector --|> AbstractSelector +MassGreaterThanSelector --|> AbstractSelector +MassSmallerThanOrEqSelector --|> AbstractSelector +MovementSelector --|> AbstractSelector +NegationSelector --|> AbstractSelector +SizeSelector --|> AbstractSelector +@enduml \ No newline at end of file diff --git a/etc/spotinst-logos-black-small.png b/etc/spotinst-logos-black-small.png new file mode 100644 index 000000000000..b748f80c7c59 Binary files /dev/null and b/etc/spotinst-logos-black-small.png differ diff --git a/etc/state.urm.puml b/etc/state.urm.puml new file mode 100644 index 000000000000..207a227d83d7 --- /dev/null +++ b/etc/state.urm.puml @@ -0,0 +1,39 @@ +@startuml +package com.iluwatar.state { + class AngryState { + - LOGGER : Logger {static} + - mammoth : Mammoth + + AngryState(mammoth : Mammoth) + + observe() + + onEnterState() + } + class App { + + App() + + main(args : String[]) {static} + } + class Mammoth { + - state : State + + Mammoth() + - changeStateTo(newState : State) + + observe() + + timePasses() + + toString() : String + } + class PeacefulState { + - LOGGER : Logger {static} + - mammoth : Mammoth + + PeacefulState(mammoth : Mammoth) + + observe() + + onEnterState() + } + interface State { + + observe() {abstract} + + onEnterState() {abstract} + } +} +PeacefulState --> "-mammoth" Mammoth +AngryState --> "-mammoth" Mammoth +Mammoth --> "-state" State +AngryState ..|> State +PeacefulState ..|> State +@enduml \ No newline at end of file diff --git a/etc/state_urm.png b/etc/state_urm.png new file mode 100644 index 000000000000..c2cf9f562943 Binary files /dev/null and b/etc/state_urm.png differ diff --git a/etc/static-content-hosting.drawio b/etc/static-content-hosting.drawio new file mode 100644 index 000000000000..50281e5e6d0d --- /dev/null +++ b/etc/static-content-hosting.drawio @@ -0,0 +1 @@ +7Vpbc9o6EP41PMZjW77AY0Kh56HttMOcIX3qCCxsNbLlyjKX/PqzMvING9rMQGE4mWQS72olrfbbXe8KBmgcbz8KnEafeUDYwDaD7QB9GNi2hRwL/inObs8ZIc0IBQ20UM2Y0Veimabm5jQgWUtQcs4kTdvMJU8SspQtHhaCb9piK87au6Y4JB3GbIlZlzungYz23KFr1vx/CA2jcmfL1CMxLoU1I4twwDcNFpoM0FhwLvdP8XZMmDJeaZf9vOmR0UoxQRL5JxOePj8vvN38XzEXc/KNzvDj65cH29PKyV15YhKAATTJhYx4yBPMJjX3aZmLNVGrWkDUIp84TzXzJ5Fyp8HEueTAimTM9CgoLHbPQJiGW5Lfm2MflPuYFbUrqS2Vz6UcPH+vlwCqnqSIcs7+eOpMR82mWRnPxZKcspWr/Q+LkMgTgsMKXQgLwmMCh4B5gjAs6bqtCNb+GVZyNYTwoFF8C6L+NRDVyJg3jox/VWS0lmvMcr1VFyrGILMpSDYRlWSW4uLgG0iubYvrpYiQZHvaft3j6gn2SCukU7M30plqUyc6G2le1Exy/uhCJhreloWc0iLaQrZvGe61beTflo089/ZMNLqhl5r5m5faGdNgWR/ddBYsC7vrgGO9Q3NCSes9bm62rrN60vzfBGfYRsewQKHflOuK+koEBQMQ8X+FrfO2DsiaMJ6CRQ7x5LlkNCHjqpVVBlvxRI4546KQQfAzVds/hQIHlNRjCU8U4ivKWJ94JgV/IQfCAc6iwj3URqoKoND4fsILwr7yjErKExhbcCl53BB4ZDRUA1I50RPW1BJ0USg33Ufprn2r8JaC1udVW+Is3R90RbdKj6eUU7XKZA2LZXoR6JtTNSHehuqKwcCbzDHyrNjrDPUL8ts1ntctgv1ht3gpeefvEjoO8zifAWOG4M8iX76Ar/+R41wa3B5ckLFX8MeGyugHX/wEbbKuU05M13bQcR8+A6qW20YVoS6sXk9N6lXV69mBRUeAHTOeB1MBoXHDuC6VkqtCyQ6cU3foIu+icLqeZ7T7DGQ5PX2GX4k1QR2hSyX3LqaWoS4jBcGSHI9XMIQ8MHpfem7aWbM6wB3iG9MgYMc6P8HzJKh85xxhZrfDzOrJnpbVE2flvPND4nQgsRUkOAhgvTwN9sCUuelukaku0Mu+3OxBpq8rvxwy3esv1AqWgIKt6SIvUtjdAuOWSaMMGf/qwHRvlJwqZEyaAJ9C2AAqdxwvnnMQL9bVYRl1YClfJ+aGLOBVr4KGJEFRNA9sjykkFtBWeOEeEwmWelRKqF8Px8pwe6FinYcEx6QaKOYYGXrQaz+0pwgSggP0TcExfoWmcpMZS6g47tZBDvKp0/OmQ30V5cX8o1y44R+NKg3SKY8xhURqasxOuUdgv6DtJsG/8DD5tW1Ue0ai/G16v7A69s3h2r0yUN1uN/e+Xxe86bogO9d9gdVyGN8x+xqRv3llYL3pY7PSQEWQHwmzM3+M1g4xt6cU9Z2eEKua+DdYDMj6KxXFWOOLKWjyHw== \ No newline at end of file diff --git a/etc/static-content-hosting.png b/etc/static-content-hosting.png new file mode 100644 index 000000000000..6e0baa95e0f9 Binary files /dev/null and b/etc/static-content-hosting.png differ diff --git a/etc/step-builder.png b/etc/step-builder.png new file mode 100644 index 000000000000..b7b623657c58 Binary files /dev/null and b/etc/step-builder.png differ diff --git a/etc/step-builder.ucls b/etc/step-builder.ucls new file mode 100644 index 000000000000..bb3560a2e425 --- /dev/null +++ b/etc/step-builder.ucls @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/step-builder.urm.puml b/etc/step-builder.urm.puml new file mode 100644 index 000000000000..4a56e1e9bdbe --- /dev/null +++ b/etc/step-builder.urm.puml @@ -0,0 +1,91 @@ +@startuml +package com.iluwatar.stepbuilder { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Character { + - abilities : List + - fighterClass : String + - name : String + - spell : String + - weapon : String + - wizardClass : String + + Character(name : String) + + getAbilities() : List + + getFighterClass() : String + + getName() : String + + getSpell() : String + + getWeapon() : String + + getWizardClass() : String + + setAbilities(abilities : List) + + setFighterClass(fighterClass : String) + + setName(name : String) + + setSpell(spell : String) + + setWeapon(weapon : String) + + setWizardClass(wizardClass : String) + + toString() : String + } + class CharacterStepBuilder { + - CharacterStepBuilder() + + newBuilder() : NameStep {static} + } + interface AbilityStep { + + noAbilities() : BuildStep {abstract} + + noMoreAbilities() : BuildStep {abstract} + + withAbility(String) : AbilityStep {abstract} + } + interface BuildStep { + + build() : Character {abstract} + } + -class CharacterSteps { + - abilities : List + - fighterClass : String + - name : String + - spell : String + - weapon : String + - wizardClass : String + - CharacterSteps() + + build() : Character + + fighterClass(fighterClass : String) : WeaponStep + + name(name : String) : ClassStep + + noAbilities() : BuildStep + + noMoreAbilities() : BuildStep + + noSpell() : BuildStep + + noWeapon() : BuildStep + + withAbility(ability : String) : AbilityStep + + withSpell(spell : String) : AbilityStep + + withWeapon(weapon : String) : AbilityStep + + wizardClass(wizardClass : String) : SpellStep + } + interface ClassStep { + + fighterClass(String) : WeaponStep {abstract} + + wizardClass(String) : SpellStep {abstract} + } + interface NameStep { + + name(String) : ClassStep {abstract} + } + interface SpellStep { + + noSpell() : BuildStep {abstract} + + withSpell(String) : AbilityStep {abstract} + } + interface WeaponStep { + + noWeapon() : BuildStep {abstract} + + withWeapon(String) : AbilityStep {abstract} + } +} +WeaponStep ..+ CharacterStepBuilder +AbilityStep ..+ CharacterStepBuilder +ClassStep ..+ CharacterStepBuilder +CharacterSteps ..+ CharacterStepBuilder +SpellStep ..+ CharacterStepBuilder +BuildStep ..+ CharacterStepBuilder +NameStep ..+ CharacterStepBuilder +CharacterSteps ..|> NameStep +CharacterSteps ..|> ClassStep +CharacterSteps ..|> WeaponStep +CharacterSteps ..|> SpellStep +CharacterSteps ..|> AbilityStep +CharacterSteps ..|> BuildStep +@enduml \ No newline at end of file diff --git a/etc/strangler.png b/etc/strangler.png new file mode 100644 index 000000000000..c69305e5d510 Binary files /dev/null and b/etc/strangler.png differ diff --git a/etc/strangler.puml b/etc/strangler.puml new file mode 100644 index 000000000000..cb2c266a1998 --- /dev/null +++ b/etc/strangler.puml @@ -0,0 +1,61 @@ +@startuml + +package com.iluwatar.strangler { + class App { + + main(args : String[]) {static} + } + + class OldArithmetic { + - LOGGER : Logger {static} + - VERSION : String {static} + - source : OldSource + + sum(nums : int...) + + mul(nums : int...) + } + + class HalfArithmetic { + - LOGGER : Logger {static} + - VERSION : String {static} + - oldSource : OldSource + - newSource : HalfSource + + sum(nums : int...) + + mul(nums : int...) + + ifHasZero(nums : int...) + } + + class NewArithmetic { + - LOGGER : Logger {static} + - VERSION : String {static} + - source : NewSource + + sum(nums : int...) + + mul(nums : int...) + + ifHasZero(nums : int...) + } + + class OldSource { + - LOGGER : Logger {static} + - VERSION : String {static} + + accumulateSum(nums : int...) + + accumulateMul(nums : int...) + } + + class HalfSource { + - LOGGER : Logger {static} + - VERSION : String {static} + + accumulateSum(nums : int...) + + ifNonZero(nums : int...) + } + + class NewSource { + - LOGGER : Logger {static} + - VERSION : String {static} + + accumulateSum(nums : int...) + + accumulateMul(nums : int...) + + ifNonZero(nums : int...) + } +} +OldArithmetic o--> OldSource +HalfArithmetic o--> OldSource +HalfArithmetic o--> HalfSource +NewArithmetic o--> NewSource +@enduml \ No newline at end of file diff --git a/etc/strangler.urm.puml b/etc/strangler.urm.puml new file mode 100644 index 000000000000..afbe4d49988a --- /dev/null +++ b/etc/strangler.urm.puml @@ -0,0 +1,61 @@ +@startuml +package com.iluwatar.strangler { + class App { + + App() + + main(args : String[]) {static} + } + class HalfArithmetic { + - LOGGER : Logger {static} + - VERSION : String {static} + - newSource : HalfSource + - oldSource : OldSource + + HalfArithmetic(newSource : HalfSource, oldSource : OldSource) + + ifHasZero(nums : int[]) : boolean + + mul(nums : int[]) : int + + sum(nums : int[]) : int + } + class HalfSource { + - LOGGER : Logger {static} + - VERSION : String {static} + + HalfSource() + + accumulateSum(nums : int[]) : int + + ifNonZero(nums : int[]) : boolean + } + class NewArithmetic { + - LOGGER : Logger {static} + - VERSION : String {static} + - source : NewSource + + NewArithmetic(source : NewSource) + + ifHasZero(nums : int[]) : boolean + + mul(nums : int[]) : int + + sum(nums : int[]) : int + } + class NewSource { + - LOGGER : Logger {static} + - VERSION : String {static} + + NewSource() + + accumulateMul(nums : int[]) : int + + accumulateSum(nums : int[]) : int + + ifNonZero(nums : int[]) : boolean + } + class OldArithmetic { + - LOGGER : Logger {static} + - VERSION : String {static} + - source : OldSource + + OldArithmetic(source : OldSource) + + mul(nums : int[]) : int + + sum(nums : int[]) : int + } + class OldSource { + - LOGGER : Logger {static} + - VERSION : String {static} + + OldSource() + + accumulateMul(nums : int[]) : int + + accumulateSum(nums : int[]) : int + } +} +OldArithmetic --> "-source" OldSource +NewArithmetic --> "-source" NewSource +HalfArithmetic --> "-newSource" HalfSource +HalfArithmetic --> "-oldSource" OldSource +@enduml \ No newline at end of file diff --git a/etc/strategy.urm.puml b/etc/strategy.urm.puml new file mode 100644 index 000000000000..d9b9aa526d9a --- /dev/null +++ b/etc/strategy.urm.puml @@ -0,0 +1,53 @@ +@startuml +package com.iluwatar.strategy { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class DragonSlayer { + - strategy : DragonSlayingStrategy + + DragonSlayer(strategy : DragonSlayingStrategy) + + changeStrategy(strategy : DragonSlayingStrategy) + + goToBattle() + } + interface DragonSlayingStrategy { + + execute() {abstract} + } + class LambdaStrategy { + - LOGGER : Logger {static} + + LambdaStrategy() + } + enum Strategy { + + MeleeStrategy {static} + + ProjectileStrategy {static} + + SpellStrategy {static} + - dragonSlayingStrategy : DragonSlayingStrategy + + execute() + + valueOf(name : String) : Strategy {static} + + values() : Strategy[] {static} + } + class MeleeStrategy { + - LOGGER : Logger {static} + + MeleeStrategy() + + execute() + } + class ProjectileStrategy { + - LOGGER : Logger {static} + + ProjectileStrategy() + + execute() + } + class SpellStrategy { + - LOGGER : Logger {static} + + SpellStrategy() + + execute() + } +} +Strategy ..+ LambdaStrategy +Strategy --> "-dragonSlayingStrategy" DragonSlayingStrategy +DragonSlayer --> "-strategy" DragonSlayingStrategy +Strategy ..|> DragonSlayingStrategy +MeleeStrategy ..|> DragonSlayingStrategy +ProjectileStrategy ..|> DragonSlayingStrategy +SpellStrategy ..|> DragonSlayingStrategy +@enduml \ No newline at end of file diff --git a/etc/strategy_urm.png b/etc/strategy_urm.png new file mode 100644 index 000000000000..67d19acae62d Binary files /dev/null and b/etc/strategy_urm.png differ diff --git a/etc/subclass-sandbox.urm.png b/etc/subclass-sandbox.urm.png new file mode 100644 index 000000000000..db81e12cc815 Binary files /dev/null and b/etc/subclass-sandbox.urm.png differ diff --git a/etc/subclass-sandbox.urm.puml b/etc/subclass-sandbox.urm.puml new file mode 100644 index 000000000000..a1f863b697c9 --- /dev/null +++ b/etc/subclass-sandbox.urm.puml @@ -0,0 +1,27 @@ +@startuml +package com.iluwatar.subclasssandbox { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class GroundDive { + + GroundDive() + # activate() + } + class SkyLaunch { + + SkyLaunch() + # activate() + } + abstract class Superpower { + # logger : Logger + + Superpower() + # activate() {abstract} + # move(x : double, y : double, z : double) + # playSound(soundName : String, volumn : int) + # spawnParticles(particleType : String, count : int) + } +} +GroundDive --|> Superpower +SkyLaunch --|> Superpower +@enduml \ No newline at end of file diff --git a/etc/table-module.urm.png b/etc/table-module.urm.png new file mode 100644 index 000000000000..9c4bc0b189db Binary files /dev/null and b/etc/table-module.urm.png differ diff --git a/etc/table-module.urm.puml b/etc/table-module.urm.puml new file mode 100644 index 000000000000..6cf75797f080 --- /dev/null +++ b/etc/table-module.urm.puml @@ -0,0 +1,38 @@ +@startuml +package com.iluwatar.tablemodule { + class App { + - DB_URL : String {static} + - LOGGER : Logger {static} + - App() + - createDataSource() : DataSource {static} + - createSchema(dataSource : DataSource) {static} + - deleteSchema(dataSource : DataSource) {static} + + main(args : String[]) {static} + } + class User { + - id : int + - password : String + - username : String + + User(id : int, username : String, password : String) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getId() : int + + getPassword() : String + + getUsername() : String + + hashCode() : int + + setId(id : int) + + setPassword(password : String) + + setUsername(username : String) + + toString() : String + } + class UserTableModule { + + CREATE_SCHEMA_SQL : String {static} + + DELETE_SCHEMA_SQL : String {static} + - LOGGER : Logger {static} + - dataSource : DataSource + + UserTableModule(userDataSource : DataSource) + + login(username : String, password : String) : int + + registerUser(user : User) : int + } +} +@enduml \ No newline at end of file diff --git a/etc/template-method.urm.puml b/etc/template-method.urm.puml new file mode 100644 index 000000000000..a6e2dc3d20fd --- /dev/null +++ b/etc/template-method.urm.puml @@ -0,0 +1,39 @@ +@startuml +package com.iluwatar.templatemethod { + class App { + + App() + + main(args : String[]) {static} + } + class HalflingThief { + - method : StealingMethod + + HalflingThief(method : StealingMethod) + + changeMethod(method : StealingMethod) + + steal() + } + class HitAndRunMethod { + - LOGGER : Logger {static} + + HitAndRunMethod() + # confuseTarget(target : String) + # pickTarget() : String + # stealTheItem(target : String) + } + abstract class StealingMethod { + - LOGGER : Logger {static} + + StealingMethod() + # confuseTarget(String) {abstract} + # pickTarget() : String {abstract} + + steal() + # stealTheItem(String) {abstract} + } + class SubtleMethod { + - LOGGER : Logger {static} + + SubtleMethod() + # confuseTarget(target : String) + # pickTarget() : String + # stealTheItem(target : String) + } +} +HalflingThief --> "-method" StealingMethod +HitAndRunMethod --|> StealingMethod +SubtleMethod --|> StealingMethod +@enduml \ No newline at end of file diff --git a/etc/template_method_urm.png b/etc/template_method_urm.png new file mode 100644 index 000000000000..b7babccff96d Binary files /dev/null and b/etc/template_method_urm.png differ diff --git a/etc/thread-pool.urm.puml b/etc/thread-pool.urm.puml new file mode 100644 index 000000000000..251033c8157c --- /dev/null +++ b/etc/thread-pool.urm.puml @@ -0,0 +1,37 @@ +@startuml +package com.iluwatar.threadpool { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class CoffeeMakingTask { + - TIME_PER_CUP : int {static} + + CoffeeMakingTask(numCups : int) + + toString() : String + } + class PotatoPeelingTask { + - TIME_PER_POTATO : int {static} + + PotatoPeelingTask(numPotatoes : int) + + toString() : String + } + abstract class Task { + - ID_GENERATOR : AtomicInteger {static} + - id : int + - timeMs : int + + Task(timeMs : int) + + getId() : int + + getTimeMs() : int + + toString() : String + } + class Worker { + - LOGGER : Logger {static} + - task : Task + + Worker(task : Task) + + run() + } +} +Worker --> "-task" Task +CoffeeMakingTask --|> Task +PotatoPeelingTask --|> Task +@enduml \ No newline at end of file diff --git a/etc/thread_pool_urm.png b/etc/thread_pool_urm.png new file mode 100644 index 000000000000..3d433824f95a Binary files /dev/null and b/etc/thread_pool_urm.png differ diff --git a/etc/throttling.urm.puml b/etc/throttling.urm.puml new file mode 100644 index 000000000000..797006627b84 --- /dev/null +++ b/etc/throttling.urm.puml @@ -0,0 +1,47 @@ +@startuml +package com.iluwatar.throttling { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + - makeServiceCalls(tenant : Tenant, callsCount : CallsCount) {static} + } + ~class B2BService { + - LOGGER : Logger {static} + - callsCount : CallsCount + + B2BService(timer : Throttler, callsCount : CallsCount) + + dummyCustomerApi(tenant : Tenant) : int + - getRandomCustomerId() : int + } + class CallsCount { + - LOGGER : Logger {static} + - tenantCallsCount : Map + + CallsCount() + + addTenant(tenantName : String) + + getCount(tenantName : String) : long + + incrementCount(tenantName : String) + + reset() + } + class Tenant { + - allowedCallsPerSecond : int + - name : String + + Tenant(name : String, allowedCallsPerSecond : int, callsCount : CallsCount) + + getAllowedCallsPerSecond() : int + + getName() : String + } +} +package com.iluwatar.throttling.timer { + class ThrottleTimerImpl { + - callsCount : CallsCount + - throttlePeriod : int + + ThrottleTimerImpl(throttlePeriod : int, callsCount : CallsCount) + + start() + } + interface Throttler { + + start() {abstract} + } +} +B2BService --> "-callsCount" CallsCount +ThrottleTimerImpl --> "-callsCount" CallsCount +ThrottleTimerImpl ..|> Throttler +@enduml \ No newline at end of file diff --git a/etc/throttling_urm.png b/etc/throttling_urm.png new file mode 100644 index 000000000000..a9824e24b5a4 Binary files /dev/null and b/etc/throttling_urm.png differ diff --git a/etc/tls.png b/etc/tls.png new file mode 100644 index 000000000000..442f39a0c730 Binary files /dev/null and b/etc/tls.png differ diff --git a/etc/tls.ucls b/etc/tls.ucls new file mode 100644 index 000000000000..bd238346d0be --- /dev/null +++ b/etc/tls.ucls @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/tls.urm.puml b/etc/tls.urm.puml new file mode 100644 index 000000000000..12bcea0643b6 --- /dev/null +++ b/etc/tls.urm.puml @@ -0,0 +1,25 @@ +@startuml +package com.iluwatar.tls { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + - printAndCountDates(res : Result) : int {static} + - printAndCountExceptions(res : Result) : int {static} + } + class DateFormatCallable { + - LOGGER : Logger {static} + - dateValue : String + - df : ThreadLocal + + DateFormatCallable(inDateFormat : String, inDateValue : String) + + call() : Result + } + class Result { + - dateList : List + - exceptionList : List + + Result() + + getDateList() : List + + getExceptionList() : List + } +} +@enduml \ No newline at end of file diff --git a/etc/tolerant-reader.urm.puml b/etc/tolerant-reader.urm.puml new file mode 100644 index 000000000000..a73394a4ed7d --- /dev/null +++ b/etc/tolerant-reader.urm.puml @@ -0,0 +1,39 @@ +@startuml +package com.iluwatar.tolerantreader { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class RainbowFish { + - age : int + - lengthMeters : int + - name : String + - serialVersionUID : long {static} + - weightTons : int + + RainbowFish(name : String, age : int, lengthMeters : int, weightTons : int) + + getAge() : int + + getLengthMeters() : int + + getName() : String + + getWeightTons() : int + } + class RainbowFishSerializer { + - RainbowFishSerializer() + + readV1(filename : String) : RainbowFish {static} + + writeV1(rainbowFish : RainbowFish, filename : String) {static} + + writeV2(rainbowFish : RainbowFishV2, filename : String) {static} + } + class RainbowFishV2 { + - angry : boolean + - hungry : boolean + - serialVersionUID : long {static} + - sleeping : boolean + + RainbowFishV2(name : String, age : int, lengthMeters : int, weightTons : int) + + RainbowFishV2(name : String, age : int, lengthMeters : int, weightTons : int, sleeping : boolean, hungry : boolean, angry : boolean) + + getAngry() : boolean + + getHungry() : boolean + + getSleeping() : boolean + } +} +RainbowFishV2 --|> RainbowFish +@enduml \ No newline at end of file diff --git a/etc/tolerant_reader_urm.png b/etc/tolerant_reader_urm.png new file mode 100644 index 000000000000..9f5499172ee9 Binary files /dev/null and b/etc/tolerant_reader_urm.png differ diff --git a/etc/trampoline.urm.png b/etc/trampoline.urm.png new file mode 100644 index 000000000000..f2e9c7439a32 Binary files /dev/null and b/etc/trampoline.urm.png differ diff --git a/etc/trampoline.urm.puml b/etc/trampoline.urm.puml new file mode 100644 index 000000000000..31ca84b6da4a --- /dev/null +++ b/etc/trampoline.urm.puml @@ -0,0 +1,18 @@ +@startuml +package com.iluwatar.trampoline { + interface Trampoline { + + complete() : boolean + + done(result : T) : Trampoline {static} + + get() : T {abstract} + + jump() : Trampoline + + more(trampoline : Trampoline>) : Trampoline {static} + + result() : T + } + class TrampolineApp { + - log : Logger {static} + + TrampolineApp() + + loop(times : int, prod : int) : Trampoline {static} + + main(args : String[]) {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/transaction-script.png b/etc/transaction-script.png new file mode 100644 index 000000000000..6d0cffb6a551 Binary files /dev/null and b/etc/transaction-script.png differ diff --git a/etc/transaction-script.urm.puml b/etc/transaction-script.urm.puml new file mode 100644 index 000000000000..e8d172377918 --- /dev/null +++ b/etc/transaction-script.urm.puml @@ -0,0 +1,65 @@ +@startuml +package com.ashishtrivedi16.transaction-script { + class App { + - H2_DB_URL : String {static} + - LOGGER : Logger {static} + - addRooms(hotelDaoImpl : HotelDaoImpl) {static} + - createDataSource() : DataSource {static} + - createSchema(dataSource : DataSource) {static} + - deleteSchema(dataSource : DataSource) {static} + - getRoomsStatus(hotelDaoImpl : HotelDaoImpl) {static} + - generateSampleRooms() : List {static} + + main(args : String[]) {static} + } + class Room { + - id: Int + - roomType: String + - price: Int + - booked: Boolean + + Customer(id : int, roomType : String, price: Int, booked: Boolean) + + getId() : int + + getRoomType() : String + + getPrice() : Int + + isBooked() : Boolean + + setId(id : int) + + setRoomType(roomType : String) + + setPrice(price : Int) + + setBooked(booked : boolean) + + equals(that : Object) : boolean + + hashCode() : int + + toString() : String + } + interface HotelDao { + + add(Room) : boolean {abstract} + + delete(Room) : boolean {abstract} + + getAll() : Stream {abstract} + + getById(int) : Optional {abstract} + + update(Room) : boolean {abstract} + } + class RoomSchemaSql { + + CREATE_SCHEMA_SQL : String {static} + + DELETE_SCHEMA_SQL : String {static} + - RoomSchemaSql() + } + class HotelDaoImpl { + - dataSource : DataSource + + HotelDaoImpl(dataSource : DataSource) + + add(room : Room) : boolean + - createRoom(resultSet : ResultSet) : Room + + delete(room : Room) : boolean + + getAll() : Stream + + getById(id : int) : Optional + - getConnection() : Connection + - mutedClose(connection : Connection, statement : PreparedStatement, resultSet : ResultSet) + + update(room : Room) : boolean + } + class Hotel { + - LOGGER : Logger {static} + - hotelDao: HotelDaoImpl + + Hotel(hotelDao: HotelDaoImpl) + + bookRoom(roomNumber: Int) + + cancelRoomBooking(roomNumber: Int) + } +} +HotelDaoImpl ..|> HotelDao +@enduml diff --git a/etc/twin.png b/etc/twin.png new file mode 100644 index 000000000000..724092525bd6 Binary files /dev/null and b/etc/twin.png differ diff --git a/etc/twin.ucls b/etc/twin.ucls new file mode 100644 index 000000000000..6948dbf6afa7 --- /dev/null +++ b/etc/twin.ucls @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/twin.urm.puml b/etc/twin.urm.puml new file mode 100644 index 000000000000..e48298f18262 --- /dev/null +++ b/etc/twin.urm.puml @@ -0,0 +1,27 @@ +@startuml +package com.iluwatar.twin { + class App { + + App() + + main(args : String[]) {static} + - waiting() {static} + } + class BallItem { + - LOGGER : Logger {static} + - isSuspended : boolean + - twin : BallThread + + BallItem() + + click() + + doDraw() + + move() + + setTwin(twin : BallThread) + } + abstract class GameItem { + - LOGGER : Logger {static} + + GameItem() + + click() {abstract} + + doDraw() {abstract} + + draw() + } +} +BallItem --|> GameItem +@enduml \ No newline at end of file diff --git a/etc/typeobjectpattern.urm.png b/etc/typeobjectpattern.urm.png new file mode 100644 index 000000000000..477dac5f2a2e Binary files /dev/null and b/etc/typeobjectpattern.urm.png differ diff --git a/etc/typeobjectpattern.urm.puml b/etc/typeobjectpattern.urm.puml new file mode 100644 index 000000000000..80a95b0b4a9a --- /dev/null +++ b/etc/typeobjectpattern.urm.puml @@ -0,0 +1,72 @@ +@startuml +package com.iluwatar.typeobject { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Candy { + ~ name : String + ~ parent : Candy + ~ parentName : String + - points : int + - type : Type + ~ Candy(name : String, parentName : String, type : Type, points : int) + ~ getPoints() : int + ~ getType() : Type + ~ setPoints(a : int) + } + ~enum Type { + + crushableCandy {static} + + rewardFruit {static} + + valueOf(name : String) : Type {static} + + values() : Type[] {static} + } + class CandyGame { + - LOGGER : Logger {static} + ~ cells : Cell[][] + ~ pool : CellPool + ~ totalPoints : int + ~ CandyGame(num : int, pool : CellPool) + ~ adjacentCells(y : int, x : int) : List + ~ continueRound() : boolean + ~ handleChange(points : int) + ~ numOfSpaces(num : int) : String {static} + ~ printGameStatus() + ~ round(timeSoFar : int, totalTime : int) + } + class Cell { + ~ candy : Candy + ~ positionX : int + ~ positionY : int + ~ Cell() + ~ Cell(candy : Candy, positionX : int, positionY : int) + ~ crush(pool : CellPool, cellMatrix : Cell[][]) + ~ fillThisSpace(pool : CellPool, cellMatrix : Cell[][]) + ~ handleCrush(c : Cell, pool : CellPool, cellMatrix : Cell[][]) + ~ interact(c : Cell, pool : CellPool, cellMatrix : Cell[][]) : int + } + class CellPool { + - RANDOM : Random {static} + ~ pointer : int + ~ pool : List + ~ randomCode : Candy[] + ~ CellPool(num : int) + ~ addNewCell(c : Cell) + ~ assignRandomCandytypes() : Candy[] + ~ getNewCell() : Cell + } + class JsonParser { + ~ candies : Hashtable + ~ JsonParser() + ~ parse() + ~ setParentAndPoints() + } +} +Cell --> "-candy" Candy +Type ..+ Candy +Candy --> "-type" Type +Candy --> "-parent" Candy +CandyGame --> "-pool" CellPool +CellPool --> "-pool" Cell +@enduml \ No newline at end of file diff --git a/etc/unit-of-work.ucls b/etc/unit-of-work.ucls new file mode 100644 index 000000000000..0a80d680d536 --- /dev/null +++ b/etc/unit-of-work.ucls @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/unit-of-work.urm.png b/etc/unit-of-work.urm.png new file mode 100644 index 000000000000..bb192af54477 Binary files /dev/null and b/etc/unit-of-work.urm.png differ diff --git a/etc/unit-of-work.urm.puml b/etc/unit-of-work.urm.puml new file mode 100644 index 000000000000..7767a2e32f56 --- /dev/null +++ b/etc/unit-of-work.urm.puml @@ -0,0 +1,48 @@ +@startuml +package com.iluwatar.unitofwork { + class App { + + App() + + main(args : String[]) {static} + } + interface IUnitOfWork { + + DELETE : String {static} + + INSERT : String {static} + + MODIFY : String {static} + + commit() {abstract} + + registerDeleted(T) {abstract} + + registerModified(T) {abstract} + + registerNew(T) {abstract} + } + class Student { + - address : String + - id : Integer + - name : String + + Student(id : Integer, name : String, address : String) + + getAddress() : String + + getId() : Integer + + getName() : String + } + class StudentDatabase { + + StudentDatabase() + + delete(student : Student) + + insert(student : Student) + + modify(student : Student) + } + class StudentRepository { + - LOGGER : Logger {static} + - context : Map> + - studentDatabase : StudentDatabase + + StudentRepository(context : Map>, studentDatabase : StudentDatabase) + + commit() + - commitDelete() + - commitInsert() + - commitModify() + - register(student : Student, operation : String) + + registerDeleted(student : Student) + + registerModified(student : Student) + + registerNew(student : Student) + } +} +StudentRepository --> "-studentDatabase" StudentDatabase +StudentRepository ..|> IUnitOfWork +@enduml \ No newline at end of file diff --git a/etc/update-method.urm.png b/etc/update-method.urm.png new file mode 100644 index 000000000000..ddc47b5fe145 Binary files /dev/null and b/etc/update-method.urm.png differ diff --git a/etc/update-method.urm.puml b/etc/update-method.urm.puml new file mode 100644 index 000000000000..53d2a6eb6a2e --- /dev/null +++ b/etc/update-method.urm.puml @@ -0,0 +1,51 @@ +@startuml +package com.iluwatar.updatemethod { + class App { + - GAME_RUNNING_TIME : int {static} + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + abstract class Entity { + # id : int + # logger : Logger + # position : int + + Entity(id : int) + + getPosition() : int + + setPosition(position : int) + + update() {abstract} + } + class Skeleton { + - PATROLLING_LEFT_BOUNDING : int {static} + - PATROLLING_RIGHT_BOUNDING : int {static} + # patrollingLeft : boolean + + Skeleton(id : int) + + Skeleton(id : int, postition : int) + + update() + } + class Statue { + # delay : int + # frames : int + + Statue(id : int) + + Statue(id : int, delay : int) + - shootLightning() + + update() + } + class World { + - LOGGER : Logger {static} + # entities : List + # isRunning : boolean + + World() + + addEntity(entity : Entity) + - gameLoop() + - processInput() + - render() + + run() + + stop() + - update() + } +} +World --> "-entities" Entity +Skeleton --|> Entity +Statue --|> Entity +@enduml \ No newline at end of file diff --git a/etc/value-object.png b/etc/value-object.png new file mode 100644 index 000000000000..69a244c80691 Binary files /dev/null and b/etc/value-object.png differ diff --git a/etc/value-object.ucls b/etc/value-object.ucls new file mode 100644 index 000000000000..7bbf5e47cfbd --- /dev/null +++ b/etc/value-object.ucls @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/value-object.urm.puml b/etc/value-object.urm.puml new file mode 100644 index 000000000000..6149ead9ba36 --- /dev/null +++ b/etc/value-object.urm.puml @@ -0,0 +1,22 @@ +@startuml +package com.iluwatar.value.object { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class HeroStat { + - intelligence : int + - luck : int + - strength : int + - HeroStat(strength : int, intelligence : int, luck : int) + + equals(obj : Object) : boolean + + getIntelligence() : int + + getLuck() : int + + getStrength() : int + + hashCode() : int + + toString() : String + + valueOf(strength : int, intelligence : int, luck : int) : HeroStat {static} + } +} +@enduml \ No newline at end of file diff --git a/etc/version-number.urm.png b/etc/version-number.urm.png new file mode 100644 index 000000000000..95a5819b4b6e Binary files /dev/null and b/etc/version-number.urm.png differ diff --git a/etc/version-number.urm.puml b/etc/version-number.urm.puml new file mode 100644 index 000000000000..6f3c3364edae --- /dev/null +++ b/etc/version-number.urm.puml @@ -0,0 +1,32 @@ +@startuml +package com.iluwatar.versionnumber { + class App { + - LOGGER : Logger {static} + + App() + + main(args : String[]) {static} + } + class Book { + - author : String + - id : long + - title : String + - version : long + + Book() + + Book(book : Book) + + getAuthor() : String + + getId() : long + + getTitle() : String + + getVersion() : long + + setAuthor(author : String) + + setId(id : long) + + setTitle(title : String) + + setVersion(version : long) + } + class BookRepository { + - collection : Map + + BookRepository() + + add(book : Book) + + get(bookId : long) : Book + + update(book : Book) + } +} +@enduml \ No newline at end of file diff --git a/etc/visitor.png b/etc/visitor.png new file mode 100644 index 000000000000..5bbee60eeabf Binary files /dev/null and b/etc/visitor.png differ diff --git a/etc/visitor.ucls b/etc/visitor.ucls new file mode 100644 index 000000000000..17fe353265cf --- /dev/null +++ b/etc/visitor.ucls @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/etc/visitor.urm.puml b/etc/visitor.urm.puml new file mode 100644 index 000000000000..36a67b41514b --- /dev/null +++ b/etc/visitor.urm.puml @@ -0,0 +1,60 @@ +@startuml +package com.iluwatar.visitor { + class App { + + App() + + main(args : String[]) {static} + } + class Commander { + + Commander(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + class CommanderVisitor { + - LOGGER : Logger {static} + + CommanderVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } + class Sergeant { + + Sergeant(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + class SergeantVisitor { + - LOGGER : Logger {static} + + SergeantVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } + class Soldier { + + Soldier(children : Unit[]) + + accept(visitor : UnitVisitor) + + toString() : String + } + class SoldierVisitor { + - LOGGER : Logger {static} + + SoldierVisitor() + + visitCommander(commander : Commander) + + visitSergeant(sergeant : Sergeant) + + visitSoldier(soldier : Soldier) + } + abstract class Unit { + - children : Unit[] + + Unit(children : Unit[]) + + accept(visitor : UnitVisitor) + } + interface UnitVisitor { + + visitCommander(Commander) {abstract} + + visitSergeant(Sergeant) {abstract} + + visitSoldier(Soldier) {abstract} + } +} +Commander --|> Unit +CommanderVisitor ..|> UnitVisitor +Sergeant --|> Unit +SergeantVisitor ..|> UnitVisitor +Soldier --|> Unit +SoldierVisitor ..|> UnitVisitor +@enduml \ No newline at end of file diff --git a/etc/visitor_1.png b/etc/visitor_1.png new file mode 100644 index 000000000000..de5285d7fdc3 Binary files /dev/null and b/etc/visitor_1.png differ diff --git a/etc/webtask-small-grayscale.png b/etc/webtask-small-grayscale.png new file mode 100644 index 000000000000..8e218093557e Binary files /dev/null and b/etc/webtask-small-grayscale.png differ diff --git a/etc/wiretap.gif b/etc/wiretap.gif new file mode 100644 index 000000000000..4141737167ca Binary files /dev/null and b/etc/wiretap.gif differ diff --git a/extract.sh b/extract.sh new file mode 100755 index 000000000000..0350e74f9f34 --- /dev/null +++ b/extract.sh @@ -0,0 +1,9 @@ +#! /usr/bin/zsh +for d in /home/miro/IdeaProjects/java-design-patterns/*; do + if [ -d "$d" ]; then + cd $d + if [ -d "$d/etc" ]; then + cp -R $d/etc/* /home/miro/IdeaProjects/java-design-patterns/etc + fi + fi +done diff --git a/mvnw b/mvnw old mode 100755 new mode 100644 diff --git a/notes.md b/notes.md new file mode 100644 index 000000000000..0c63fa8648e1 --- /dev/null +++ b/notes.md @@ -0,0 +1,153 @@ +abstract-document +abstract-factory +active-object +acyclic-visitor +adapter +aggregator-microservices +ambassador +api-gateway +arrange-act-assert +async-method-invocation +balking +bridge +builder +business-delegate +bytecode +caching +callback +chain-of-responsibility +circuit-breaker +cloud-claim-check-pattern +cloud-static-content-hosting +collection-pipeline +combinator +command +commander +composite +composite-entity +composite-view +converter +cqrs +dao +data-bus +data-locality +data-mapper +data-transfer-object +decorator +delegation +dependency-injection +dirty-flag +domain-model +double-buffer +double-checked-locking +double-dispatch +eip-aggregator +eip-message-channel +eip-publish-subscribe +eip-splitter +eip-wire-tap +event-aggregator +event-asynchronous +event-driven-architecture +event-queue +event-sourcing +execute-around +extension-objects +facade +factory +factory-kit +factory-method +fanout-fanin +feature-toggle +filterer +fluentinterface +flux +flyweight +front-controller +game-loop +guarded-suspension +half-sync-half-async +hexagonal +identity-map +intercepting-filter +interpreter +iterator +layers +lazy-loading +leader-election +leader-followers +localization +lockable-object +marker +master-worker-pattern +mediator +memento +metadata-mapping +model-view-controller +model-view-presenter +model-view-viewmodel +module +monad +monitor +monostate +multiton +mute-idiom +naked-objects +null-object +object-mother +object-pool +observer +page-object +parameter-object +partial-response +pipeline +poison-pill +presentation-model +priority-queue +private-class-data +producer-consumer +promise +property +prototype +proxy +queue-load-leveling +reactor +reader-writer-lock +registry +repository +resource-acquisition-is-initialization +retry +role-object +saga +separated-interface +serialized-entity +servant +serverless +service-layer +service-locator +service-to-worker +sharding +singleton +spatial-partition +special-case +specification +state +step-builder +strangler +strategy +subclass-sandbox +table-module +template-method +thread-pool +throttling +tls +tolerant-reader +trampoline +transaction-script +twin +typeobjectpattern +unit-of-work +update-method +value-object +version-number +visitor diff --git a/parse.sh b/parse.sh new file mode 100755 index 000000000000..be7511f1ca76 --- /dev/null +++ b/parse.sh @@ -0,0 +1,13 @@ +#! /usr/bin/zsh + +#line starts with open brace and number +regex='^[\[][0-9]' +url=http://localhost:8888/api/users/jobs/upload-patterns + while read line; +do + if [[ $line =~ $regex ]] + then + #send line to antitask + curl -d $line -X POST $url -H "Content-Type:application/json" + fi +done < patterns.md diff --git a/patterns.md b/patterns.md new file mode 100644 index 000000000000..9b0f4af32c8a --- /dev/null +++ b/patterns.md @@ -0,0 +1,15037 @@ +# Java design patterns + +## Categories +* creational +* structural +* behavioral +* functional +* architectural +* concurrency +* idiom +* cloud +* eip (enterprise integration pattern) + +## Patterns +[Abstract Document](#abstract-document) (structural) +[Abstract Factory](#abstract-factory) (creational) +[Active Object](#active-object) (concurrency) +[Acyclic Visitor](#acyclic-visitor) (behavioral) +[Adapter](#adapter) (structural) +[Aggregator Microservices](#aggregator-microservices) (architectural) +[Ambassador](#ambassador) (structural) +[Api Gateway](#api-gateway) (architectural) +[Async Method Invocation](#async-method-invocation) (concurrency) + +[Balking](#balking) (concurrency) +[Bridge](#bridge) (structural) +[Builder](#builder) (creational) +[Business Delegete](#business-delegate) (structural) +[Bytecode](#bytecode) (behavioral) + +[Caching](#caching) (behavioral) +[Callback](#callback) (idiom) +[Chain of Responsibility](#chain-of-responsibility) (behavioral) +[Circuit Breaker](#circuit-breaker) (behavioral) +[Cloud Claim Check Pattern](#cloud-claim-check-pattern) (cloud) +[Cloud Static Content Hosting](#cloud-static-content-hosting) (cloud) +[Collection Pipeline](#collection-pipeline) (functional) +[Combinator](#combinator) (idiom) +[Command](#command) (behavioral) +[Commander](#commander) (concurrency) +[Composite](#composite) (structural) +[Composite Entity](#composite-entity) (structural) +[Composite View](#composite-view) (structural) +[Converter](#converter) (creational) +[CQRS](#cqrs) (architectural) + +[Data Access Object](#data-access-object) (architectural) +[Data Bus](#data-bus) (architectural) +[Data Locality](#data-locality) (behavioral) +[Data Mapper](#data-mapper) (architectural) +[Data Transfer Object](#data-transfer-object) (architectural) +[Decorator](#decorator) (structural) +[Delegation](#delegation) (structural) +[Dependency Injection](#dependency-injection) (creational) +[Dirty Flag](#dirty-flag) (behavioral) +[Domain Model](#domain-model) (architectural) +[DoubleBuffer](#double-buffer) (behavioral) +[DoubleCheckedLocking](#double-checked-locking) (idiom) +[DoubleDispatch](#double-dispatch) (idiom) + +[EIPAggregator](#eip-aggregator) (eip) +[EIPMessageChannel](#eip-message-channel) (eip) +[EIPPublishSubscribe](#eip-publish-subscribe) (eip) +[EIPSplitter](#eip-splitter) (eip) +[EIPWireTap](#eip-wire-tap) (eip) +[EventAggregator](#event-aggregator) (structural) +[EventBasedAsynchronous](#event-asynchronous) (concurrency) +[EventDrivenArchitecture](#event-driven-architecture) (architectural) +[EventQueue](#event-queue) (concurrency) +[EventSourcing](#event-sourcing) (architectural) +[ExecuteAround](#execute-around) (idiom) +[ExtensionObjects](#extension-objects) (behavioral) + +[Facade](#facade) (structural) +[Factory](#factory) (creational) +[FactoryKit](#factory-kit) (creational) +[FactoryMethod](#factory-method) (creational) +[FeatureToogle](#feature-toggle) (behavioral) +[Filterer](#filterer) (functional) +[FluentInterface](#fluent-interface) (functional) +[Flux](#flux) (structural) +[Flyweight](#flyweight) (structural) +[FrontController](#front-controller) (structural) + +[GameLoop](#game-loop) (behavioral) +[GuardedSuspension](#guarded-suspension) (concurrency) + +[HalfSyncHalfAsync](#half-synchalf-async) (concurrency) +[HexagonalArchitecture](#hexagonal-architecture) (architectural) + +[InterceptingFilter](#intercepting-filter) (behavioral) +[Interpreter](#interpreter) (behavioral) +[Iterator](#iterator) (behavioral) + +[Layers](#layers) (architectural) +[LazyLoading](#lazy-loading) (idiom) +[LeaderElection](#leader-election) (behavioral) +[LeaderFollowers](#leader-followers) (concurrency) + +[MarkerInterface](#marker-interface) (structural) +[MasterWorker](#master-worker) (concurrency) +[Mediator](#mediator) (behavioral) +[Memento](#memento) (behavioral) +[ModelViewController](#model-view-controller) (architectural) +[ModelViewPresenter](#model-view-presenter) (architectural) +[ModelViewViewModel](#model-view-view-model) (architectural) +[Module](#module) (structural) +[Monad](#monad) (functional) +[Monostate](#monostate) (creational) +[Multiton](#multiton) (creational) +[MuteIdiom](#mute-idiom) (idiom) + +[NakedObjects](#naked-objects) (architectural) +[NullObject](#null-object) (behavioral) + +[ObjectMother](#object-mother) (creational) +[ObjectPool](#object-pool) (creational) +[Observer](#observer) (behavioral) + +[PageObject](#page-object) (structural) +[ParameterObject](#parameter-object) (behavioral) +[PartialResponse](#partial-response) (behavioral) +[Pipeline](#pipeline) (behavioral) +[PoisonPill](#poison-pill) (behavioral) +[Prezenntation Model](#presentation-model) +[PriorityQueue](#priority-queue-pattern) (behavioral) +[PrivateClassData](#private-class-data) (idiom) +[ProducerConsumer](#producer-consumer) (concurrency) +[Promise](#promise) (concurrency) +[Property](#property) (creational) +[Prototype](#prototype) (creational) +[Proxy](#proxy) (structural) + +[QueueBasedLoadLeveling](#queue-based-load-leveling) (concurrency) + +[Reactor](#reactor) (concurrency) +[RederWriterLock](#reader-writer-lock) (concurrency) +[Registry](#registry) (creational) +[Repository](#repository) (architectural) +[ResourceAcquisitionIsInitialization](#resource-acquisition-is-initialization) (idiom) +[Retry](#retry) (behavioral) +[RoleObject](#role-object) (structural) + +[Saga](#saga) (concurrency) +[SeparatedInterface](#separated-interface) (structural) +[Serialized Entity](#serialized-entity) (architectural) +[Servant](#servant) (behavioral) +[Serverless](#serverless) (architectural) +[ServiceLayer](#service-layer) (architectural) +[ServiceLocator](#service-locator) (architectural) +[Service To Worker](#service-to-worker) (architectural) +[Sharding](#sharding) (behavioral) +[Singleton](#singleton) (creational) +[SpatialPartition](#spatial-partition) (behavioral) +[SpecialCase](#special-case) (behavioral) +[Specification](#specification) (behavioral) +[State](#state) (behavioral) +[Static Content Hosting](#static-content-hosting) (cloud) +[StepBuilder](#step-builder) (creational) +[Strangler](#strangler) (structural) +[Strategy](#strategy) (behavioral) +[SubclassSandbox](#subclass-sandbox) (behavioral) + +[Table Module](#table-module) (structural) +[TemplateMethod](#template-method) (behavioral) +[ThreadPool](#thread-pool) (concurrency) +[Throttling](#throttling) (behavioral) +[Tls](#tls) (idiom) +[Thread Local Storage](#thread-local-storage) (idiom) +[TolerantReader](#tolerant-reader) (eip) +[Trampoline](#trampoline) (behavioral) +[TransactionScript](#transaction-script) (behavioral) +[Twin](#twin) (structural) +[TypeObjectPattern](#type-object-pattern) (behavioral) + +[UnitofWork](#unit-of-work) (architectural) +[UpdateMethod](#update-method) (behavioral) + +[ValueObject](#value-object) (creational) +[VersionNumber](#version-number) (concurrency) +[Visitor](#visitor) (behavioral) + + + +--- +## Abstract Document +[⬆](#patterns) +--- +layout: pattern +title: Abstract Document +folder: abstract-document +permalink: /patterns/abstract-document/ +categories: Structural +tags: + - Extensibility +--- + +### Intent + +Use dynamic properties and achieve flexibility of untyped languages while keeping type-safety. + +### Explanation + +The Abstract Document pattern enables handling additional, non-static properties. This pattern +uses concept of traits to enable type safety and separate properties of different classes into +set of interfaces. + +Real world example + +> Consider a car that consists of multiple parts. However we don't know if the specific car really has all the parts, or just some of them. Our cars are dynamic and extremely flexible. + +In plain words + +> Abstract Document pattern allows attaching properties to objects without them knowing about it. + +Wikipedia says + +> An object-oriented structural design pattern for organizing objects in loosely typed key-value stores and exposing +the data using typed views. The purpose of the pattern is to achieve a high degree of flexibility between components +in a strongly typed language where new properties can be added to the object-tree on the fly, without losing the +support of type-safety. The pattern makes use of traits to separate different properties of a class into different +interfaces. + +**Programmatic Example** + +Let's first define the base classes `Document` and `AbstractDocument`. They basically make the object hold a property +map and any amount of child objects. + +```java +public interface Document { + + Void put(String key, Object value); + + Object get(String key); + + Stream children(String key, Function, T> constructor); +} + +public abstract class AbstractDocument implements Document { + + private final Map properties; + + protected AbstractDocument(Map properties) { + Objects.requireNonNull(properties, "properties map is required"); + this.properties = properties; + } + + @Override + public Void put(String key, Object value) { + properties.put(key, value); + return null; + } + + @Override + public Object get(String key) { + return properties.get(key); + } + + @Override + public Stream children(String key, Function, T> constructor) { + return Stream.ofNullable(get(key)) + .filter(Objects::nonNull) + .map(el -> (List>) el) + .findAny() + .stream() + .flatMap(Collection::stream) + .map(constructor); + } + ... +} +``` +Next we define an enum `Property` and a set of interfaces for type, price, model and parts. This allows us to create +static looking interface to our `Car` class. + +```java +public enum Property { + + PARTS, TYPE, PRICE, MODEL +} + +public interface HasType extends Document { + + default Optional getType() { + return Optional.ofNullable((String) get(Property.TYPE.toString())); + } +} + +public interface HasPrice extends Document { + + default Optional getPrice() { + return Optional.ofNullable((Number) get(Property.PRICE.toString())); + } +} +public interface HasModel extends Document { + + default Optional getModel() { + return Optional.ofNullable((String) get(Property.MODEL.toString())); + } +} + +public interface HasParts extends Document { + + default Stream getParts() { + return children(Property.PARTS.toString(), Part::new); + } +} +``` + +Now we are ready to introduce the `Car`. + +```java +public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts { + + public Car(Map properties) { + super(properties); + } +} +``` + +And finally here's how we construct and use the `Car` in a full example. + +```java + LOGGER.info("Constructing parts and car"); + + var wheelProperties = Map.of( + Property.TYPE.toString(), "wheel", + Property.MODEL.toString(), "15C", + Property.PRICE.toString(), 100L); + + var doorProperties = Map.of( + Property.TYPE.toString(), "door", + Property.MODEL.toString(), "Lambo", + Property.PRICE.toString(), 300L); + + var carProperties = Map.of( + Property.MODEL.toString(), "300SL", + Property.PRICE.toString(), 10000L, + Property.PARTS.toString(), List.of(wheelProperties, doorProperties)); + + var car = new Car(carProperties); + + LOGGER.info("Here is our car:"); + LOGGER.info("-> model: {}", car.getModel().orElseThrow()); + LOGGER.info("-> price: {}", car.getPrice().orElseThrow()); + LOGGER.info("-> parts: "); + car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}", + p.getType().orElse(null), + p.getModel().orElse(null), + p.getPrice().orElse(null)) + ); + + // Constructing parts and car + // Here is our car: + // model: 300SL + // price: 10000 + // parts: + // wheel/15C/100 + // door/Lambo/300 +``` + +### Class diagram + +![alt text](./etc/abstract-document.png "Abstract Document Traits and Domain") + +### Applicability + +Use the Abstract Document Pattern when + +* There is a need to add new properties on the fly +* You want a flexible way to organize domain in tree like structure +* You want more loosely coupled system + +### Credits + +* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern) +* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf) +* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)](https://www.amazon.com/gp/product/0470059028/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0470059028&linkId=e3aacaea7017258acf184f9f3283b492) + + +## Abstract Factory +[⬆](#patterns) +--- +layout: pattern +title: Abstract Factory +folder: abstract-factory +permalink: /patterns/abstract-factory/ +categories: Creational +tags: + - Gang of Four +--- + +### Also known as + +Kit + +### Intent + +Provide an interface for creating families of related or dependent +objects without specifying their concrete classes. + +### Explanation + +Real world example + +> To create a kingdom we need objects with a common theme. Elven kingdom needs an Elven king, Elven castle and Elven army whereas Orcish kingdom needs an Orcish king, Orcish castle and Orcish army. There is a dependency between the objects in the kingdom. + +In plain words + +> A factory of factories; a factory that groups the individual but related/dependent factories together without specifying their concrete classes. + +Wikipedia 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 + +**Programmatic Example** + +Translating the kingdom example above. First of all we have some interfaces and implementation for the objects in the +kingdom. + +```java +public interface Castle { + String getDescription(); +} + +public interface King { + String getDescription(); +} + +public interface Army { + String getDescription(); +} + +// Elven implementations -> +public class ElfCastle implements Castle { + static final String DESCRIPTION = "This is the Elven castle!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} +public class ElfKing implements King { + static final String DESCRIPTION = "This is the Elven king!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} +public class ElfArmy implements Army { + static final String DESCRIPTION = "This is the Elven Army!"; + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +// Orcish implementations similarly -> ... + +``` + +Then we have the abstraction and implementations for the kingdom factory + +```java +public interface KingdomFactory { + Castle createCastle(); + King createKing(); + Army createArmy(); +} + +public class ElfKingdomFactory implements KingdomFactory { + public Castle createCastle() { + return new ElfCastle(); + } + public King createKing() { + return new ElfKing(); + } + public Army createArmy() { + return new ElfArmy(); + } +} + +public class OrcKingdomFactory implements KingdomFactory { + public Castle createCastle() { + return new OrcCastle(); + } + public King createKing() { + return new OrcKing(); + } + public Army createArmy() { + return new OrcArmy(); + } +} +``` + +Now we have our abstract factory that lets us make family of related objects i.e. Elven kingdom factory creates Elven castle, king and army etc. + +```java +var factory = new ElfKingdomFactory(); +var castle = factory.createCastle(); +var king = factory.createKing(); +var army = factory.createArmy(); + +castle.getDescription(); +king.getDescription(); +army.getDescription(); +``` + +Program output: + +```java +This is the Elven castle! +This is the Elven king! +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. + +```java +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) { + var 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 +} +``` + +### Class diagram + +![alt text](./etc/abstract-factory.urm.png "Abstract Factory class diagram") + + +### Applicability + +Use the Abstract Factory pattern when + +* The system should be independent of how its products are created, composed and represented +* The system should be configured with one of multiple families of products +* The 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 +* 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. +* When you need consistency among products +* You don’t want to change existing code when adding new products or families of products to the program. + +### Example use cases + +* Selecting to call to the appropriate implementation of FileSystemAcmeService or DatabaseAcmeService or NetworkAcmeService at runtime. +* Unit test case writing becomes much easier +* UI tools for different OS + +### Consequences + +* Dependency injection in java hides the service class dependencies that can lead to runtime errors that would have been caught at compile time. +* While the pattern is great when creating predefined objects, adding the new ones might be challenging. +* The code becomes more complicated than it should be, since a lot of new interfaces and classes are introduced along with the pattern. + +### Tutorial + +* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java) + +### Known uses + +* [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--) + +### Related patterns + +[Factory Method](https://java-design-patterns.com/patterns/factory-method/) +[Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + +## Active Object +[⬆](#patterns) +--- +layout: pattern +title: Active Object +folder: active-object +permalink: /patterns/active-object/ +categories: Concurrency +tags: + - Performance +--- + + +## Intent +The active object design pattern decouples method execution from method invocation for objects that each reside in their thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests. + +## Explanation + +The class that implements the active object pattern will contain a self-synchronization mechanism without using 'synchronized' methods. + +Real-world example + +>The Orcs are known for their wildness and untameable soul. It seems like they have their own thread of control based on previous behavior. + +To implement a creature that has its own thread of control mechanism and expose its API only and not the execution itself, we can use the Active Object pattern. + + +**Programmatic Example** + +```java +public abstract class ActiveCreature{ + private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName()); + + private BlockingQueue requests; + + private String name; + + private Thread thread; + + public ActiveCreature(String name) { + this.name = name; + this.requests = new LinkedBlockingQueue(); + thread = new Thread(new Runnable() { + @Override + public void run() { + while (true) { + try { + requests.take().run(); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + } + } + } + ); + thread.start(); + } + + public void eat() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} is eating!",name()); + logger.info("{} has finished eating!",name()); + } + } + ); + } + + public void roam() throws InterruptedException { + requests.put(new Runnable() { + @Override + public void run() { + logger.info("{} has started to roam and the wastelands.",name()); + } + } + ); + } + + public String name() { + return this.name; + } +} +``` + +We can see that any class that will extend the ActiveCreature class will have its own thread of control to execute and invocate methods. + +For example, the Orc class: + +```java +public class Orc extends ActiveCreature { + + public Orc(String name) { + super(name); + } + +} +``` + +Now, we can create multiple creatures such as Orcs, tell them to eat and roam and they will execute it on their own thread of control: + +```java + public static void main(String[] args) { + var app = new App(); + app.run(); + } + + @Override + public void run() { + ActiveCreature creature; + try { + for (int i = 0;i < creatures;i++) { + creature = new Orc(Orc.class.getSimpleName().toString() + i); + creature.eat(); + creature.roam(); + } + Thread.sleep(1000); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + Runtime.getRuntime().exit(1); + } +``` + +## Class diagram + +![alt text](./etc/active-object.urm.PNG "Active Object class diagram") + +## Acyclic Visitor +[⬆](#patterns) +--- +layout: pattern +title: Acyclic Visitor +folder: acyclic-visitor +permalink: /patterns/acyclic-visitor/ +categories: Behavioral +tags: + - Extensibility +--- + +### Intent + +Allow new functions to be added to existing class hierarchies without affecting those hierarchies, and without creating +the troublesome dependency cycles that are inherent to the GoF Visitor Pattern. + +### Explanation + +Real world example + +> We have a hierarchy of modem classes. The modems in this hierarchy need to be visited by an external algorithm based +> on filtering criteria (is it Unix or DOS compatible modem). + +In plain words + +> Acyclic Visitor allows functions to be added to existing class hierarchies without modifying the hierarchies. + +[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) says + +> The Acyclic Visitor pattern allows new functions to be added to existing class hierarchies without affecting those +> hierarchies, and without creating the dependency cycles that are inherent to the GangOfFour VisitorPattern. + +**Programmatic Example** + +Here's the `Modem` hierarchy. + +```java +public abstract class Modem { + public abstract void accept(ModemVisitor modemVisitor); +} + +public class Zoom extends Modem { + ... + @Override + public void accept(ModemVisitor modemVisitor) { + if (modemVisitor instanceof ZoomVisitor) { + ((ZoomVisitor) modemVisitor).visit(this); + } else { + LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem"); + } + } +} + +public class Hayes extends Modem { + ... + @Override + public void accept(ModemVisitor modemVisitor) { + if (modemVisitor instanceof HayesVisitor) { + ((HayesVisitor) modemVisitor).visit(this); + } else { + LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem"); + } + } +} +``` + +Next we introduce the `ModemVisitor` hierarchy. + +```java +public interface ModemVisitor { +} + +public interface HayesVisitor extends ModemVisitor { + void visit(Hayes hayes); +} + +public interface ZoomVisitor extends ModemVisitor { + void visit(Zoom zoom); +} + +public interface AllModemVisitor extends ZoomVisitor, HayesVisitor { +} + +public class ConfigureForDosVisitor implements AllModemVisitor { + ... + @Override + public void visit(Hayes hayes) { + LOGGER.info(hayes + " used with Dos configurator."); + } + @Override + public void visit(Zoom zoom) { + LOGGER.info(zoom + " used with Dos configurator."); + } +} + +public class ConfigureForUnixVisitor implements ZoomVisitor { + ... + @Override + public void visit(Zoom zoom) { + LOGGER.info(zoom + " used with Unix configurator."); + } +} +``` + +Finally, here are the visitors in action. + +```java + var conUnix = new ConfigureForUnixVisitor(); + var conDos = new ConfigureForDosVisitor(); + var zoom = new Zoom(); + var hayes = new Hayes(); + hayes.accept(conDos); + zoom.accept(conDos); + hayes.accept(conUnix); + zoom.accept(conUnix); +``` + +Program output: + +``` + // Hayes modem used with Dos configurator. + // Zoom modem used with Dos configurator. + // Only HayesVisitor is allowed to visit Hayes modem + // Zoom modem used with Unix configurator. +``` + +### Class diagram + +![alt text](./etc/acyclic-visitor.png "Acyclic Visitor") + +### Applicability + +This pattern can be used: + +* When you need to add a new function to an existing hierarchy without the need to alter or affect that hierarchy. +* When there are functions that operate upon a hierarchy, but which do not belong in the hierarchy itself. e.g. the ConfigureForDOS / ConfigureForUnix / ConfigureForX issue. +* When you need to perform very different operations on an object depending upon its type. +* When the visited class hierarchy will be frequently extended with new derivatives of the Element class. +* When the recompilation, relinking, retesting or redistribution of the derivatives of Element is very expensive. + +### Consequences + +The good: + +* No dependency cycles between class hierarchies. +* No need to recompile all the visitors if a new one is added. +* Does not cause compilation failure in existing visitors if class hierarchy has a new member. + +The bad: + +* Violates [Liskov's Substitution Principle](https://java-design-patterns.com/principles/#liskov-substitution-principle) by showing that it can accept all visitors but actually only being interested in particular visitors. +* Parallel hierarchy of visitors has to be created for all members in visitable class hierarchy. + +### Related patterns + +* [Visitor Pattern](https://java-design-patterns.com/patterns/visitor/) + +### Credits + +* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf) +* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) + + +## Adapter +[⬆](#patterns) +--- +layout: pattern +title: Adapter +folder: adapter +permalink: /patterns/adapter/ +categories: Structural +tags: + - Gang of Four +--- + +### Also known as +Wrapper + +### Intent +Convert the interface of a class into another interface the clients expect. Adapter lets classes work together that +couldn't otherwise because of incompatible interfaces. + +### Explanation + +Real world example + +> Consider that you have some pictures in your memory card and you need to transfer them to your computer. In order to transfer them you need some kind of adapter that is compatible with your computer ports so that you can attach memory card to your computer. In this case card reader is an adapter. +> Another example would be the famous power adapter; a three legged plug can't be connected to a two pronged outlet, it needs to use a power adapter that makes it compatible with the two pronged outlet. +> Yet another example would be a translator translating words spoken by one person to another + +In plain words + +> Adapter pattern lets you wrap an otherwise incompatible object in an adapter to make it compatible with another class. + +Wikipedia says + +> In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface. It is often used to make existing classes work with others without modifying their source code. + +**Programmatic Example** + +Consider a captain that can only use rowing boats and cannot sail at all. + +First we have interfaces `RowingBoat` and `FishingBoat` + +```java +public interface RowingBoat { + void row(); +} + +public class FishingBoat { + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoat.class); + public void sail() { + LOGGER.info("The fishing boat is sailing"); + } +} +``` + +And captain expects an implementation of `RowingBoat` interface to be able to move + +```java +public class Captain { + + private final RowingBoat rowingBoat; + // default constructor and setter for rowingBoat + public Captain(RowingBoat rowingBoat) { + this.rowingBoat = rowingBoat; + } + + public void row() { + rowingBoat.row(); + } +} +``` + +Now let's say the pirates are coming and our captain needs to escape but there is only fishing boat available. We need to create an adapter that allows the captain to operate the fishing boat with his rowing boat skills. + +```java +public class FishingBoatAdapter implements RowingBoat { + + private static final Logger LOGGER = LoggerFactory.getLogger(FishingBoatAdapter.class); + + private final FishingBoat boat; + + public FishingBoatAdapter() { + boat = new FishingBoat(); + } + + @Override + public void row() { + boat.sail(); + } +} +``` + +And now the `Captain` can use the `FishingBoat` to escape the pirates. + +```java +var captain = new Captain(new FishingBoatAdapter()); +captain.row(); +``` + +### Class diagram +![alt text](./etc/adapter.urm.png "Adapter class diagram") + +### Applicability +Use the Adapter pattern when + +* you want to use an existing class, and its interface does not match the one you need +* you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don't necessarily have compatible interfaces +* you need to use several existing subclasses, but it's impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class. +* most of the applications using third party libraries use adapters as a middle layer between the application and the 3rd party library to decouple the application from the library. If another library has to be used only an adapter for the new library is required without having to change the application code. + +### Consequences +Class and object adapters have different trade-offs. A class adapter + +* adapts Adaptee to Target by committing to a concrete Adaptee class. As a consequence, a class adapter won’t work when we want to adapt a class and all its subclasses. +* let’s Adapter override some of Adaptee’s behavior, since Adapter is a subclass of Adaptee. +* introduces only one object, and no additional pointer indirection is needed to get to the adaptee. + +An object adapter + +* let’s a single Adapter work with many Adaptees—that is, the Adaptee itself and all of its subclasses (if any). The Adapter can also add functionality to all Adaptees at once. +* makes it harder to override Adaptee behavior. It will require subclassing Adaptee and making Adapter refer to the subclass rather than the Adaptee itself. + + +## Real world examples + +* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29) +* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-) +* [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-) +* [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-) + + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) + + +## Aggregator Microservices +[⬆](#patterns) +--- +layout: pattern +title: Aggregator Microservices +folder: aggregator-microservices +permalink: /patterns/aggregator-microservices/ +categories: Architectural +tags: +- Cloud distributed +- Decoupling +- Microservices +--- + +### Intent + +The user makes a single call to the aggregator service, and the aggregator then calls each relevant microservice. + +### Explanation + +Real world example + +> Our web marketplace needs information about products and their current inventory. It makes a call to an aggregator +> service which in turn calls the product information microservice and product inventory microservice returning the +> combined information. + +In plain words + +> Aggregator Microservice collects pieces of data from various microservices and returns an aggregate for processing. + +Stack Overflow says + +> Aggregator Microservice invokes multiple services to achieve the functionality required by the application. + +**Programmatic Example** + +Let's start from the data model. Here's our `Product`. + +```java +public class Product { + private String title; + private int productInventories; + // getters and setters -> + ... +} +``` + +Next we can introduce our `Aggregator` microservice. It contains clients `ProductInformationClient` and +`ProductInventoryClient` for calling respective microservices. + +```java +@RestController +public class Aggregator { + + @Resource + private ProductInformationClient informationClient; + + @Resource + private ProductInventoryClient inventoryClient; + + @RequestMapping(path = "/product", method = RequestMethod.GET) + public Product getProduct() { + + var product = new Product(); + var productTitle = informationClient.getProductTitle(); + var productInventory = inventoryClient.getProductInventories(); + + //Fallback to error message + product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed")); + + //Fallback to default error inventory + product.setProductInventories(requireNonNullElse(productInventory, -1)); + + return product; + } +} +``` + +Here's the essence of information microservice implementation. Inventory microservice is similar, it just returns +inventory counts. + +```java +@RestController +public class InformationController { + @RequestMapping(value = "/information", method = RequestMethod.GET) + public String getProductTitle() { + return "The Product Title."; + } +} +``` + +Now calling our `Aggregator` REST API returns the product information. + +```bash +curl http://localhost:50004/product +{"title":"The Product Title.","productInventories":5} +``` + +### Class diagram + +![alt text](./aggregator-service/etc/aggregator-service.png "Aggregator Microservice") + +### Applicability + +Use the Aggregator Microservices pattern when you need a unified API for various microservices, regardless the client device. + +### Credits + +* [Microservice Design Patterns](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/) +* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60) +* [Architectural Patterns: Uncover essential patterns in the most indispensable realm of enterprise architecture](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4) + +## Ambassador +[⬆](#patterns) +--- +layout: pattern +title: Ambassador +folder: ambassador +permalink: /patterns/ambassador/ +categories: Structural +tags: + - Decoupling + - Cloud distributed +--- + +### Intent + +Provide a helper service instance on a client and offload common functionality away from a shared resource. + +### Explanation + +Real world example + +> A remote service has many clients accessing a function it provides. The service is a legacy application and is +> impossible to update. Large numbers of requests from users are causing connectivity issues. New rules for request +> frequency should be implemented along with latency checks and client-side logging. + +In plain words + +> With the Ambassador pattern, we can implement less-frequent polling from clients along with latency checks and +> logging. + +Microsoft documentation states + +> An ambassador service can be thought of as an out-of-process proxy which is co-located with the client. This pattern +> can be useful for offloading common client connectivity tasks such as monitoring, logging, routing, +> security (such as TLS), and resiliency patterns in a language agnostic way. It is often used with legacy applications, +> or other applications that are difficult to modify, in order to extend their networking capabilities. It can also +> enable a specialized team to implement those features. + +**Programmatic Example** + +With the above introduction in mind we will imitate the functionality in this example. We have an interface implemented +by the remote service as well as the ambassador service: + +```java +interface RemoteServiceInterface { + long doRemoteFunction(int value) throws Exception; +} +``` + +A remote services represented as a singleton. + +```java +public class RemoteService implements RemoteServiceInterface { + + private static final Logger LOGGER = LoggerFactory.getLogger(RemoteService.class); + private static RemoteService service = null; + + static synchronized RemoteService getRemoteService() { + if (service == null) { + service = new RemoteService(); + } + return service; + } + + private RemoteService() {} + + @Override + public long doRemoteFunction(int value) { + long waitTime = (long) Math.floor(Math.random() * 1000); + + try { + sleep(waitTime); + } catch (InterruptedException e) { + LOGGER.error("Thread sleep interrupted", e); + } + + return waitTime >= 200 ? value * 10 : -1; + } +} +``` + +A service ambassador adding additional features such as logging, latency checks + +```java +public class ServiceAmbassador implements RemoteServiceInterface { + + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceAmbassador.class); + private static final int RETRIES = 3; + private static final int DELAY_MS = 3000; + + ServiceAmbassador() { + } + + @Override + public long doRemoteFunction(int value) { + return safeCall(value); + } + + private long checkLatency(int value) { + var startTime = System.currentTimeMillis(); + var result = RemoteService.getRemoteService().doRemoteFunction(value); + var timeTaken = System.currentTimeMillis() - startTime; + + LOGGER.info("Time taken (ms): " + timeTaken); + return result; + } + + private long safeCall(int value) { + var retries = 0; + var result = (long) FAILURE; + + for (int i = 0; i < RETRIES; i++) { + if (retries >= RETRIES) { + return FAILURE; + } + + if ((result = checkLatency(value)) == FAILURE) { + LOGGER.info("Failed to reach remote: (" + (i + 1) + ")"); + retries++; + try { + sleep(DELAY_MS); + } catch (InterruptedException e) { + LOGGER.error("Thread sleep state interrupted", e); + } + } else { + break; + } + } + return result; + } +} +``` + +A client has a local service ambassador used to interact with the remote service: + +```java +public class Client { + + private static final Logger LOGGER = LoggerFactory.getLogger(Client.class); + private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador(); + + long useService(int value) { + var result = serviceAmbassador.doRemoteFunction(value); + LOGGER.info("Service result: " + result); + return result; + } +} +``` + +Here are two clients using the service. + +```java +public class App { + public static void main(String[] args) { + var host1 = new Client(); + var host2 = new Client(); + host1.useService(12); + host2.useService(73); + } +} +``` + +Here's the output for running the example: + +```java +Time taken (ms): 111 +Service result: 120 +Time taken (ms): 931 +Failed to reach remote: (1) +Time taken (ms): 665 +Failed to reach remote: (2) +Time taken (ms): 538 +Failed to reach remote: (3) +Service result: -1 +``` + +### Class diagram + +![alt text](./etc/ambassador.urm.png "Ambassador class diagram") + +### Applicability + +Ambassador is applicable when working with a legacy remote service which cannot be modified or would be extremely +difficult to modify. Connectivity features can be implemented on the client avoiding the need for changes on the remote +service. + +* Ambassador provides a local interface for a remote service. +* Ambassador provides logging, circuit breaking, retries and security on the client. + +## Typical Use Case + +* Control access to another object +* Implement logging +* Implement circuit breaking +* Offload remote service tasks +* Facilitate network connection + +### Known uses + +* [Kubernetes-native API gateway for microservices](https://github.com/datawire/ambassador) + +### Related patterns + +* [Proxy](https://java-design-patterns.com/patterns/proxy/) + +### Credits + +* [Ambassador pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador) +* [Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services](https://books.google.co.uk/books?id=6BJNDwAAQBAJ&pg=PT35&lpg=PT35&dq=ambassador+pattern+in+real+world&source=bl&ots=d2e7GhYdHi&sig=Lfl_MDnCgn6lUcjzOg4GXrN13bQ&hl=en&sa=X&ved=0ahUKEwjk9L_18rrbAhVpKcAKHX_KA7EQ6AEIWTAI#v=onepage&q=ambassador%20pattern%20in%20real%20world&f=false) + +## Api Gateway +[⬆](#patterns) +--- +layout: pattern +title: API Gateway +folder: api-gateway +permalink: /patterns/api-gateway/ +categories: Architectural +tags: + - Cloud distributed + - Decoupling + - Microservices +--- + +### Intent + +Aggregate calls to microservices in a single location, the API Gateway. The user makes a single call +to the API Gateway, and the API Gateway then calls each relevant microservice. + +### Explanation + +With the Microservices pattern, a client may need data from multiple different microservices. If the +client called each microservice directly, that could contribute to longer load times, since the +client would have to make a network request for each microservice called. Moreover, having the +client call each microservice directly ties the client to that microservice - if the internal +implementations of the microservices change (for example, if two microservices are combined sometime +in the future) or if the location (host and port) of a microservice changes, then every client that +makes use of those microservices must be updated. + +The intent of the API Gateway pattern is to alleviate some of these issues. In the API Gateway +pattern, an additional entity (the API Gateway) is placed between the client and the microservices. +The job of the API Gateway is to aggregate the calls to the microservices. Rather than the client +calling each microservice individually, the client calls the API Gateway a single time. The API +Gateway then calls each of the microservices that the client needs. + +Real world example + +> We are implementing microservices and API Gateway pattern for an e-commerce site. In this system +> the API Gateway makes calls to the Image and Price microservices. + +In plain words + +> For a system implemented using microservices architecture, API Gateway is the single entry point +> that aggregates the calls to the individual microservices. + +Wikipedia says + +> API Gateway is a server that acts as an API front-end, receives API requests, enforces throttling +> and security policies, passes requests to the back-end service and then passes the response back +> to the requester. A gateway often includes a transformation engine to orchestrate and modify the +> requests and responses on the fly. A gateway can also provide functionality such as collecting +> analytics data and providing caching. The gateway can provide functionality to support +> authentication, authorization, security, audit and regulatory compliance. + +**Programmatic Example** + +This implementation shows what the API Gateway pattern could look like for an e-commerce site. The +`ApiGateway` makes calls to the Image and Price microservices using the `ImageClientImpl` and +`PriceClientImpl` respectively. Customers viewing the site on a desktop device can see both price +information and an image of a product, so the `ApiGateway` calls both of the microservices and +aggregates the data in the `DesktopProduct` model. However, mobile users only see price information; +they do not see a product image. For mobile users, the `ApiGateway` only retrieves price +information, which it uses to populate the `MobileProduct`. + +Here's the Image microservice implementation. + +```java +public interface ImageClient { + String getImagePath(); +} + +public class ImageClientImpl implements ImageClient { + @Override + public String getImagePath() { + var httpClient = HttpClient.newHttpClient(); + var httpGet = HttpRequest.newBuilder() + .GET() + .uri(URI.create("http://localhost:50005/image-path")) + .build(); + + try { + var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString()); + return httpResponse.body(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + + return null; + } +} +``` + +Here's the Price microservice implementation. + +```java +public interface PriceClient { + String getPrice(); +} + +public class PriceClientImpl implements PriceClient { + + @Override + public String getPrice() { + var httpClient = HttpClient.newHttpClient(); + var httpGet = HttpRequest.newBuilder() + .GET() + .uri(URI.create("http://localhost:50006/price")) + .build(); + + try { + var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString()); + return httpResponse.body(); + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + + return null; + } +} +``` + +Here we can see how API Gateway maps the requests to the microservices. + +```java +public class ApiGateway { + + @Resource + private ImageClient imageClient; + + @Resource + private PriceClient priceClient; + + @RequestMapping(path = "/desktop", method = RequestMethod.GET) + public DesktopProduct getProductDesktop() { + var desktopProduct = new DesktopProduct(); + desktopProduct.setImagePath(imageClient.getImagePath()); + desktopProduct.setPrice(priceClient.getPrice()); + return desktopProduct; + } + + @RequestMapping(path = "/mobile", method = RequestMethod.GET) + public MobileProduct getProductMobile() { + var mobileProduct = new MobileProduct(); + mobileProduct.setPrice(priceClient.getPrice()); + return mobileProduct; + } +} +``` + +### Class diagram +![alt text](./etc/api-gateway.png "API Gateway") + +### Applicability + +Use the API Gateway pattern when + +* You're using microservices architecture and need a single point of aggregation for your microservice calls. + +### Credits + +* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html) +* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/) +* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=ac7b6a57f866ac006a309d9086e8cfbd) +* [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/gp/product/1491950358/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1491950358&linkId=4c95ca9831e05e3f0dadb08841d77bf1) + + +## Arrange/Act/Assert +[⬆](#patterns) +--- +layout: pattern +title: Arrange/Act/Assert +folder: arrange-act-assert +permalink: /patterns/arrange-act-assert/ +categories: Idiom +tags: + - Testing +--- + +### Also known as + +Given/When/Then + +### Intent + +Arrange/Act/Assert (AAA) is a pattern for organizing unit tests. +It breaks tests down into three clear and distinct steps: + +1. Arrange: Perform the setup and initialization required for the test. +2. Act: Take action(s) required for the test. +3. Assert: Verify the outcome(s) of the test. + +### Explanation + +This pattern has several significant benefits. It creates a clear separation between a test's +setup, operations, and results. This structure makes the code easier to read and understand. If +you place the steps in order and format your code to separate them, you can scan a test and +quickly comprehend what it does. + +It also enforces a certain degree of discipline when you write your tests. You have to think +clearly about the three steps your test will perform. It makes tests more natural to write at +the same time since you already have an outline. + +Real world example + +> We need to write comprehensive and clear unit test suite for a class. + +In plain words + +> Arrange/Act/Assert is a testing pattern that organizes tests into three clear steps for easy +> maintenance. + +WikiWikiWeb says + +> Arrange/Act/Assert is a pattern for arranging and formatting code in UnitTest methods. + +**Programmatic Example** + +Let's first introduce our `Cash` class to be unit tested. + +```java +public class Cash { + + private int amount; + + Cash(int amount) { + this.amount = amount; + } + + void plus(int addend) { + amount += addend; + } + + boolean minus(int subtrahend) { + if (amount >= subtrahend) { + amount -= subtrahend; + return true; + } else { + return false; + } + } + + int count() { + return amount; + } +} +``` + +Then we write our unit tests according to Arrange/Act/Assert pattern. Notice the clearly +separated steps for each unit test. + +```java +public class CashAAATest { + + @Test + public void testPlus() { + //Arrange + var cash = new Cash(3); + //Act + cash.plus(4); + //Assert + assertEquals(7, cash.count()); + } + + @Test + public void testMinus() { + //Arrange + var cash = new Cash(8); + //Act + var result = cash.minus(5); + //Assert + assertTrue(result); + assertEquals(3, cash.count()); + } + + @Test + public void testInsufficientMinus() { + //Arrange + var cash = new Cash(1); + //Act + var result = cash.minus(6); + //Assert + assertFalse(result); + assertEquals(1, cash.count()); + } + + @Test + public void testUpdate() { + //Arrange + var cash = new Cash(5); + //Act + cash.plus(6); + var result = cash.minus(3); + //Assert + assertTrue(result); + assertEquals(8, cash.count()); + } +} +``` + +### Applicability + +Use Arrange/Act/Assert pattern when + +* You need to structure your unit tests so that they're easier to read, maintain, and enhance. + +### Credits + +* [Arrange, Act, Assert: What is AAA Testing?](https://blog.ncrunch.net/post/arrange-act-assert-aaa-testing.aspx) +* [Bill Wake: 3A – Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/) +* [Martin Fowler: GivenWhenThen](https://martinfowler.com/bliki/GivenWhenThen.html) +* [xUnit Test Patterns: Refactoring Test Code](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f7e8dd50d720c9b63dbf) +* [Unit Testing Principles, Practices, and Patterns](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cf22a63c3e4758ae08aa0a0cc35) +* [Test Driven Development: By Example](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b84ca5087472ef0e05) + + +## Async Method Invocation +[⬆](#patterns) +--- +layout: pattern +title: Async Method Invocation +folder: async-method-invocation +permalink: /patterns/async-method-invocation/ +categories: Concurrency +tags: + - Reactive +--- + +### Intent +Asynchronous method invocation is pattern where the calling thread +is not blocked while waiting results of tasks. The pattern provides parallel +processing of multiple independent tasks and retrieving the results via +callbacks or waiting until everything is done. + +# Class diagram +![alt text](./etc/async-method-invocation.png "Async Method Invocation") + +### Applicability +Use async method invocation pattern when + +* you have multiple independent tasks that can run in parallel +* you need to improve the performance of a group of sequential tasks +* you have limited amount of processing capacity or long running tasks and the + caller should not wait the tasks to be ready + +## Real world examples + +* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html), [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) and [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) (Java) +* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx) (.NET) + +## Balking +[⬆](#patterns) +--- +layout: pattern +title: Balking +folder: balking +permalink: /patterns/balking/ +categories: Concurrency +tags: + - Decoupling +--- + +### Intent +Balking Pattern is used to prevent an object from executing certain code if it is an +incomplete or inappropriate state + +### Class diagram +![alt text](./etc/balking.png "Balking") + +### Applicability +Use the Balking pattern when + +* 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 +but for an unknown amount of time + +### Related patterns +* Guarded Suspension Pattern +* Double Checked Locking Pattern + +## Bridge +[⬆](#patterns) +--- +layout: pattern +title: Bridge +folder: bridge +permalink: /patterns/bridge/ +categories: Structural +tags: + - Gang of Four +--- + +### Also known as + +Handle/Body + +### Intent + +Decouple an abstraction from its implementation so that the two can vary independently. + +### Explanation + +Real world example + +> Consider you have a weapon with different enchantments, and you are supposed to allow mixing +> different weapons with different enchantments. What would you do? Create multiple copies of each +> of the weapons for each of the enchantments or would you just create separate enchantment and set +> it for the weapon as needed? Bridge pattern allows you to do the second. + +In Plain Words + +> Bridge pattern is about preferring composition over inheritance. Implementation details are pushed +> from a hierarchy to another object with a separate hierarchy. + +Wikipedia says + +> The bridge pattern is a design pattern used in software engineering that is meant to "decouple an abstraction from its implementation so that the two can vary independently" + +**Programmatic Example** + +Translating our weapon example from above. Here we have the `Weapon` hierarchy: + +```java +public interface Weapon { + void wield(); + void swing(); + void unwield(); + Enchantment getEnchantment(); +} + +public class Sword implements Weapon { + + private final Enchantment enchantment; + + public Sword(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The sword is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The sword is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The sword is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} + +public class Hammer implements Weapon { + + private final Enchantment enchantment; + + public Hammer(Enchantment enchantment) { + this.enchantment = enchantment; + } + + @Override + public void wield() { + LOGGER.info("The hammer is wielded."); + enchantment.onActivate(); + } + + @Override + public void swing() { + LOGGER.info("The hammer is swinged."); + enchantment.apply(); + } + + @Override + public void unwield() { + LOGGER.info("The hammer is unwielded."); + enchantment.onDeactivate(); + } + + @Override + public Enchantment getEnchantment() { + return enchantment; + } +} +``` + +Here's the separate enchantment hierarchy: + +```java +public interface Enchantment { + void onActivate(); + void apply(); + void onDeactivate(); +} + +public class FlyingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item begins to glow faintly."); + } + + @Override + public void apply() { + LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand."); + } + + @Override + public void onDeactivate() { + LOGGER.info("The item's glow fades."); + } +} + +public class SoulEatingEnchantment implements Enchantment { + + @Override + public void onActivate() { + LOGGER.info("The item spreads bloodlust."); + } + + @Override + public void apply() { + LOGGER.info("The item eats the soul of enemies."); + } + + @Override + public void onDeactivate() { + LOGGER.info("Bloodlust slowly disappears."); + } +} +``` + +Here are both hierarchies in action: + +```java +var enchantedSword = new Sword(new SoulEatingEnchantment()); +enchantedSword.wield(); +enchantedSword.swing(); +enchantedSword.unwield(); +// The sword is wielded. +// The item spreads bloodlust. +// The sword is swinged. +// The item eats the soul of enemies. +// The sword is unwielded. +// Bloodlust slowly disappears. + +var hammer = new Hammer(new FlyingEnchantment()); +hammer.wield(); +hammer.swing(); +hammer.unwield(); +// The hammer is wielded. +// The item begins to glow faintly. +// The hammer is swinged. +// The item flies and strikes the enemies finally returning to owner's hand. +// The hammer is unwielded. +// The item's glow fades. +``` + +### Class Diagram + +![alt text](./etc/bridge.urm.png "Bridge class diagram") + +### Applicability + +Use the Bridge pattern when + +* You want to avoid a permanent binding between an abstraction and its implementation. This might be the case, for example, when the implementation must be selected or switched at run-time. +* Both the abstractions and their implementations should be extensible by subclassing. In this case, the Bridge pattern lets you combine the different abstractions and implementations and extend them independently. +* Changes in the implementation of an abstraction should have no impact on clients; that is, their code should not have to be recompiled. +* You have a proliferation of classes. Such a class hierarchy indicates the need for splitting an object into two parts. Rumbaugh uses the term "nested generalizations" to refer to such class hierarchies. +* You want to share an implementation among multiple objects (perhaps using reference counting), and this fact should be hidden from the client. A simple example is Coplien's String class, in which multiple objects can share the same string representation. + +### Tutorial + +* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + + +## Builder +[⬆](#patterns) +--- +layout: pattern +title: Builder +folder: builder +permalink: /patterns/builder/ +categories: Creational +tags: + - Gang of Four +--- + +### Intent + +Separate the construction of a complex object from its representation so that the same construction +process can create different representations. + +### Explanation + +Real world example + +> Imagine a character generator for a role-playing game. The easiest option is to let the computer +> create the character for you. If you want to manually select the character details like +> profession, gender, hair color etc. the character generation becomes a step-by-step process that +> completes when all the selections are ready. + +In plain words + +> Allows you to create different flavors of an object while avoiding constructor pollution. Useful +> when there could be several flavors of an object. Or when there are a lot of steps involved in +> creation of an object. + +Wikipedia says + +> The builder pattern is an object creation software design pattern with the intentions of finding +> a solution to the telescoping constructor anti-pattern. + +Having said that let me add a bit about what telescoping constructor anti-pattern is. At one point +or the other, we have all seen a constructor like below: + +```java +public Hero(Profession profession, String name, HairType hairType, HairColor hairColor, Armor armor, Weapon weapon) { +} +``` + +As you can see the number of constructor parameters can quickly get out of hand, and it may become +difficult to understand the arrangement of parameters. Plus this parameter list could keep on +growing if you would want to add more options in the future. This is called telescoping constructor +anti-pattern. + +**Programmatic Example** + +The sane alternative is to use the Builder pattern. First of all we have our hero that we want to +create: + +```java +public final class Hero { + private final Profession profession; + private final String name; + private final HairType hairType; + private final HairColor hairColor; + private final Armor armor; + private final Weapon weapon; + + private Hero(Builder builder) { + this.profession = builder.profession; + this.name = builder.name; + this.hairColor = builder.hairColor; + this.hairType = builder.hairType; + this.weapon = builder.weapon; + this.armor = builder.armor; + } +} +``` + +Then we have the builder: + +```java + public static class Builder { + private final Profession profession; + private final String name; + private HairType hairType; + private HairColor hairColor; + private Armor armor; + private Weapon weapon; + + public Builder(Profession profession, String name) { + if (profession == null || name == null) { + throw new IllegalArgumentException("profession and name can not be null"); + } + this.profession = profession; + this.name = name; + } + + public Builder withHairType(HairType hairType) { + this.hairType = hairType; + return this; + } + + public Builder withHairColor(HairColor hairColor) { + this.hairColor = hairColor; + return this; + } + + public Builder withArmor(Armor armor) { + this.armor = armor; + return this; + } + + public Builder withWeapon(Weapon weapon) { + this.weapon = weapon; + return this; + } + + public Hero build() { + return new Hero(this); + } + } +``` + +Then it can be used as: + +```java +var mage = new Hero.Builder(Profession.MAGE, "Riobard").withHairColor(HairColor.BLACK).withWeapon(Weapon.DAGGER).build(); +``` + +### Class diagram + +![alt text](./etc/builder.urm.png "Builder class diagram") + +### Applicability + +Use the Builder pattern when + +* The algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled +* The construction process must allow different representations for the object that's constructed + +## Real world examples + +* [java.lang.StringBuilder](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuilder.html) +* [java.nio.ByteBuffer](http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte-) as well as similar buffers such as FloatBuffer, IntBuffer and so on. +* [java.lang.StringBuffer](http://docs.oracle.com/javase/8/docs/api/java/lang/StringBuffer.html#append-boolean-) +* All implementations of [java.lang.Appendable](http://docs.oracle.com/javase/8/docs/api/java/lang/Appendable.html) +* [Apache Camel builders](https://github.com/apache/camel/tree/0e195428ee04531be27a0b659005e3aa8d159d23/camel-core/src/main/java/org/apache/camel/builder) +* [Apache Commons Option.Builder](https://commons.apache.org/proper/commons-cli/apidocs/org/apache/commons/cli/Option.Builder.html) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) + + +## Business Delegate +[⬆](#patterns) +--- +layout: pattern +title: Business Delegate +folder: business-delegate +permalink: /patterns/business-delegate/ +categories: Structural +tags: + - Decoupling +--- + +### Intent +The Business Delegate pattern adds an abstraction layer between +presentation and business tiers. By using the pattern we gain loose coupling +between the tiers and encapsulate knowledge about how to locate, connect to, +and interact with the business objects that make up the application. + +### Class diagram +![alt text](./etc/business-delegate.png "Business Delegate") + +### Applicability +Use the Business Delegate pattern when + +* you want loose coupling between presentation and business tiers +* you want to orchestrate calls to multiple business services +* you want to encapsulate service lookups and service calls + +### Credits + +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) + + +## Bytecode +[⬆](#patterns) +--- +layout: pattern +title: Bytecode +folder: bytecode +permalink: /patterns/bytecode/ +categories: Behavioral +tags: + - Game programming +--- + +### Intent +Allows to encode behaviour as instructions for virtual machine. + +### Class diagram +![alt text](./etc/bytecode.urm.png "Bytecode class diagram") + +### Applicability +Use the Bytecode pattern when you have a lot of behavior you need to define and your +game’s implementation language isn’t a good fit because: + +* it’s too low-level, making it tedious or error-prone to program in. +* iterating on it takes too long due to slow compile times or other tooling issues. +* it has too much trust. If you want to ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of the codebase. + +### Credits + +* [Game programming patterns](http://gameprogrammingpatterns.com/bytecode.html) + +## Caching +[⬆](#patterns) +--- +layout: pattern +title: Caching +folder: caching +permalink: /patterns/caching/ +categories: Behavioral +tags: + - Performance + - Cloud distributed +--- + +### Intent +To avoid expensive re-acquisition of resources by not releasing +the resources immediately after their use. The resources retain their identity, are kept in some +fast-access storage, and are re-used to avoid having to acquire them again. + +### Class diagram +![alt text](./etc/caching.png "Caching") + +### Applicability +Use the Caching pattern(s) when + +* Repetitious acquisition, initialization, and release of the same resource causes unnecessary performance overhead. + +### Credits + +* [Write-through, write-around, write-back: Cache explained](http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained) +* [Read-Through, Write-Through, Write-Behind, and Refresh-Ahead Caching](https://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177) +* [Cache-Aside pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cache-aside) + + +## Callback +[⬆](#patterns) +--- +layout: pattern +title: Callback +folder: callback +permalink: /patterns/callback/ +categories: Idiom +tags: + - Reactive +--- + +### Intent + +Callback is a piece of executable code that is passed as an argument to other code, which is +expected to call back (execute) the argument at some convenient time. + +### Explanation + +Real world example + +> We need to be notified after executing task has finished. We pass a callback method for +> the executor and wait for it to call back on us. + +In plain words + +> Callback is a method passed to the executor which will be called at defined moment. + +Wikipedia says + +> In computer programming, a callback, also known as a "call-after" function, is any executable +> code that is passed as an argument to other code; that other code is expected to call +> back (execute) the argument at a given time. + +**Programmatic Example** + +Callback is a simple interface with single method. + +```java +public interface Callback { + + void call(); +} +``` + +Next we define a task that will execute the callback after the task execution has finished. + +```java +public abstract class Task { + + final void executeWith(Callback callback) { + execute(); + Optional.ofNullable(callback).ifPresent(Callback::call); + } + + public abstract void execute(); +} + +public final class SimpleTask extends Task { + + private static final Logger LOGGER = getLogger(SimpleTask.class); + + @Override + public void execute() { + LOGGER.info("Perform some important activity and after call the callback method."); + } +} +``` + +Finally, here's how we execute a task and receive a callback when it's finished. + +```java + var task = new SimpleTask(); + task.executeWith(() -> LOGGER.info("I'm done now.")); +``` + +### Class diagram + +![alt text](./etc/callback.png "Callback") + +### Applicability + +Use the Callback pattern when + +* when some arbitrary synchronous or asynchronous action must be performed after execution of some defined activity. + +## Real world examples + +* [CyclicBarrier](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CyclicBarrier.html#CyclicBarrier%28int,%20java.lang.Runnable%29) constructor can accept a callback that will be triggered every time a barrier is tripped. + + +## Chain of Responsibility +[⬆](#patterns) +--- +layout: pattern +title: Chain of responsibility +folder: chain +permalink: /patterns/chain/ +categories: Behavioral +tags: + - Gang of Four +--- + +### Intent +Avoid coupling the sender of a request to its receiver by giving more than one object a chance to +handle the request. Chain the receiving objects and pass the request along the chain until an object +handles it. + +### Explanation + +Real world example + +> The Orc King gives loud orders to his army. The closest one to react is the commander, then +> officer and then soldier. The commander, officer and soldier here form a chain of responsibility. + +In plain words + +> It helps to build a chain of objects. A request enters from one end and keeps going from an object +> to another until it finds a suitable handler. + +Wikipedia says + +> In object-oriented design, the chain-of-responsibility pattern is a design pattern consisting of +> a source of command objects and a series of processing objects. Each processing object contains +> logic that defines the types of command objects that it can handle; the rest are passed to the +> next processing object in the chain. + +**Programmatic Example** + +Translating our example with the orcs from above. First we have the `Request` class: + +```java +public class Request { + + private final RequestType requestType; + private final String requestDescription; + private boolean handled; + + public Request(final RequestType requestType, final String requestDescription) { + this.requestType = Objects.requireNonNull(requestType); + this.requestDescription = Objects.requireNonNull(requestDescription); + } + + public String getRequestDescription() { return requestDescription; } + + public RequestType getRequestType() { return requestType; } + + public void markHandled() { this.handled = true; } + + public boolean isHandled() { return this.handled; } + + @Override + public String toString() { return getRequestDescription(); } +} + +public enum RequestType { + DEFEND_CASTLE, TORTURE_PRISONER, COLLECT_TAX +} +``` + +Then the request handler hierarchy + +```java +public abstract class RequestHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(RequestHandler.class); + private final RequestHandler next; + + public RequestHandler(RequestHandler next) { + this.next = next; + } + + public void handleRequest(Request req) { + if (next != null) { + next.handleRequest(req); + } + } + + protected void printHandling(Request req) { + LOGGER.info("{} handling request \"{}\"", this, req); + } + + @Override + public abstract String toString(); +} + +public class OrcCommander extends RequestHandler { + public OrcCommander(RequestHandler handler) { + super(handler); + } + + @Override + public void handleRequest(Request req) { + if (req.getRequestType().equals(RequestType.DEFEND_CASTLE)) { + printHandling(req); + req.markHandled(); + } else { + super.handleRequest(req); + } + } + + @Override + public String toString() { + return "Orc commander"; + } +} + +// OrcOfficer and OrcSoldier are defined similarly as OrcCommander + +``` + +Then we have the Orc King who gives the orders and forms the chain + +```java +public class OrcKing { + RequestHandler chain; + + public OrcKing() { + buildChain(); + } + + private void buildChain() { + chain = new OrcCommander(new OrcOfficer(new OrcSoldier(null))); + } + + public void makeRequest(Request req) { + chain.handleRequest(req); + } +} +``` + +Then it is used as follows + +```java +var king = new OrcKing(); +king.makeRequest(new Request(RequestType.DEFEND_CASTLE, "defend castle")); // Orc commander handling request "defend castle" +king.makeRequest(new Request(RequestType.TORTURE_PRISONER, "torture prisoner")); // Orc officer handling request "torture prisoner" +king.makeRequest(new Request(RequestType.COLLECT_TAX, "collect tax")); // Orc soldier handling request "collect tax" +``` + +### Class diagram + +![alt text](./etc/chain.urm.png "Chain of Responsibility class diagram") + +### Applicability + +Use Chain of Responsibility when + +* More than one object may handle a request, and the handler isn't known a priori. The handler should be ascertained automatically. +* You want to issue a request to one of several objects without specifying the receiver explicitly. +* The set of objects that can handle a request should be specified dynamically. + +## Real world examples + +* [java.util.logging.Logger#log()](http://docs.oracle.com/javase/8/docs/api/java/util/logging/Logger.html#log%28java.util.logging.Level,%20java.lang.String%29) +* [Apache Commons Chain](https://commons.apache.org/proper/commons-chain/index.html) +* [javax.servlet.Filter#doFilter()](http://docs.oracle.com/javaee/7/api/javax/servlet/Filter.html#doFilter-javax.servlet.ServletRequest-javax.servlet.ServletResponse-javax.servlet.FilterChain-) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + + +## Circuit Breaker +[⬆](#patterns) +--- +layout: pattern +title: Circuit Breaker +folder: circuit-breaker +permalink: /patterns/circuit-breaker/ +categories: Behavioral +tags: + - Performance + - Decoupling + - Cloud distributed +--- + +### Intent + +Handle costly remote service calls in such a way that the failure of a single service/component +cannot bring the whole application down, and we can reconnect to the service as soon as possible. + +### Explanation + +Real world example + +> Imagine a web application that has both local files/images and remote services that are used for +> fetching data. These remote services may be either healthy and responsive at times, or may become +> slow and unresponsive at some point of time due to variety of reasons. So if one of the remote +> services is slow or not responding successfully, our application will try to fetch response from +> the remote service using multiple threads/processes, soon all of them will hang (also called +> [thread starvation](https://en.wikipedia.org/wiki/Starvation_(computer_science))) causing our entire web application to crash. We should be able to detect +> this situation and show the user an appropriate message so that he/she can explore other parts of +> the app unaffected by the remote service failure. Meanwhile, the other services that are working +> normally, should keep functioning unaffected by this failure. + +In plain words + +> Circuit Breaker allows graceful handling of failed remote services. It's especially useful when +> all parts of our application are highly decoupled from each other, and failure of one component +> doesn't mean the other parts will stop working. + +Wikipedia says + +> Circuit breaker is a design pattern used in modern software development. It is used to detect +> failures and encapsulates the logic of preventing a failure from constantly recurring, during +> maintenance, temporary external system failure or unexpected system difficulties. + +## Programmatic Example + +So, how does this all come together? With the above example in mind we will imitate the +functionality in a simple example. A monitoring service mimics the web app and makes both local and +remote calls. + +The service architecture is as follows: + +![alt text](./etc/ServiceDiagram.PNG "Service Diagram") + +In terms of code, the end user application is: + +```java +public class App { + + private static final Logger LOGGER = LoggerFactory.getLogger(App.class); + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(String[] args) { + + var serverStartTime = System.nanoTime(); + + var delayedService = new DelayedRemoteService(serverStartTime, 5); + var delayedServiceCircuitBreaker = new DefaultCircuitBreaker(delayedService, 3000, 2, + 2000 * 1000 * 1000); + + var quickService = new QuickRemoteService(); + var quickServiceCircuitBreaker = new DefaultCircuitBreaker(quickService, 3000, 2, + 2000 * 1000 * 1000); + + //Create an object of monitoring service which makes both local and remote calls + var monitoringService = new MonitoringService(delayedServiceCircuitBreaker, + quickServiceCircuitBreaker); + + //Fetch response from local resource + LOGGER.info(monitoringService.localResourceResponse()); + + //Fetch response from delayed service 2 times, to meet the failure threshold + LOGGER.info(monitoringService.delayedServiceResponse()); + LOGGER.info(monitoringService.delayedServiceResponse()); + + //Fetch current state of delayed service circuit breaker after crossing failure threshold limit + //which is OPEN now + LOGGER.info(delayedServiceCircuitBreaker.getState()); + + //Meanwhile, the delayed service is down, fetch response from the healthy quick service + LOGGER.info(monitoringService.quickServiceResponse()); + LOGGER.info(quickServiceCircuitBreaker.getState()); + + //Wait for the delayed service to become responsive + try { + LOGGER.info("Waiting for delayed service to become responsive"); + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + //Check the state of delayed circuit breaker, should be HALF_OPEN + LOGGER.info(delayedServiceCircuitBreaker.getState()); + + //Fetch response from delayed service, which should be healthy by now + LOGGER.info(monitoringService.delayedServiceResponse()); + //As successful response is fetched, it should be CLOSED again. + LOGGER.info(delayedServiceCircuitBreaker.getState()); + } +} +``` + +The monitoring service: + +```java +public class MonitoringService { + + private final CircuitBreaker delayedService; + + private final CircuitBreaker quickService; + + public MonitoringService(CircuitBreaker delayedService, CircuitBreaker quickService) { + this.delayedService = delayedService; + this.quickService = quickService; + } + + //Assumption: Local service won't fail, no need to wrap it in a circuit breaker logic + public String localResourceResponse() { + return "Local Service is working"; + } + + /** + * Fetch response from the delayed service (with some simulated startup time). + * + * @return response string + */ + public String delayedServiceResponse() { + try { + return this.delayedService.attemptRequest(); + } catch (RemoteServiceException e) { + return e.getMessage(); + } + } + + /** + * Fetches response from a healthy service without any failure. + * + * @return response string + */ + public String quickServiceResponse() { + try { + return this.quickService.attemptRequest(); + } catch (RemoteServiceException e) { + return e.getMessage(); + } + } +} +``` +As it can be seen, it does the call to get local resources directly, but it wraps the call to +remote (costly) service in a circuit breaker object, which prevents faults as follows: + +```java +public class DefaultCircuitBreaker implements CircuitBreaker { + + private final long timeout; + private final long retryTimePeriod; + private final RemoteService service; + long lastFailureTime; + private String lastFailureResponse; + int failureCount; + private final int failureThreshold; + private State state; + private final long futureTime = 1000 * 1000 * 1000 * 1000; + + /** + * Constructor to create an instance of Circuit Breaker. + * + * @param timeout Timeout for the API request. Not necessary for this simple example + * @param failureThreshold Number of failures we receive from the depended service before changing + * state to 'OPEN' + * @param retryTimePeriod Time period after which a new request is made to remote service for + * status check. + */ + DefaultCircuitBreaker(RemoteService serviceToCall, long timeout, int failureThreshold, + long retryTimePeriod) { + this.service = serviceToCall; + // We start in a closed state hoping that everything is fine + this.state = State.CLOSED; + this.failureThreshold = failureThreshold; + // Timeout for the API request. + // Used to break the calls made to remote resource if it exceeds the limit + this.timeout = timeout; + this.retryTimePeriod = retryTimePeriod; + //An absurd amount of time in future which basically indicates the last failure never happened + this.lastFailureTime = System.nanoTime() + futureTime; + this.failureCount = 0; + } + + // Reset everything to defaults + @Override + public void recordSuccess() { + this.failureCount = 0; + this.lastFailureTime = System.nanoTime() + futureTime; + this.state = State.CLOSED; + } + + @Override + public void recordFailure(String response) { + failureCount = failureCount + 1; + this.lastFailureTime = System.nanoTime(); + // Cache the failure response for returning on open state + this.lastFailureResponse = response; + } + + // Evaluate the current state based on failureThreshold, failureCount and lastFailureTime. + protected void evaluateState() { + if (failureCount >= failureThreshold) { //Then something is wrong with remote service + if ((System.nanoTime() - lastFailureTime) > retryTimePeriod) { + //We have waited long enough and should try checking if service is up + state = State.HALF_OPEN; + } else { + //Service would still probably be down + state = State.OPEN; + } + } else { + //Everything is working fine + state = State.CLOSED; + } + } + + @Override + public String getState() { + evaluateState(); + return state.name(); + } + + /** + * Break the circuit beforehand if it is known service is down Or connect the circuit manually if + * service comes online before expected. + * + * @param state State at which circuit is in + */ + @Override + public void setState(State state) { + this.state = state; + switch (state) { + case OPEN: + this.failureCount = failureThreshold; + this.lastFailureTime = System.nanoTime(); + break; + case HALF_OPEN: + this.failureCount = failureThreshold; + this.lastFailureTime = System.nanoTime() - retryTimePeriod; + break; + default: + this.failureCount = 0; + } + } + + /** + * Executes service call. + * + * @return Value from the remote resource, stale response or a custom exception + */ + @Override + public String attemptRequest() throws RemoteServiceException { + evaluateState(); + if (state == State.OPEN) { + // return cached response if the circuit is in OPEN state + return this.lastFailureResponse; + } else { + // Make the API request if the circuit is not OPEN + try { + //In a real application, this would be run in a thread and the timeout + //parameter of the circuit breaker would be utilized to know if service + //is working. Here, we simulate that based on server response itself + var response = service.call(); + // Yay!! the API responded fine. Let's reset everything. + recordSuccess(); + return response; + } catch (RemoteServiceException ex) { + recordFailure(ex.getMessage()); + throw ex; + } + } + } +} +``` + +How does the above pattern prevent failures? Let's understand via this finite state machine +implemented by it. + +![alt text](./etc/StateDiagram.PNG "State Diagram") + +- We initialize the Circuit Breaker object with certain parameters: `timeout`, `failureThreshold` and `retryTimePeriod` which help determine how resilient the API is. +- Initially, we are in the `closed` state and nos remote calls to the API have occurred. +- Every time the call succeeds, we reset the state to as it was in the beginning. +- If the number of failures cross a certain threshold, we move to the `open` state, which acts just like an open circuit and prevents remote service calls from being made, thus saving resources. (Here, we return the response called ```stale response from API```) +- Once we exceed the retry timeout period, we move to the `half-open` state and make another call to the remote service again to check if the service is working so that we can serve fresh content. A failure sets it back to `open` state and another attempt is made after retry timeout period, while a success sets it to `closed` state so that everything starts working normally again. + +### Class diagram + +![alt text](./etc/circuit-breaker.urm.png "Circuit Breaker class diagram") + +### Applicability + +Use the Circuit Breaker pattern when + +- Building a fault-tolerant application where failure of some services shouldn't bring the entire application down. +- Building a continuously running (always-on) application, so that its components can be upgraded without shutting it down entirely. + +## Related Patterns + +- [Retry Pattern](https://github.com/iluwatar/java-design-patterns/tree/master/retry) + +## Real world examples + +* [Spring Circuit Breaker module](https://spring.io/guides/gs/circuit-breaker) +* [Netflix Hystrix API](https://github.com/Netflix/Hystrix) + +### Credits + +* [Understanding Circuit Breaker Pattern](https://itnext.io/understand-circuitbreaker-design-pattern-with-simple-practical-example-92a752615b42) +* [Martin Fowler on Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html) +* [Fault tolerance in a high volume, distributed system](https://medium.com/netflix-techblog/fault-tolerance-in-a-high-volume-distributed-system-91ab4faae74a) +* [Circuit Breaker pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/circuit-breaker) + + +## Cloud Claim Check Pattern +[⬆](#patterns) +--- +title: Claim Check Pattern +category: Cloud +language: en +tags: + - Cloud distributed + - Microservices +--- + +## Name + +[Claim Check Pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/claim-check) + +## Also known as + +[Reference-Based Messaging](https://www.enterpriseintegrationpatterns.com/patterns/messaging/StoreInLibrary.html) + +## Intent + +- Reduce the load of data transfer through the Internet. Instead of sending actual data directly, just send the message reference. +- Improve data security. As only message reference is shared, no data is exposed to the Internet. + +## Explanation + +Real-World Example + +> Suppose if you want to build a photo processing system. A photo processing system takes an image as input, processes it, and outputs a different set of images. Consider system has one persistent storage, one input component, ten processing components, messaging platform. Once a photo is given to the input component, it stores that image on persistent storage. It then creates ten different messages/events with the same image location and publishes them to the messaging platform. The messaging platform triggers ten different processing components. The ten processing components extract information about image location from the received event and then read an image from persistent storage. They generate ten different images from the original image and drop these images again to persistent storage. + +In Plain words + +> Split a large message into a claim check and a payload. Send the claim check to the messaging platform and store the payload to an external service. This pattern allows large messages to be processed while protecting the message bus and the client from being overwhelmed or slowed down. This pattern also helps to reduce costs, as storage is usually cheaper than resource units used by the messaging platform.([ref](https://docs.microsoft.com/en-us/azure/architecture/patterns/claim-check)) + +## Architecture Diagram + +![alt text](./etc/Claim-Check-Pattern.png "Claim Check Pattern") + +## Applicability + +Use the Claim Check Pattern when + +- Huge processing data causes a lot of bandwidth consumption to transfer data through the Internet. +- To secure your data transfer by storing in common persistent storage. +- Using a cloud platform - Azure Functions or AWS Lambda, Azure EventGrid or AWS Event Bridge, Azure Blob Storage or AWS S3 Bucket. +- Each service must be independent and idempotent. Output data is dropped to persistent storage by the service. +- Publish-subscribe messaging pattern needs to be used. + +## Consequences + +- This pattern is stateless. Any compute API will not store any data. +- You must have persistent storage and a reliable messaging platform. + +## Tutorials + +### Workflow + +Suppose a telecom company wants to build call cost calculator system which generate the call cost daily. At the end of each day, details of the calls made by the consumers are stored somewhere. The call calculator system will read this data and generate call cost data for each user. Consumers will be billed using this generated data in case of postpaid service. + +Producer class( `UsageDetailPublisherFunction` Azure Function) will generate call usage details (here we are generating call data in producer class itself. In real world scenario, it will read from storage). `UsageDetailPublisherFunction` creates a message. Message consists of message header and message body. Message header is basically an event grid event or claim or message reference. Message body contains actual data. `UsageDetailPublisherFunction` sends a message header to Event Grid topic `usage-detail` and drops an entire message to the blob storage. Event Grid then sent this message header to the `UsageCostProcessorFunction` Azure function. It will read the entire message from blob storage with the help of the header, will calculate call cost and drop the result to the blob storage. + +### Class Diagrams + +![alt text](./etc/class-diagram.png "Claim-Check-Class-Diagram") + +### Setup + +- Any operating system can be used macOS, Windows, Linux as everything is deployed on Azure. +- Install Java JDK 11 and set up Java environmental variables. +- Install Git. +- Install Visual Studio Code. +- Install [ Azure Functions extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-azurefunctions) to be able to deploy using Visual studio. + +### Storage Data + +The data is stored in the Azure blob storage in the container `callusageapp`. For every trigger, one GUID is created. Under the `GUID folder`, 2 files will be created `input.json` and `output.json`. +`Input.json` is dropped `producer` azure function which contains call usage details.` Output.json` contains call cost details which are dropped by the `consumer` azure function. + +## Credits + +- [Messaging Pattern - Claim Check](https://www.enterpriseintegrationpatterns.com/patterns/messaging/StoreInLibrary.html) +- [Azure Architecture Pattern - Claim Check Pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/claim-check) + +## Cloud Static Content Hosting +[⬆](#patterns) +--- +title: Static Content Hosting +category: Cloud +language: en +tags: +- Cloud distributed +--- + +## Intent + +Deploy static content to a cloud-based storage service that can deliver them directly to the client. +This can reduce the need for potentially expensive compute instances. + +## Explanation + +Real world example + +> A global marketing web site with static content needs to be quickly deployed to start attracting +> potential customers. To keep the hosting expenses and maintenance minimum, a cloud hosted storage +> service along with content delivery network is used. + +In plain words + +> Static Content Hosting pattern utilizes cloud native storage service to store the content and +> global content delivery network to cache it in multiple data centers around the world. +> +> On a static website, individual webpages include static content. They might also contain +> client-side scripts such as Javascript. By contrast, a dynamic website relies on server-side +> processing, including server-side scripts such as PHP, JSP, or ASP.NET. + +Wikipedia says + +> A static web page (sometimes called a flat page or a stationary page) is a web page that is +> delivered to the user's web browser exactly as stored, in contrast to dynamic web pages which are +> generated by a web application. +> +> Static web pages are suitable for content that never or rarely needs to be updated, though modern +> web template systems are changing this. Maintaining large numbers of static pages as files can be +> impractical without automated tools, such as static site generators. + +**Example** + +![alt text](./etc/static-content-hosting.png "Static Content Hosting") + +In this example we create a static web site using AWS S3 and utilize AWS Cloudfront to distribute +the content globally. + +1. First you will need an AWS account. You can create a free one here: [AWS Free Tier](https://aws.amazon.com/free/free-tier/) + +2. Login to the [AWS Console](https://console.aws.amazon.com/console/home?nc2=h_ct&src=header-signin) + +3. Go to Identity and Access Management (IAM) service. + +4. Create IAM user that has only the necessary rights for this application. + + * Click `Users` + * Click `Add user`. Choose `User name` as you wish and `Access type` should be `Programmatic access`. Click `Next: Permissions`. + * Choose `Attach existing policies directly`. Select `AmazonS3FullAccess` and `CloudFrontFullAccess`. Click `Next: Tags`. + * No tags are necessarily needed, so just click `Next: Review`. + * Review the presented information and if all seems good click `Create user`. + * You are presented with `Access key ID` and `Secret access key` which you will need to complete this example, so store them safely. + * Click `Close`. + +5. [Install AWS Command Line Interface (AWS CLI)](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv1.html) to gain programmic access to AWS cloud. + +6. Configure AWS CLI with command `aws configure` as desribed in the [instructions](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config) + +7. Create AWS S3 bucket for the web site content. Note that the S3 bucket names must be globally unique. + + * The syntax is `aws s3 mb ` as described in the [instructions](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-buckets-creating) + * For example `aws s3 mb s3://my-static-website-jh34jsjmg` + * Verify that the bucket was successfully created with command `aws s3 ls` which list the existing buckets + +8. Configure the bucket as a web site with command `aws s3 website` as described in the [instructions](https://docs.aws.amazon.com/cli/latest/reference/s3/website.html). + + * E.g. `aws s3 website s3://my-static-website-jh34jsjmg --index-document index.html --error-document error.html` + +9. Upload content to the bucket. + + * First create the content, at least `index.html` and `error.html` documents. + * Upload the content to your bucket as described [here](https://docs.aws.amazon.com/cli/latest/userguide/cli-services-s3-commands.html#using-s3-commands-managing-objects-copy) + * E.g. `aws s3 cp index.html s3://my-static-website-jh34jsjmg` and `aws s3 cp error.html s3://my-static-website-jh34jsjmg` + +10. Next we need to set the bucket policy to allow read access. + + * Create `policy.json` with the following contents (note that you need to replace the bucket name with your own). + + ```json + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "PublicReadGetObject", + "Effect": "Allow", + "Principal": "*", + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::my-static-website-jh34jsjmg/*" + } + ] + } + ``` + + * Set the bucket policy according to these [instructions](https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-policy.html) + * E.g. `aws s3api put-bucket-policy --bucket my-static-website-jh34jsjmg --policy file://policy.json` + +11. Test the web site in your browser. + + * The web site URL format is `http://.s3-website-.amazonaws.com` + * E.g. this web site was created in `eu-west-1` region with name `my-static-website-jh34jsjmg` so it can be accessed via url `http://my-static-website-jh34jsjmg.s3-website-eu-west-1.amazonaws.com` + +12. Create CloudFormation distribution for the web site. + + * The syntax is described in [this reference](https://docs.aws.amazon.com/cli/latest/reference/cloudfront/create-distribution.html) + * E.g. the easiest way is to call `aws cloudfront create-distribution --origin-domain-name my-static-website-jh34jsjmg.s3.amazonaws.com --default-root-object index.html` + * There's also JSON syntax e.g. `--distribution-config file://dist-config.json` to pass distribution configuration arguments in file + * The output of the call will show you the exact distribution settings including the generated CloudFront domain name you can use for testing e.g. `d2k3xwnaqa8nqx.cloudfront.net` + * CloudFormation distribution deployment takes some time, but once it's completed your web site is served from data centers all around the globe! + +13. That's it! You have implemented a static web site with content distribution network serving it lightning fast all around the world. + + * To update the web site you need to update the objects in S3 bucket and invalidate the objects in the CloudFront distribution + * To do it from AWS CLI see [this reference](https://docs.aws.amazon.com/cli/latest/reference/cloudfront/create-invalidation.html) + * Some further development you might want to do is serve the content over https and add a domain name for your site + +## Applicability + +Use the Static Content Hosting pattern when you want to: + +* Minimize the hosting cost for websites and applications that contain some static resources. +* Build a globally available web site with static content +* Monitor the web site traffic, bandwidth usage, costs etc. + +## Typical Use Case + +* Web sites with global reach +* Content produced by static web site generators +* Web sites with no dynamic content requirements + +## Real world examples + +* [Java Design Patterns web site](https://java-design-patterns.com) + +## Credits + +* [Static Content Hosting pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/static-content-hosting) + +## Collection Pipeline +[⬆](#patterns) +--- +layout: pattern +title: Collection Pipeline +folder: collection-pipeline +permalink: /patterns/collection-pipeline/ +categories: Functional +tags: + - Reactive +--- + +### Intent +Collection Pipeline introduces Function Composition and Collection Pipeline, two functional-style patterns that you can combine to iterate collections in your code. +In functional programming, it's common to sequence complex operations through a series of smaller modular functions or operations. The series is called a composition of functions, or a function composition. When a collection of data flows through a function composition, it becomes a collection pipeline. Function Composition and Collection Pipeline are two design patterns frequently used in functional-style programming. + +### Class diagram +![alt text](./etc/collection-pipeline.png "Collection Pipeline") + +### Applicability +Use the Collection Pipeline pattern when + +* When you want to perform a sequence of operations where one operation's collected output is fed into the next +* When you use a lot of statements in your code +* When you use a lot of loops in your code + +### Credits + +* [Function composition and the Collection Pipeline pattern](https://www.ibm.com/developerworks/library/j-java8idioms2/index.html) +* [Martin Fowler](https://martinfowler.com/articles/collection-pipeline/) +* [Java8 Streams](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html) + + +## Combinator +[⬆](#patterns) +--- +layout: pattern +title: Combinator +folder: combinator +permalink: /patterns/combinator/ +categories: Idiom +tags: + - Reactive +--- + +### Also known as +Composition pattern + +### Intent +The functional pattern representing a style of organizing libraries centered around the idea of combining functions. +Putting it simply, there is some type T, some functions for constructing "primitive" values of type T, +and some "combinators" which can combine values of type T in various ways to build up more complex values of type T. + +### Class diagram +![alt text](./etc/combinator.urm.png "Combinator class diagram") + +### Applicability +Use the combinator pattern when: + +- You are able to create a more complex value from more plain values but having the same type(a combination of them) + +## Real world examples + +- java.util.function.Function#compose +- java.util.function.Function#andThen + +### Credits + +- [Example for java](https://gtrefs.github.io/code/combinator-pattern/) +- [Combinator pattern](https://wiki.haskell.org/Combinator_pattern) +- [Combinatory logic](https://wiki.haskell.org/Combinatory_logic) + +## Command +[⬆](#patterns) +--- +layout: pattern +title: Command +folder: command +permalink: /patterns/command/ +categories: Behavioral +tags: + - Gang of Four +--- + +### 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 +Real world example + +> There is a wizard casting spells on a goblin. The spells are executed on the goblin one by one. +> The first spell shrinks the goblin and the second makes him invisible. Then the wizard reverses +> the spells one by one. Each spell here is a command object that can be undone. + +In plain words + +> Storing requests as command objects allows performing an action or undoing it at a later time. + +Wikipedia 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. + +**Programmatic Example** + +Here's the sample code with wizard and goblin. Let's start from the `Wizard` class. + +```java +public class Wizard { + + private final Deque undoStack = new LinkedList<>(); + private final Deque redoStack = new LinkedList<>(); + + public Wizard() {} + + public void castSpell(Runnable runnable) { + runnable.run(); + undoStack.offerLast(runnable); + } + + public void undoLastSpell() { + if (!undoStack.isEmpty()) { + var previousSpell = undoStack.pollLast(); + redoStack.offerLast(previousSpell); + previousSpell.run(); + } + } + + public void redoLastSpell() { + if (!redoStack.isEmpty()) { + var previousSpell = redoStack.pollLast(); + undoStack.offerLast(previousSpell); + previousSpell.run(); + } + } + + @Override + public String toString() { + return "Wizard"; + } +} +``` + +Next, we have the goblin who's the target of the spells. + +```java +public abstract class Target { + + private static final Logger LOGGER = LoggerFactory.getLogger(Target.class); + + private Size size; + + private Visibility visibility; + + public Size getSize() { + return size; + } + + public void setSize(Size size) { + this.size = size; + } + + public Visibility getVisibility() { + return visibility; + } + + public void setVisibility(Visibility visibility) { + this.visibility = visibility; + } + + @Override + public abstract String toString(); + + public void printStatus() { + LOGGER.info("{}, [size={}] [visibility={}]", this, getSize(), getVisibility()); + } +} + +public class Goblin extends Target { + + public Goblin() { + setSize(Size.NORMAL); + setVisibility(Visibility.VISIBLE); + } + + @Override + public String toString() { + return "Goblin"; + } + + public void changeSize() { + var oldSize = getSize() == Size.NORMAL ? Size.SMALL : Size.NORMAL; + setSize(oldSize); + } + + public void changeVisibility() { + var visible = getVisibility() == Visibility.INVISIBLE + ? Visibility.VISIBLE : Visibility.INVISIBLE; + setVisibility(visible); + } +} +``` + +Finally we have the wizard in main function who casts spell + +```java +public static void main(String[] args) { + var wizard = new Wizard(); + var goblin = new Goblin(); + + // casts shrink/unshrink spell + wizard.castSpell(goblin::changeSize); + + // casts visible/invisible spell + wizard.castSpell(goblin::changeVisibility); + + // undo and redo casts + wizard.undoLastSpell(); + wizard.redoLastSpell(); +``` + +Here's the whole example in action. + +```java +var wizard = new Wizard(); +var goblin = new Goblin(); + +goblin.printStatus(); +wizard.castSpell(goblin::changeSize); +goblin.printStatus(); + +wizard.castSpell(goblin::changeVisibility); +goblin.printStatus(); + +wizard.undoLastSpell(); +goblin.printStatus(); + +wizard.undoLastSpell(); +goblin.printStatus(); + +wizard.redoLastSpell(); +goblin.printStatus(); + +wizard.redoLastSpell(); +goblin.printStatus(); +``` + +Here's the program output: + +```java +Goblin, [size=normal] [visibility=visible] +Goblin, [size=small] [visibility=visible] +Goblin, [size=small] [visibility=invisible] +Goblin, [size=small] [visibility=visible] +Goblin, [size=normal] [visibility=visible] +Goblin, [size=small] [visibility=visible] +Goblin, [size=small] [visibility=invisible] +``` + +### Class diagram + +![alt text](./etc/command.png "Command") + +### Applicability + +Use the Command pattern when you want to: + +* Parameterize objects by an action to perform. You can express such parameterization in a +procedural language with a callback function, that is, a function that's registered somewhere to be +called at a later point. Commands are an object-oriented replacement for callbacks. +* Specify, queue, and execute requests at different times. A Command object can have a lifetime +independent of the original request. If the receiver of a request can be represented in an address +space-independent way, then you can transfer a command object for the request to a different process +and fulfill the request there. +* 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 un-execute operation that reverses the +effects of a previous call to execute. The executed commands are stored in a history list. +Unlimited-level undo and redo is achieved by traversing this list backwards and forwards calling +un-execute and execute, respectively. +* Support logging changes so that they can be reapplied in case of a system crash. By augmenting the +Command interface with load and store operations, you can keep a persistent log of changes. +Recovering from a crash involves reloading logged commands from disk and re-executing them with +the execute operation. +* Structure a system around high-level operations build on primitive operations. Such a structure is +common in information systems that support transactions. A transaction encapsulates a set of changes +to data. The Command pattern offers a way to model transactions. Commands have a common interface, +letting you invoke all transactions the same way. The pattern also makes it easy to extend the +system with new transactions. + +## Typical Use Case + +* 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) +* [org.junit.runners.model.Statement](https://github.com/junit-team/junit4/blob/master/src/main/java/org/junit/runners/model/Statement.java) +* [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](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) + +## Commander +[⬆](#patterns) +--- +layout: pattern +title: Commander +folder: commander +permalink: /patterns/commander/ +categories: Concurrency +tags: + - Cloud distributed +--- + +### Intent + +> Used to handle all problems that can be encountered when doing distributed transactions. + +### Class diagram +![alt text](./etc/commander.urm.png "Commander class diagram") + +### Applicability +This pattern can be used when we need to make commits into 2 (or more) databases to complete transaction, which cannot be done atomically and can thereby create problems. + +### Explanation +Handling distributed transactions can be tricky, but if we choose to not handle it carefully, there could be unwanted consequences. Say, we have an e-commerce website which has a Payment microservice and a Shipping microservice. If the shipping is available currently but payment service is not up, or vice versa, how would we deal with it after having already received the order from the user? +We need a mechanism in place which can handle these kinds of situations. We have to direct the order to either one of the services (in this example, shipping) and then add the order into the database of the other service (in this example, payment), since two databses cannot be updated atomically. If currently unable to do it, there should be a queue where this request can be queued, and there has to be a mechanism which allows for a failure in the queueing as well. All this needs to be done by constant retries while ensuring idempotence (even if the request is made several times, the change should only be applied once) by a commander class, to reach a state of eventual consistency. + +### Credits + +* [https://www.grahamlea.com/2016/08/distributed-transactions-microservices-icebergs/] + +## Composite +[⬆](#patterns) +--- +layout: pattern +title: Composite +folder: composite +permalink: /patterns/composite/ +categories: Structural +tags: + - Gang of Four +--- + +### Intent + +Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients +treat individual objects and compositions of objects uniformly. + +### Explanation + +Real world example + +> Every sentence is composed of words which are in turn composed of characters. Each of these +> objects is printable and they can have something printed before or after them like sentence always +> ends with full stop and word always has space before it. + +In plain words + +> Composite pattern lets clients treat the individual objects in a uniform manner. + +Wikipedia says + +> In software engineering, the composite pattern is a partitioning design pattern. The composite +> pattern describes that a group of objects is to be treated in the same way as a single instance of +> an object. The intent of a composite is to "compose" objects into tree structures to represent +> part-whole hierarchies. Implementing the composite pattern lets clients treat individual objects +> and compositions uniformly. + +**Programmatic Example** + +Taking our sentence example from above. Here we have the base class `LetterComposite` and the +different printable types `Letter`, `Word` and `Sentence`. + +```java +public abstract class LetterComposite { + + private final List children = new ArrayList<>(); + + public void add(LetterComposite letter) { + children.add(letter); + } + + public int count() { + return children.size(); + } + + protected void printThisBefore() { + } + + protected void printThisAfter() { + } + + public void print() { + printThisBefore(); + children.forEach(LetterComposite::print); + printThisAfter(); + } +} + +public class Letter extends LetterComposite { + + private final char character; + + public Letter(char c) { + this.character = c; + } + + @Override + protected void printThisBefore() { + System.out.print(character); + } +} + +public class Word extends LetterComposite { + + public Word(List letters) { + letters.forEach(this::add); + } + + public Word(char... letters) { + for (char letter : letters) { + this.add(new Letter(letter)); + } + } + + @Override + protected void printThisBefore() { + System.out.print(" "); + } +} + +public class Sentence extends LetterComposite { + + public Sentence(List words) { + words.forEach(this::add); + } + + @Override + protected void printThisAfter() { + System.out.print("."); + } +} +``` + +Then we have a messenger to carry messages: + +```java +public class Messenger { + + LetterComposite messageFromOrcs() { + + var words = List.of( + new Word('W', 'h', 'e', 'r', 'e'), + new Word('t', 'h', 'e', 'r', 'e'), + new Word('i', 's'), + new Word('a'), + new Word('w', 'h', 'i', 'p'), + new Word('t', 'h', 'e', 'r', 'e'), + new Word('i', 's'), + new Word('a'), + new Word('w', 'a', 'y') + ); + + return new Sentence(words); + + } + + LetterComposite messageFromElves() { + + var words = List.of( + new Word('M', 'u', 'c', 'h'), + new Word('w', 'i', 'n', 'd'), + new Word('p', 'o', 'u', 'r', 's'), + new Word('f', 'r', 'o', 'm'), + new Word('y', 'o', 'u', 'r'), + new Word('m', 'o', 'u', 't', 'h') + ); + + return new Sentence(words); + + } + +} +``` + +And then it can be used as: + +```java +var orcMessage = new Messenger().messageFromOrcs(); +orcMessage.print(); // Where there is a whip there is a way. +var elfMessage = new Messenger().messageFromElves(); +elfMessage.print(); // Much wind pours from your mouth. +``` + +### Class diagram + +![alt text](./etc/composite.urm.png "Composite class diagram") + +### Applicability + +Use the Composite pattern when + +* You want to represent part-whole hierarchies of objects. +* You want clients to be able to ignore the difference between compositions of objects and +individual objects. Clients will treat all objects in the composite structure uniformly. + +## Real world examples + +* [java.awt.Container](http://docs.oracle.com/javase/8/docs/api/java/awt/Container.html) and [java.awt.Component](http://docs.oracle.com/javase/8/docs/api/java/awt/Component.html) +* [Apache Wicket](https://github.com/apache/wicket) component tree, see [Component](https://github.com/apache/wicket/blob/91e154702ab1ff3481ef6cbb04c6044814b7e130/wicket-core/src/main/java/org/apache/wicket/Component.java) and [MarkupContainer](https://github.com/apache/wicket/blob/b60ec64d0b50a611a9549809c9ab216f0ffa3ae3/wicket-core/src/main/java/org/apache/wicket/MarkupContainer.java) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) + + +## Composite Entity +[⬆](#patterns) +--- +title: Composite Entity +category: Structural +language: en +tags: + - Enterprise Integration Pattern +--- + +## Intent + +It is used to model, represent, and manage a set of persistent objects that are interrelated, rather than representing them as individual fine-grained entities. + +## Explanation + +Real world example + +> For a console, there may be many interfaces that need to be managed and controlled. Using the composite entity pattern, dependent objects such as messages and signals can be combined together and controlled using a single object. + +In plain words + +> Composite entity pattern allows a set of related objects to be represented and managed by a unified object. + +**Programmatic Example** + +We need a generic solution for the problem. To achieve this, let's introduce a generic +Composite Entity Pattern. + +```java +public abstract class DependentObject { + + T data; + + public void setData(T message) { + this.data = message; + } + + public T getData() { + return data; + } +} + +public abstract class CoarseGrainedObject { + + DependentObject[] dependentObjects; + + public void setData(T... data) { + IntStream.range(0, data.length).forEach(i -> dependentObjects[i].setData(data[i])); + } + + public T[] getData() { + return (T[]) Arrays.stream(dependentObjects).map(DependentObject::getData).toArray(); + } +} + +``` + +The specialized composite entity `console` inherit from this base class as follows. + +```java +public class MessageDependentObject extends DependentObject { + +} + +public class SignalDependentObject extends DependentObject { + +} + +public class ConsoleCoarseGrainedObject extends CoarseGrainedObject { + + @Override + public String[] getData() { + super.getData(); + return new String[]{ + dependentObjects[0].getData(), dependentObjects[1].getData() + }; + } + + public void init() { + dependentObjects = new DependentObject[]{ + new MessageDependentObject(), new SignalDependentObject()}; + } +} + +public class CompositeEntity { + + private final ConsoleCoarseGrainedObject console = new ConsoleCoarseGrainedObject(); + + public void setData(String message, String signal) { + console.setData(message, signal); + } + + public String[] getData() { + return console.getData(); + } +} +``` + +Now managing the assignment of message and signal objects with the composite entity `console`. + +```java +var console = new CompositeEntity(); +console.init(); +console.setData("No Danger", "Green Light"); +Arrays.stream(console.getData()).forEach(LOGGER::info); +console.setData("Danger", "Red Light"); +Arrays.stream(console.getData()).forEach(LOGGER::info); +``` + +## Class diagram + +![alt text](./etc/composite_entity.urm.png "Composite Entity Pattern") + +## Applicability + +Use the Composite Entity Pattern in the following situation: + +* You want to manage multiple dependency objects through one object to adjust the degree of granularity between objects. At the same time, the lifetime of dependency objects depends on a coarse-grained object. +## Credits + +* [Composite Entity Pattern in wikipedia](https://en.wikipedia.org/wiki/Composite_entity_pattern) +--- + +## Composite View +[⬆](#patterns) +--- +title: Composite View +category: Structural +language: en +tags: +- Enterprise Integration Pattern +- Presentation +--- + +## Name +**Composite View** + +## Intent +The purpose of the Composite View Pattern is to increase re-usability and flexibility when creating views for websites/webapps. +This pattern seeks to decouple the content of the page from its layout, allowing changes to be made to either the content +or layout of the page without impacting the other. This pattern also allows content to be easily reused across different views easily. + +## Explanation +Real World Example +> A news site wants to display the current date and news to different users +> based on that user's preferences. The news site will substitute in different news feed +> components depending on the user's interest, defaulting to local news. + +In Plain Words +> Composite View Pattern is having a main view being composed of smaller subviews. +> The layout of this composite view is based on a template. A View-manager then decides which +> subviews to include in this template. + +Wikipedia Says +> Composite views that are composed of multiple atomic subviews. Each component of +> the template may be included dynamically into the whole and the layout of the page may be managed independently of the content. +> This solution provides for the creation of a composite view based on the inclusion and substitution of +> modular dynamic and static template fragments. +> It promotes the reuse of atomic portions of the view by encouraging modular design. + +**Programmatic Example** + +Since this is a web development pattern, a server is required to demonstrate it. +This example uses Tomcat 10.0.13 to run the servlet, and this programmatic example will only work with Tomcat 10+. + +Firstly there is `AppServlet` which is an `HttpServlet` that runs on Tomcat 10+. +```java +public class AppServlet extends HttpServlet { + private String msgPartOne = "

This Server Doesn't Support"; + private String msgPartTwo = "Requests

\n" + + "

Use a GET request with boolean values for the following parameters

\n" + + "

'name'

\n

'bus'

\n

'sports'

\n

'sci'

\n

'world'

"; + + private String destination = "newsDisplay.jsp"; + + public AppServlet() { + + } + + @Override + public void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + RequestDispatcher requestDispatcher = req.getRequestDispatcher(destination); + ClientPropertiesBean reqParams = new ClientPropertiesBean(req); + req.setAttribute("properties", reqParams); + requestDispatcher.forward(req, resp); + } + + @Override + public void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/html"); + PrintWriter out = resp.getWriter(); + out.println(msgPartOne + " Post " + msgPartTwo); + + } + + @Override + public void doDelete(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/html"); + PrintWriter out = resp.getWriter(); + out.println(msgPartOne + " Delete " + msgPartTwo); + + } + + @Override + public void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/html"); + PrintWriter out = resp.getWriter(); + out.println(msgPartOne + " Put " + msgPartTwo); + + } +} + +``` +This servlet is not part of the pattern, and simply forwards GET requests to the correct JSP. +PUT, POST, and DELETE requests are not supported and will simply show an error message. + +The view management in this example is done via a javabean class: `ClientPropertiesBean`, which stores user preferences. +```java +public class ClientPropertiesBean implements Serializable { + + private static final String WORLD_PARAM = "world"; + private static final String SCIENCE_PARAM = "sci"; + private static final String SPORTS_PARAM = "sport"; + private static final String BUSINESS_PARAM = "bus"; + private static final String NAME_PARAM = "name"; + + private static final String DEFAULT_NAME = "DEFAULT_NAME"; + private boolean worldNewsInterest; + private boolean sportsInterest; + private boolean businessInterest; + private boolean scienceNewsInterest; + private String name; + + public ClientPropertiesBean() { + worldNewsInterest = true; + sportsInterest = true; + businessInterest = true; + scienceNewsInterest = true; + name = DEFAULT_NAME; + + } + + public ClientPropertiesBean(HttpServletRequest req) { + worldNewsInterest = Boolean.parseBoolean(req.getParameter(WORLD_PARAM)); + sportsInterest = Boolean.parseBoolean(req.getParameter(SPORTS_PARAM)); + businessInterest = Boolean.parseBoolean(req.getParameter(BUSINESS_PARAM)); + scienceNewsInterest = Boolean.parseBoolean(req.getParameter(SCIENCE_PARAM)); + String tempName = req.getParameter(NAME_PARAM); + if (tempName == null || tempName == "") { + tempName = DEFAULT_NAME; + } + name = tempName; + } + // getters and setters generated by Lombok +} +``` +This javabean has a default constructor, and another that takes an `HttpServletRequest`. +This second constructor takes the request object, parses out the request parameters which contain the +user preferences for different types of news. + +The template for the news page is in `newsDisplay.jsp` +```html + + + + + + <%ClientPropertiesBean propertiesBean = (ClientPropertiesBean) request.getAttribute("properties");%> +

Welcome <%= propertiesBean.getName()%>

+ + + + + + <% if(propertiesBean.isWorldNewsInterest()) { %> + + <% } else { %> + + <% } %> + + + + <% if(propertiesBean.isBusinessInterest()) { %> + + <% } else { %> + + <% } %> + + <% if(propertiesBean.isSportsInterest()) { %> + + <% } else { %> + + <% } %> + + + + <% if(propertiesBean.isScienceNewsInterest()) { %> + + <% } else { %> + + <% } %> + + +
<%@include file="worldNews.jsp"%><%@include file="localNews.jsp"%>
<%@include file="businessNews.jsp"%><%@include file="localNews.jsp"%><%@include file="sportsNews.jsp"%><%@include file="localNews.jsp"%>
<%@include file="scienceNews.jsp"%><%@include file="localNews.jsp"%>
+ + +``` +This JSP page is the template. It declares a table with three rows, with one component in the first row, +two components in the second row, and one component in the third row. + +The scriplets in the file are part of the +view management strategy that include different atomic subviews based on the user preferences in the Javabean. + +Here are two examples of the mock atomic subviews used in the composite: +`businessNews.jsp` +```html + + + + + +

+ Generic Business News +

+ + + + + + + + + +
Stock prices up across the worldNew tech companies to invest in
Industry leaders unveil new projectPrice fluctuations and what they mean
+ + +``` +`localNews.jsp` +```html + + +
+

+ Generic Local News +

+
    +
  • + Mayoral elections coming up in 2 weeks +
  • +
  • + New parking meter rates downtown coming tomorrow +
  • +
  • + Park renovations to finish by the next year +
  • +
  • + Annual marathon sign ups available online +
  • +
+
+ + +``` +The results are as such: + +1) The user has put their name as `Tammy` in the request parameters and no preferences: +![alt text](./etc/images/noparam.png) +2) The user has put their name as `Johnny` in the request parameters and has a preference for world, business, and science news: +![alt text](./etc/images/threeparams.png) + +The different subviews such as `worldNews.jsp`, `businessNews.jsp`, etc. are included conditionally +based on the request parameters. + +**How To Use** + +To try this example, make sure you have Tomcat 10+ installed. +Set up your IDE to build a WAR file from the module and deploy that file to the server + +IntelliJ: + +Under `Run` and `edit configurations` Make sure Tomcat server is one of the run configurations. +Go to the deployment tab, and make sure there is one artifact being built called `composite-view:war exploded`. +If not present, add one. + +Ensure that the artifact is being built from the content of the `web` directory and the compilation results of the module. +Point the output of the artifact to a convenient place. Run the configuration and view the landing page, +follow instructions on that page to continue. + +## Class diagram + +![alt text](./etc/composite_view.png) + +The class diagram here displays the Javabean which is the view manager. +The views are JSP's held inside the web directory. + +## Applicability + +This pattern is applicable to most websites that require content to be displayed dynamically/conditionally. +If there are components that need to be re-used for multiple views, or if the project requires reusing a template, +or if it needs to include content depending on certain conditions, then this pattern is a good choice. + +## Known uses + +Most modern websites use composite views in some shape or form, as they have templates for views and small atomic components +that are included in the page dynamically. Most modern Javascript libraries, like React, support this design pattern +with components. + +## Consequences +**Pros** +* Easy to re-use components +* Change layout/content without affecting the other +* Reduce code duplication +* Code is more maintainable and modular + +**Cons** +* Overhead cost at runtime +* Slower response compared to directly embedding elements +* Increases potential for display errors + +## Related patterns +* [Composite (GoF)](https://java-design-patterns.com/patterns/composite/) +* [View Helper](https://www.oracle.com/java/technologies/viewhelper.html) + +## Credits +* [Core J2EE Patterns - Composite View](https://www.oracle.com/java/technologies/composite-view.html) +* [Composite View Design Pattern – Core J2EE Patterns](https://www.dineshonjava.com/composite-view-design-pattern/) + +--- + +## Converter +[⬆](#patterns) +--- +layout: pattern +title: Converter +folder: converter +permalink: /patterns/converter/ +categories: Creational +tags: + - Decoupling +--- + +### Intent + +The purpose of the Converter pattern is to provide a generic, common way of bidirectional +conversion between corresponding types, allowing a clean implementation in which the types do not +need to be aware of each other. Moreover, the Converter pattern introduces bidirectional collection +mapping, reducing a boilerplate code to minimum. + +### Explanation + +Real world example + +> In real world applications it is often the case that database layer consists of entities that need +> to be mapped into DTOs for use on the business logic layer. Similar mapping is done for +> potentially huge amount of classes and we need a generic way to achieve this. + +In plain words + +> Converter pattern makes it easy to map instances of one class into instances of another class. + +**Programmatic Example** + +We need a generic solution for the mapping problem. To achieve this, let's introduce a generic +converter. + +```java +public class Converter { + + private final Function fromDto; + private final Function fromEntity; + + public Converter(final Function fromDto, final Function fromEntity) { + this.fromDto = fromDto; + this.fromEntity = fromEntity; + } + + public final U convertFromDto(final T dto) { + return fromDto.apply(dto); + } + + public final T convertFromEntity(final U entity) { + return fromEntity.apply(entity); + } + + public final List createFromDtos(final Collection dtos) { + return dtos.stream().map(this::convertFromDto).collect(Collectors.toList()); + } + + public final List createFromEntities(final Collection entities) { + return entities.stream().map(this::convertFromEntity).collect(Collectors.toList()); + } +} +``` + +The specialized converters inherit from this base class as follows. + +```java +public class UserConverter extends Converter { + + public UserConverter() { + super(UserConverter::convertToEntity, UserConverter::convertToDto); + } + + private static UserDto convertToDto(User user) { + return new UserDto(user.getFirstName(), user.getLastName(), user.isActive(), user.getUserId()); + } + + private static User convertToEntity(UserDto dto) { + return new User(dto.getFirstName(), dto.getLastName(), dto.isActive(), dto.getEmail()); + } + +} +``` + +Now mapping between `User` and `UserDto` becomes trivial. + +```java +var userConverter = new UserConverter(); +var dtoUser = new UserDto("John", "Doe", true, "whatever[at]wherever.com"); +var user = userConverter.convertFromDto(dtoUser); +``` + +### Class diagram + +![alt text](./etc/converter.png "Converter Pattern") + +### Applicability + +Use the Converter Pattern in the following situations: + +* When you have types that logically correspond with each other and you need to convert entities +between them. +* When you want to provide different ways of types conversions depending on the context. +* Whenever you introduce a DTO (Data transfer object), you will probably need to convert it into the +domain equivalence. + +### Credits + +* [Converter](http://www.xsolve.pl/blog/converter-pattern-in-java-8/) + + +## CQRS +[⬆](#patterns) +--- +layout: pattern +title: CQRS +folder: cqrs +permalink: /patterns/cqrs/ +categories: Architectural +tags: + - Performance + - Cloud distributed +--- + +### Intent +CQRS Command Query Responsibility Segregation - Separate the query side from the command side. + +### Class diagram +![alt text](./etc/cqrs.png "CQRS") + +### Applicability +Use the CQRS pattern when + +* You want to scale the queries and commands independently. +* You want to use different data models for queries and commands. Useful when dealing with complex domains. +* You want to use architectures like event sourcing or task based UI. + +### Credits + +* [Greg Young - CQRS, Task Based UIs, Event Sourcing agh!](http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/) +* [Martin Fowler - CQRS](https://martinfowler.com/bliki/CQRS.html) +* [Oliver Wolf - CQRS for Great Good](https://www.youtube.com/watch?v=Ge53swja9Dw) +* [Command and Query Responsibility Segregation (CQRS) pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs) + + +## Data Access Object +[⬆](#patterns) +--- +layout: pattern +title: Data Access Object +folder: dao +permalink: /patterns/dao/ +categories: Architectural +tags: + - Data access +--- + +### Intent + +Object provides an abstract interface to some type of database or other persistence mechanism. + +### Explanation + +Real world example + +> There's a set of customers that need to be persisted to database. Additionally we need the whole +> set of CRUD (create/read/update/delete) operations so we can operate on customers easily. + +In plain words + +> DAO is an interface we provide over the base persistence mechanism. + +Wikipedia says + +> In computer software, a data access object (DAO) is a pattern that provides an abstract interface +> to some type of database or other persistence mechanism. + +**Programmatic Example** + +Walking through our customers example, here's the basic `Customer` entity. + +```java +public class Customer { + + private int id; + private String firstName; + private String lastName; + + public Customer(int id, String firstName, String lastName) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + } + // getters and setters -> + ... +} +``` + +Here's the `CustomerDao` interface and two different implementations for it. `InMemoryCustomerDao` +keeps a simple map of customers in memory while `DBCustomerDao` is the real RDBMS implementation. + +```java +public interface CustomerDao { + + Stream getAll() throws Exception; + + Optional getById(int id) throws Exception; + + boolean add(Customer customer) throws Exception; + + boolean update(Customer customer) throws Exception; + + boolean delete(Customer customer) throws Exception; +} + +public class InMemoryCustomerDao implements CustomerDao { + + private final Map idToCustomer = new HashMap<>(); + + // implement the interface using the map + ... +} + +public class DbCustomerDao implements CustomerDao { + + private static final Logger LOGGER = LoggerFactory.getLogger(DbCustomerDao.class); + + private final DataSource dataSource; + + public DbCustomerDao(DataSource dataSource) { + this.dataSource = dataSource; + } + + // implement the interface using the data source + ... +``` + +Finally here's how we use our DAO to manage customers. + +```java + final var dataSource = createDataSource(); + createSchema(dataSource); + final var customerDao = new DbCustomerDao(dataSource); + + addCustomers(customerDao); + log.info(ALL_CUSTOMERS); + try (var customerStream = customerDao.getAll()) { + customerStream.forEach((customer) -> log.info(customer.toString())); + } + log.info("customerDao.getCustomerById(2): " + customerDao.getById(2)); + final var customer = new Customer(4, "Dan", "Danson"); + customerDao.add(customer); + log.info(ALL_CUSTOMERS + customerDao.getAll()); + customer.setFirstName("Daniel"); + customer.setLastName("Danielson"); + customerDao.update(customer); + log.info(ALL_CUSTOMERS); + try (var customerStream = customerDao.getAll()) { + customerStream.forEach((cust) -> log.info(cust.toString())); + } + customerDao.delete(customer); + log.info(ALL_CUSTOMERS + customerDao.getAll()); + + deleteSchema(dataSource); +``` + +The program output: + +```java +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +customerDao.getCustomerById(2): Optional[Customer{id=2, firstName='Bob', lastName='Bobson'}] +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@7cef4e59 +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +Customer{id=4, firstName='Daniel', lastName='Danielson'} +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@2db0f6b2 +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +customerDao.getCustomerById(2): Optional[Customer{id=2, firstName='Bob', lastName='Bobson'}] +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@12c8a2c0 +customerDao.getAllCustomers(): +Customer{id=1, firstName='Adam', lastName='Adamson'} +Customer{id=2, firstName='Bob', lastName='Bobson'} +Customer{id=3, firstName='Carl', lastName='Carlson'} +Customer{id=4, firstName='Daniel', lastName='Danielson'} +customerDao.getAllCustomers(): java.util.stream.ReferencePipeline$Head@6ec8211c +``` + +### Class diagram + +![alt text](./etc/dao.png "Data Access Object") + +### Applicability + +Use the Data Access Object in any of the following situations: + +* When you want to consolidate how the data layer is accessed. +* When you want to avoid writing multiple data retrieval/persistence layers. + +### Credits + +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) + + +## Data Bus +[⬆](#patterns) +--- +layout: pattern +title: Data Bus +folder: data-bus +permalink: /patterns/data-bus/ + +categories: Architectural +tags: + - Decoupling +--- + +### Intent + +Allows send of messages/events between components of an application +without them needing to know about each other. They only need to know +about the type of the message/event being sent. + +### Class diagram +![data bus pattern uml diagram](./etc/data-bus.urm.png "Data Bus pattern") + +### Applicability +Use Data Bus pattern when + +* you want your components to decide themselves which messages/events they want to receive +* you want to have many-to-many communication +* you want your components to know nothing about each other + +## Related Patterns +Data Bus is similar to + +* Mediator pattern with Data Bus Members deciding for themselves if they want to accept any given message +* Observer pattern but supporting many-to-many communication +* Publish/Subscribe pattern with the Data Bus decoupling the publisher and the subscriber + +## Data Locality +[⬆](#patterns) +--- +layout: pattern +title: Data Locality +folder: data-locality +permalink: /patterns/data-locality/ +categories: Behavioral +tags: + - Game programming + - Performance +--- + +### Intent +Accelerate memory access by arranging data to take advantage of CPU caching. + +Modern CPUs have caches to speed up memory access. These can access memory adjacent to recently accessed memory much quicker. Take advantage of that to improve performance by increasing data locality keeping data in contiguous memory in the order that you process it. + +### Class diagram +![alt text](./etc/data-locality.urm.png "Data Locality pattern class diagram") + +### Applicability + +* Like most optimizations, the first guideline for using the Data Locality pattern is when you have a performance problem. +* With this pattern specifically, you’ll also want to be sure your performance problems are caused by cache misses. + +## Real world example + +* The [Artemis](http://gamadu.com/artemis/) game engine is one of the first and better-known frameworks that uses simple IDs for game entities. + +### Credits + +* [Game Programming Patterns Optimization Patterns: Data Locality](http://gameprogrammingpatterns.com/data-locality.html)--- + + +## Data Mapper +[⬆](#patterns) +--- +layout: pattern +title: Data Mapper +folder: data-mapper +permalink: /patterns/data-mapper/ +categories: Architectural +tags: + - Decoupling +--- + +### Intent +A layer of mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself + +### Class diagram +![alt text](./etc/data-mapper.png "Data Mapper") + +### Applicability +Use the Data Mapper in any of the following situations + +* when you want to decouple data objects from DB access layer +* when you want to write multiple data retrieval/persistence implementations + +### Credits + +* [Data Mapper](http://richard.jp.leguen.ca/tutoring/soen343-f2010/tutorials/implementing-data-mapper/) + +## Data Transfer Object +[⬆](#patterns) +--- +layout: pattern +title: Data Transfer Object +folder: data-transfer-object +permalink: /patterns/data-transfer-object/ +categories: Architectural +tags: + - Performance +--- + +### Intent + +Pass data with multiple attributes in one shot from client to server, to avoid multiple calls to +remote server. + +### Explanation + +Real world example + +> We need to fetch information about customers from remote database. Instead of querying the +> attributes one at a time, we use DTOs to transfer all the relevant attributes in a single shot. + +In plain words + +> Using DTO relevant information can be fetched with a single backend query. + +Wikipedia says + +> In the field of programming a data transfer object (DTO) is an object that carries data between +> processes. The motivation for its use is that communication between processes is usually done +> resorting to remote interfaces (e.g. web services), where each call is an expensive operation. +> Because the majority of the cost of each call is related to the round-trip time between the client +> and the server, one way of reducing the number of calls is to use an object (the DTO) that +> aggregates the data that would have been transferred by the several calls, but that is served by +> one call only. + +**Programmatic Example** + +Let's first introduce our simple `CustomerDTO` class. + +```java +public class CustomerDto { + private final String id; + private final String firstName; + private final String lastName; + + public CustomerDto(String id, String firstName, String lastName) { + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + } + + public String getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } +} +``` + +`CustomerResource` class acts as the server for customer information. + +```java +public class CustomerResource { + private final List customers; + + public CustomerResource(List customers) { + this.customers = customers; + } + + public List getAllCustomers() { + return customers; + } + + public void save(CustomerDto customer) { + customers.add(customer); + } + + public void delete(String customerId) { + customers.removeIf(customer -> customer.getId().equals(customerId)); + } +} +``` + +Now fetching customer information is easy since we have the DTOs. + +```java + var allCustomers = customerResource.getAllCustomers(); + allCustomers.forEach(customer -> LOGGER.info(customer.getFirstName())); + // Kelly + // Alfonso +``` + +### Class diagram + +![alt text](./etc/data-transfer-object.urm.png "data-transfer-object") + +### Applicability + +Use the Data Transfer Object pattern when: + +* The client is asking for multiple information. And the information is related. +* When you want to boost the performance to get resources. +* You want reduced number of remote calls. + +### Credits + +* [Design Pattern - Transfer Object Pattern](https://www.tutorialspoint.com/design_pattern/transfer_object_pattern.htm) +* [Data Transfer Object](https://msdn.microsoft.com/en-us/library/ff649585.aspx) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=014237a67c9d46f384b35e10151956bd) + + +## Decorator +[⬆](#patterns) +--- +layout: pattern +title: Decorator +folder: decorator +permalink: /patterns/decorator/ +categories: Structural +tags: + - Gang Of Four + - Extensibility +--- + +### Also known as + +Wrapper + +### Intent + +Attach additional responsibilities to an object dynamically. Decorators provide a flexible +alternative to subclassing for extending functionality. + +### Explanation + +Real world example + +> There is an angry troll living in the nearby hills. Usually it goes bare handed but sometimes it +> has a weapon. To arm the troll it's not necessary to create a new troll but to decorate it +> dynamically with a suitable weapon. + +In plain words + +> Decorator pattern lets you dynamically change the behavior of an object at run time by wrapping +> them in an object of a decorator class. + +Wikipedia says + +> In object-oriented programming, the decorator pattern is a design pattern that allows behavior to +> be added to an individual object, either statically or dynamically, without affecting the behavior +> of other objects from the same class. The decorator pattern is often useful for adhering to the +> Single Responsibility Principle, as it allows functionality to be divided between classes with +> unique areas of concern. + +**Programmatic Example** + +Let's take the troll example. First of all we have a `SimpleTroll` implementing the `Troll` +interface: + +```java +public interface Troll { + void attack(); + int getAttackPower(); + void fleeBattle(); +} + +public class SimpleTroll implements Troll { + + private static final Logger LOGGER = LoggerFactory.getLogger(SimpleTroll.class); + + @Override + public void attack() { + LOGGER.info("The troll tries to grab you!"); + } + + @Override + public int getAttackPower() { + return 10; + } + + @Override + public void fleeBattle() { + LOGGER.info("The troll shrieks in horror and runs away!"); + } +} +``` + +Next we want to add club for the troll. We can do it dynamically by using a decorator: + +```java +public class ClubbedTroll implements Troll { + + private static final Logger LOGGER = LoggerFactory.getLogger(ClubbedTroll.class); + + private final Troll decorated; + + public ClubbedTroll(Troll decorated) { + this.decorated = decorated; + } + + @Override + public void attack() { + decorated.attack(); + LOGGER.info("The troll swings at you with a club!"); + } + + @Override + public int getAttackPower() { + return decorated.getAttackPower() + 10; + } + + @Override + public void fleeBattle() { + decorated.fleeBattle(); + } +} +``` + +Here's the troll in action: + +```java +// simple troll +var troll = new SimpleTroll(); +troll.attack(); // The troll tries to grab you! +troll.fleeBattle(); // The troll shrieks in horror and runs away! + +// change the behavior of the simple troll by adding a decorator +var clubbedTroll = new ClubbedTroll(troll); +clubbedTroll.attack(); // The troll tries to grab you! The troll swings at you with a club! +clubbedTroll.fleeBattle(); // The troll shrieks in horror and runs away! +``` + +Program output: + +```java +The troll tries to grab you! +The troll shrieks in horror and runs away! +The troll tries to grab you! The troll swings at you with a club! +The troll shrieks in horror and runs away! +``` + +### Class diagram + +![alt text](./etc/decorator.urm.png "Decorator pattern class diagram") + +### Applicability + +Decorator is used to: + +* Add responsibilities to individual objects dynamically and transparently, that is, without +affecting other objects. +* For responsibilities that can be withdrawn. +* When extension by subclassing is impractical. Sometimes a large number of independent extensions +are possible and would produce an explosion of subclasses to support every combination. Or a class +definition may be hidden or otherwise unavailable for subclassing. + +### Tutorial + +* [Decorator Pattern Tutorial](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example) + +## Real world examples + + * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), + [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) and [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) + * [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) + * [java.util.Collections#unmodifiableXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableCollection-java.util.Collection-) + * [java.util.Collections#checkedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#checkedCollection-java.util.Collection-java.lang.Class-) + + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) + + +## Delegation +[⬆](#patterns) +--- +layout: pattern +title: Delegation +folder: delegation +permalink: /patterns/delegation/ +categories: Structural +tags: + - Decoupling +--- + +### Also known as +Proxy Pattern + +### Intent +It is a technique where an object expresses certain behavior to the outside but in +reality delegates responsibility for implementing that behaviour to an associated object. + +### Class diagram +![alt text](./etc/delegation.png "Delegate") + +### Applicability +Use the Delegate pattern in order to achieve the following + +* Reduce the coupling of methods to their class +* Components that behave identically, but realize that this situation can change in the future. + +### Credits + +* [Delegate Pattern: Wikipedia ](https://en.wikipedia.org/wiki/Delegation_pattern) +* [Proxy Pattern: Wikipedia ](https://en.wikipedia.org/wiki/Proxy_pattern) + +## Dependency Injection +[⬆](#patterns) +--- +layout: pattern +title: Dependency Injection +folder: dependency-injection +permalink: /patterns/dependency-injection/ +categories: Creational +tags: + - Decoupling +--- + +### Intent + +Dependency Injection is a software design pattern in which one or more dependencies (or services) +are injected, or passed by reference, into a dependent object (or client) and are made part of the +client's state. The pattern separates the creation of a client's dependencies from its own behavior, +which allows program designs to be loosely coupled and to follow the inversion of control and single +responsibility principles. + +### Explanation + +Real world example + +> The old wizard likes to fill his pipe and smoke tobacco once in a while. However, he doesn't want +> to depend on a single tobacco brand only but likes to be able to enjoy them all interchangeably. + +In plain words + +> Dependency Injection separates creation of client's dependencies from its own behavior. + +Wikipedia says + +> In software engineering, dependency injection is a technique in which an object receives other +> objects that it depends on. These other objects are called dependencies. + +**Programmatic Example** + +Let's first introduce the `Tobacco` interface and the concrete brands. + +```java +public abstract class Tobacco { + + private static final Logger LOGGER = LoggerFactory.getLogger(Tobacco.class); + + public void smoke(Wizard wizard) { + LOGGER.info("{} smoking {}", wizard.getClass().getSimpleName(), + this.getClass().getSimpleName()); + } +} + +public class SecondBreakfastTobacco extends Tobacco { +} + +public class RivendellTobacco extends Tobacco { +} + +public class OldTobyTobacco extends Tobacco { +} +``` + +Next here's the `Wizard` class hierarchy. + +```java +public interface Wizard { + + void smoke(); +} + +public class AdvancedWizard implements Wizard { + + private final Tobacco tobacco; + + public AdvancedWizard(Tobacco tobacco) { + this.tobacco = tobacco; + } + + @Override + public void smoke() { + tobacco.smoke(this); + } +} +``` + +And lastly we can show how easy it is to give the old wizard any brand of tobacco. + +```java + var advancedWizard = new AdvancedWizard(new SecondBreakfastTobacco()); + advancedWizard.smoke(); +``` + +### Class diagram + +![alt text](./etc/dependency-injection.png "Dependency Injection") + +### Applicability + +Use the Dependency Injection pattern when: + +* When you need to remove knowledge of concrete implementation from object. +* To enable unit testing of classes in isolation using mock objects or stubs. + +### Credits + +* [Dependency Injection Principles, Practices, and Patterns](https://www.amazon.com/gp/product/161729473X/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=161729473X&linkId=57079257a5c7d33755493802f3b884bd) +* [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.amazon.com/gp/product/0132350882/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0132350882&linkCode=as2&tag=javadesignpat-20&linkId=2c390d89cc9e61c01b9e7005c7842871) +* [Java 9 Dependency Injection: Write loosely coupled code with Spring 5 and Guice](https://www.amazon.com/gp/product/1788296257/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=1788296257&linkId=4e9137a3bf722a8b5b156cce1eec0fc1) +* [Google Guice Tutorial: Open source Java based dependency injection framework](https://www.amazon.com/gp/product/B083P7DZ8M/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=B083P7DZ8M&linkId=04f0f902c877921e45215b624a124bfe) + + +## Dirty Flag +[⬆](#patterns) +--- +layout: pattern +title: Dirty Flag +folder: dirty-flag +permalink: /patterns/dirty-flag/ +categories: Behavioral +tags: + - Game programming + - Performance +--- + +### Also known as +* IsDirty pattern + +### Intent +To avoid expensive re-acquisition of resources. The resources retain their identity, are kept in some +fast-access storage, and are re-used to avoid having to acquire them again. + +### Class diagram +![alt text](./etc/dirty-flag.png "Dirty Flag") + +### Applicability +Use the Dirty Flag pattern when + +* Repetitious acquisition, initialization, and release of the same resource causes unnecessary performance overhead. + +### Credits + +* [Design Patterns: Dirty Flag](https://www.takeupcode.com/podcast/89-design-patterns-dirty-flag/) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) + +## Double Buffer +[⬆](#patterns) +--- +layout: pattern +title: Double Buffer +folder: double-buffer +permalink: /patterns/double-buffer/ +categories: Behavioral +tags: + - Performance + - Game programming +--- + +### Intent +Double buffering is a term used to describe a device that has two buffers. The usage of multiple buffers increases the overall throughput of a device and helps prevents bottlenecks. This example shows using double buffer pattern on graphics. It is used to show one image or frame while a separate frame is being buffered to be shown next. This method makes animations and games look more realistic than the same done in a single buffer mode. + +### Class diagram +![alt text](./etc/double-buffer.urm.png "Double Buffer pattern class diagram") + +### Applicability +This pattern is one of those ones where you’ll know when you need it. If you have a system that lacks double buffering, it will probably look visibly wrong (tearing, etc.) or will behave incorrectly. But saying, “you’ll know when you need it” doesn’t give you much to go on. More specifically, this pattern is appropriate when all of these are true: + +- We have some state that is being modified incrementally. +- That same state may be accessed in the middle of modification. +- We want to prevent the code that’s accessing the state from seeing the work in progress. +- We want to be able to read the state and we don’t want to have to wait while it’s being written. + +### Credits + +* [Game Programming Patterns - Double Buffer]([http://gameprogrammingpatterns.com/double-buffer.html](http://gameprogrammingpatterns.com/double-buffer.html)) + +## Double Checked Locking +[⬆](#patterns) +--- +layout: pattern +title: Double Checked Locking +folder: double-checked-locking +permalink: /patterns/double-checked-locking/ +categories: Idiom +tags: + - Performance +--- + +### Intent +Reduce the overhead of acquiring a lock by first testing the +locking criterion (the "lock hint") without actually acquiring the lock. Only +if the locking criterion check indicates that locking is required does the +actual locking logic proceed. + +### Class diagram +![alt text](./etc/double_checked_locking_1.png "Double Checked Locking") + +### Applicability +Use the Double Checked Locking pattern when + +* there is a concurrent access in object creation, e.g. singleton, where you want to create single instance of the same class and checking if it's null or not maybe not be enough when there are two or more threads that checks if instance is null or not. +* there is a concurrent access on a method where method's behaviour changes according to the some constraints and these constraint change within this method. + +## Double Dispatch +[⬆](#patterns) +--- +layout: pattern +title: Double Dispatch +folder: double-dispatch +permalink: /patterns/double-dispatch/ +categories: Idiom +tags: + - Extensibility +--- + +### Intent +Double Dispatch pattern is a way to create maintainable dynamic +behavior based on receiver and parameter types. + +### Class diagram +![alt text](./etc/double-dispatch.png "Double Dispatch") + +### Applicability +Use the Double Dispatch pattern when + +* the dynamic behavior is not defined only based on receiving object's type but also on the receiving method's parameter type. + +## Real world examples + +* [ObjectOutputStream](https://docs.oracle.com/javase/8/docs/api/java/io/ObjectOutputStream.html) + +## EIP Aggregator +[⬆](#patterns) +--- +layout: pattern +title: EIP Aggregator +folder: eip-aggregator +permalink: /patterns/eip-aggregator/ +categories: Integration +tags: + - Enterprise Integration Pattern +--- + +### Intent +Sometimes in enterprise systems there is a need to group incoming data in order to process it as a whole. For example +you may need to gather offers and after defined number of offers has been received you would like to choose the one with +the best parameters. + +Aggregator allows you to merge messages based on defined criteria and parameters. It gathers original messages, +applies aggregation strategy and upon fulfilling given criteria, releasing merged messages. + +## Diagram +![alt text](./etc/aggregator.gif "Splitter") + +### Applicability +Use the Aggregator pattern when + +* You need to combine multiple incoming messages +* You want to process grouped data + +### Credits + +* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Aggregator.html) +* [Apache Camel - Documentation](http://camel.apache.org/aggregator2.html) +* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf) + +## EIP Message Channel +[⬆](#patterns) +--- +layout: pattern +title: EIP Message Channel +folder: eip-message-channel +permalink: /patterns/eip-message-channel/ +categories: Integration +tags: + - Enterprise Integration Pattern +--- + +### Intent +When two applications communicate using a messaging system they do it by using logical addresses +of the system, so called Message Channels. + +### Class diagram +![alt text](./etc/message-channel.png "Message Channel") + +### Applicability +Use the Message Channel pattern when + +* two or more applications need to communicate using a messaging system + +## Real world examples + +* [akka-camel](http://doc.akka.io/docs/akka/snapshot/scala/camel.html) +* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf) + + +## EIP Publish Subscribe +[⬆](#patterns) +--- +layout: pattern +title: EIP Publish Subscribe +folder: eip-publish-subscribe +permalink: /patterns/eip-publish-subscribe/ +categories: Integration +tags: + - Enterprise Integration Pattern +--- + +### Intent +Broadcast messages from sender to all the interested receivers. + +### Class diagram +![alt text](./etc/publish-subscribe.png "Publish Subscribe Channel") + +### Applicability +Use the Publish Subscribe Channel pattern when + +* two or more applications need to communicate using a messaging system for broadcasts. + +### Credits + +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf) + + +## EIP Splitter +[⬆](#patterns) +--- +layout: pattern +title: EIP Splitter +folder: eip-splitter +permalink: /patterns/eip-splitter/ +categories: Integration +tags: + - Enterprise Integration Pattern +--- + +### Intent +It is very common in integration systems that incoming messages consists of many items bundled together. For example +an invoice document contains multiple invoice lines describing transaction (quantity, name of provided +service/sold goods, price etc.). Such bundled messages may not be accepted by other systems. This is where splitter +pattern comes in handy. It will take the whole document, split it based on given criteria and send individual +items to the endpoint. + +## Diagram +![alt text](./etc/sequencer.gif "Splitter") + +### Applicability +Use the Splitter pattern when + +* You need to split received data into smaller pieces to process them individually +* You need to control the size of data batches you are able to process + +### Credits + +* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/Sequencer.html) +* [Apache Camel - Documentation](http://camel.apache.org/splitter.html) +* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf) + + +## EIP Wire Tap +[⬆](#patterns) +--- +layout: pattern +title: EIP Wire Tap +folder: eip-wire-tap +permalink: /patterns/eip-wire-tap/ +categories: Integration +tags: + - Enterprise Integration Pattern +--- + +### Intent +In most integration cases there is a need to monitor the messages flowing through the system. It is usually achieved +by intercepting the message and redirecting it to a different location like console, filesystem or the database. +It is important that such functionality should not modify the original message and influence the processing path. + +## Diagram +![alt text](./etc/wiretap.gif "Wire Tap") + +### Applicability +Use the Wire Tap pattern when + +* You need to monitor messages flowing through the system +* You need to redirect the same, unchanged message to two different endpoints/paths + +### Credits + +* [Gregor Hohpe, Bobby Woolf - Enterprise Integration Patterns](http://www.enterpriseintegrationpatterns.com/patterns/messaging/WireTap.html) +* [Apache Camel - Documentation](http://camel.apache.org/wire-tap.html) +* [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://www.amazon.com/gp/product/0321200683/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321200683&linkCode=as2&tag=javadesignpat-20&linkId=122e0cff74eedd004cc81a3ecfa623cf) + + +## Event Aggregator +[⬆](#patterns) +--- +layout: pattern +title: Event Aggregator +folder: event-aggregator +permalink: /patterns/event-aggregator/ +categories: Structural +tags: + - Reactive +--- + +### Intent +A system with lots of objects can lead to complexities when a +client wants to subscribe to events. The client has to find and register for +each object individually, if each object has multiple events then each event +requires a separate subscription. An Event Aggregator acts as a single source +of events for many objects. It registers for all the events of the many objects +allowing clients to register with just the aggregator. + +### Class diagram +![alt text](./etc/classes.png "Event Aggregator") + +### Applicability +Use the Event Aggregator pattern when + +* Event Aggregator is a good choice when you have lots of objects that are + potential event sources. Rather than have the observer deal with registering + with them all, you can centralize the registration logic to the Event + Aggregator. As well as simplifying registration, a Event Aggregator also + simplifies the memory management issues in using observers. + +### Credits + +* [Martin Fowler - Event Aggregator](http://martinfowler.com/eaaDev/EventAggregator.html) + +## Event Asynchronous +[⬆](#patterns) +--- +layout: pattern +title: Event Asynchronous +folder: event-asynchronous +permalink: /patterns/event-asynchronous/ +categories: Concurrency +tags: + - Reactive +--- + +### Intent +The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many +of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to: + +1. Perform time-consuming tasks, such as downloads and database operations, "in the background," without interrupting your application. +2. Execute multiple operations simultaneously, receiving notifications when each completes. +3. Wait for resources to become available without stopping ("hanging") your application. +4. Communicate with pending asynchronous operations using the familiar events-and-delegates model. + +### Class diagram +![alt text](./etc/event-asynchronous.png "Event-based Asynchronous") + +### Applicability +Use the Event-based Asynchronous pattern(s) when + +* Time-consuming tasks are needed to run in the background without disrupting the current application. + +### Credits + +* [Event-based Asynchronous Pattern Overview](https://msdn.microsoft.com/en-us/library/wewwczdw%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396) + +## Event Driven Architecture +[⬆](#patterns) +--- +layout: pattern +title: Event Driven Architecture +folder: event-driven-architecture +permalink: /patterns/event-driven-architecture/ +categories: Architectural +tags: + - Reactive +--- + +### Intent +Send and notify state changes of your objects to other applications using an Event-driven Architecture. + +### Class diagram +![alt text](./etc/eda.png "Event Driven Architecture") + +### Applicability +Use an Event-driven architecture when + +* you want to create a loosely coupled system +* you want to build a more responsive system +* you want a system that is easier to extend + +## Real world examples + +* SendGrid, an email API, sends events whenever an email is processed, delivered, opened etc... (https://sendgrid.com/docs/API_Reference/Webhooks/event.html) +* Chargify, a billing API, exposes payment activity through various events (https://docs.chargify.com/api-events) +* Amazon's AWS Lambda, lets you execute code in response to events such as changes to Amazon S3 buckets, updates to an Amazon DynamoDB table, or custom events generated by your applications or devices. (https://aws.amazon.com/lambda) +* MySQL runs triggers based on events such as inserts and update events happening on database tables. + +### Credits + +* [Event-driven architecture - Wikipedia](https://en.wikipedia.org/wiki/Event-driven_architecture) +* [Fundamental Components of an Event-Driven Architecture](http://giocc.com/fundamental-components-of-an-event-driven-architecture.html) +* [Real World Applications/Event Driven Applications](https://wiki.haskell.org/Real_World_Applications/Event_Driven_Applications) +* [Event-driven architecture definition](http://searchsoa.techtarget.com/definition/event-driven-architecture) + + +## Event Queue +[⬆](#patterns) +--- +layout: pattern +title: Event Queue +folder: event-queue +permalink: /patterns/event-queue/ +categories: Concurrency +tags: + - Game programming +--- + +### Intent +Event Queue is a good pattern if You have a limited accessibility resource (for example: +Audio or Database), but You need to handle all the requests that want to use that. +It puts all the requests in a queue and process them asynchronously. +Gives the resource for the event when it is the next in the queue and in same time +removes it from the queue. + +### Class diagram +![alt text](./etc/model.png "Event Queue") + +### Applicability +Use the Event Queue pattern when + +* You have a limited accessibility resource and the asynchronous process is acceptable to reach that + +### Credits + +* [Mihaly Kuprivecz - Event Queue] (http://gameprogrammingpatterns.com/event-queue.html) + + +## Event Sourcing +[⬆](#patterns) +--- +layout: pattern +title: Event Sourcing +folder: event-sourcing +permalink: /patterns/event-sourcing/ +categories: Architectural +tags: + - Performance + - Cloud distributed +--- + +### Intent +Instead of storing just the current state of the data in a domain, use an append-only store to record the full series of actions taken on that data. The store acts as the system of record and can be used to materialize the domain objects. This can simplify tasks in complex domains, by avoiding the need to synchronize the data model and the business domain, while improving performance, scalability, and responsiveness. It can also provide consistency for transactional data, and maintain full audit trails and history that can enable compensating actions. + +### Class diagram +![alt text](./etc/event-sourcing.png "Event Sourcing") + +### Applicability +Use the Event Sourcing pattern when + +* You need very high performance on persisting your application state even your application state have a complex relational data structure +* You need log of changes of your application state and ability to restore a state of any moment in time. +* You need to debug production problems by replaying the past events. + +## Real world examples + +* [The Lmax Architecture](https://martinfowler.com/articles/lmax.html) + +### Credits + +* [Martin Fowler - Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html) +* [Event Sourcing in Microsoft's documentation](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing) +* [Reference 3: Introducing Event Sourcing](https://msdn.microsoft.com/en-us/library/jj591559.aspx) +* [Event Sourcing pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/event-sourcing) + + +## Execute Around +[⬆](#patterns) +--- +layout: pattern +title: Execute Around +folder: execute-around +permalink: /patterns/execute-around/ +categories: Idiom +tags: + - Extensibility +--- + +### Intent + +Execute Around idiom frees the user from certain actions that should always be executed before and +after the business method. A good example of this is resource allocation and deallocation leaving +the user to specify only what to do with the resource. + +### Explanation + +Real world example + +> We need to provide a class that can be used to write text strings to files. To make it easy for +> the user we let our service class open and close the file automatically, the user only has to +> specify what is written into which file. + +In plain words + +> Execute Around idiom handles boilerplate code before and after business method. + +[Stack Overflow](https://stackoverflow.com/questions/341971/what-is-the-execute-around-idiom) says + +> Basically it's the pattern where you write a method to do things which are always required, e.g. +> resource allocation and clean-up, and make the caller pass in "what we want to do with the +> resource". + +**Programmatic Example** + +Let's introduce our file writer class. + +```java +@FunctionalInterface +public interface FileWriterAction { + + void writeFile(FileWriter writer) throws IOException; + +} + +public class SimpleFileWriter { + + public SimpleFileWriter(String filename, FileWriterAction action) throws IOException { + try (var writer = new FileWriter(filename)) { + action.writeFile(writer); + } + } +} +``` + +To utilize the file writer the following code is needed. + +```java + FileWriterAction writeHello = writer -> { + writer.write("Hello"); + writer.append(" "); + writer.append("there!"); + }; + new SimpleFileWriter("testfile.txt", writeHello); +``` + +### Class diagram + +![alt text](./etc/execute-around.png "Execute Around") + +### Applicability + +Use the Execute Around idiom when + +* You use an API that requires methods to be called in pairs such as open/close or +allocate/deallocate. + +### Credits + +* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) + + +## Extension Objects +[⬆](#patterns) +--- +layout: pattern +title: Extension objects +folder: extension-objects +permalink: /patterns/extension-objects/ +categories: Behavioral +tags: + - Extensibility +--- + +### Intent +Anticipate that an object’s interface needs to be extended in the future. Additional +interfaces are defined by extension objects. + +### Class diagram +![Extension_objects](./etc/extension_obj.png "Extension objects") + +### Applicability +Use the Extension Objects pattern when: + +* you need to support the addition of new or unforeseen interfaces to existing classes and you don't want to impact clients that don't need this new interface. Extension Objects lets you keep related operations together by defining them in a separate class +* a class representing a key abstraction plays different roles for different clients. The number of roles the class can play should be open-ended. There is a need to preserve the key abstraction itself. For example, a customer object is still a customer object even if different subsystems view it differently. +* a class should be extensible with new behavior without subclassing from it. + +## Real world examples + +* [OpenDoc](https://en.wikipedia.org/wiki/OpenDoc) +* [Object Linking and Embedding](https://en.wikipedia.org/wiki/Object_Linking_and_Embedding) + + +## Facade +[⬆](#patterns) +--- +layout: pattern +title: Facade +folder: facade +permalink: /patterns/facade/ +categories: Structural +tags: + - Gang Of Four + - Decoupling +--- + +### Intent + +Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level +interface that makes the subsystem easier to use. + +### Explanation + +Real world example + +> How does a goldmine work? "Well, the miners go down there and dig gold!" you say. That is what you +> believe because you are using a simple interface that goldmine provides on the outside, internally +> it has to do a lot of stuff to make it happen. This simple interface to the complex subsystem is a +> facade. + +In plain words + +> Facade pattern provides a simplified interface to a complex subsystem. + +Wikipedia says + +> A facade is an object that provides a simplified interface to a larger body of code, such as a +> class library. + +**Programmatic Example** + +Let's take our goldmine example from above. Here we have the dwarven mine worker hierarchy. First +there's a base class `DwarvenMineWorker`: + +```java +public abstract class DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenMineWorker.class); + + public void goToSleep() { + LOGGER.info("{} goes to sleep.", name()); + } + + public void wakeUp() { + LOGGER.info("{} wakes up.", name()); + } + + public void goHome() { + LOGGER.info("{} goes home.", name()); + } + + public void goToMine() { + LOGGER.info("{} goes to the mine.", name()); + } + + private void action(Action action) { + switch (action) { + case GO_TO_SLEEP: + goToSleep(); + break; + case WAKE_UP: + wakeUp(); + break; + case GO_HOME: + goHome(); + break; + case GO_TO_MINE: + goToMine(); + break; + case WORK: + work(); + break; + default: + LOGGER.info("Undefined action"); + break; + } + } + + public void action(Action... actions) { + Arrays.stream(actions).forEach(this::action); + } + + public abstract void work(); + + public abstract String name(); + + enum Action { + GO_TO_SLEEP, WAKE_UP, GO_HOME, GO_TO_MINE, WORK + } +} +``` + +Then we have the concrete dwarf classes `DwarvenTunnelDigger`, `DwarvenGoldDigger` and +`DwarvenCartOperator`: + +```java +public class DwarvenTunnelDigger extends DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenTunnelDigger.class); + + @Override + public void work() { + LOGGER.info("{} creates another promising tunnel.", name()); + } + + @Override + public String name() { + return "Dwarven tunnel digger"; + } +} + +public class DwarvenGoldDigger extends DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenGoldDigger.class); + + @Override + public void work() { + LOGGER.info("{} digs for gold.", name()); + } + + @Override + public String name() { + return "Dwarf gold digger"; + } +} + +public class DwarvenCartOperator extends DwarvenMineWorker { + + private static final Logger LOGGER = LoggerFactory.getLogger(DwarvenCartOperator.class); + + @Override + public void work() { + LOGGER.info("{} moves gold chunks out of the mine.", name()); + } + + @Override + public String name() { + return "Dwarf cart operator"; + } +} + +``` + +To operate all these goldmine workers we have the `DwarvenGoldmineFacade`: + +```java +public class DwarvenGoldmineFacade { + + private final List workers; + + public DwarvenGoldmineFacade() { + workers = List.of( + new DwarvenGoldDigger(), + new DwarvenCartOperator(), + new DwarvenTunnelDigger()); + } + + public void startNewDay() { + makeActions(workers, DwarvenMineWorker.Action.WAKE_UP, DwarvenMineWorker.Action.GO_TO_MINE); + } + + public void digOutGold() { + makeActions(workers, DwarvenMineWorker.Action.WORK); + } + + public void endDay() { + makeActions(workers, DwarvenMineWorker.Action.GO_HOME, DwarvenMineWorker.Action.GO_TO_SLEEP); + } + + private static void makeActions(Collection workers, + DwarvenMineWorker.Action... actions) { + workers.forEach(worker -> worker.action(actions)); + } +} +``` + +Now let's use the facade: + +```java +var facade = new DwarvenGoldmineFacade(); +facade.startNewDay(); +facade.digOutGold(); +facade.endDay(); +``` + +Program output: + +```java +// Dwarf gold digger wakes up. +// Dwarf gold digger goes to the mine. +// Dwarf cart operator wakes up. +// Dwarf cart operator goes to the mine. +// Dwarven tunnel digger wakes up. +// Dwarven tunnel digger goes to the mine. +// Dwarf gold digger digs for gold. +// Dwarf cart operator moves gold chunks out of the mine. +// Dwarven tunnel digger creates another promising tunnel. +// Dwarf gold digger goes home. +// Dwarf gold digger goes to sleep. +// Dwarf cart operator goes home. +// Dwarf cart operator goes to sleep. +// Dwarven tunnel digger goes home. +// Dwarven tunnel digger goes to sleep. +``` + +### Class diagram + +![alt text](./etc/facade.urm.png "Facade pattern class diagram") + +### Applicability + +Use the Facade pattern when + +* You want to provide a simple interface to a complex subsystem. Subsystems often get more complex +as they evolve. Most patterns, when applied, result in more and smaller classes. This makes the +subsystem more reusable and easier to customize, but it also becomes harder to use for clients that +don't need to customize it. A facade can provide a simple default view of the subsystem that is good +enough for most clients. Only clients needing more customization will need to look beyond the +facade. +* There are many dependencies between clients and the implementation classes of an abstraction. +Introduce a facade to decouple the subsystem from clients and other subsystems, thereby promoting +subsystem independence and portability. +* You want to layer your subsystems. Use a facade to define an entry point to each subsystem level. +If subsystems are dependent, then you can simplify the dependencies between them by making them +communicate with each other solely through their facades. + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + +## Factory +[⬆](#patterns) +--- +layout: pattern +title: Factory +folder: factory +permalink: /patterns/factory/ +categories: Creational +tags: + - Gang of Four +--- + +### Also known as + +* Simple Factory +* Static Factory Method + +### Intent + +Providing a static method encapsulated in a class called factory, in order to hide the +implementation logic and makes client code focus on usage rather then initialization new objects. + +### Explanation + +Real world example + +> Lets say we have a web application connected to SQLServer, but now we want to switch to Oracle. To +> do so without modifying existing source code, we need to implements Simple Factory pattern, in +> which a static method can be invoked to create connection to a given database. + +Wikipedia says + +> Factory is an object for creating other objects – formally a factory is a function or method that +> returns objects of a varying prototype or class. + +**Programmatic Example** + +We have an interface `Car` and two implementations `Ford` and `Ferrari`. + +```java +public interface Car { + String getDescription(); +} + +public class Ford implements Car { + + static final String DESCRIPTION = "This is Ford."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class Ferrari implements Car { + + static final String DESCRIPTION = "This is Ferrari."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} +``` + +Enumeration above represents types of cars that we support (`Ford` and `Ferrari`). + +```java +public enum CarType { + + FORD(Ford::new), + FERRARI(Ferrari::new); + + private final Supplier constructor; + + CarType(Supplier constructor) { + this.constructor = constructor; + } + + public Supplier getConstructor() { + return this.constructor; + } +} +``` +Then we have the static method `getCar` to create car objects encapsulated in the factory class +`CarsFactory`. + +```java +public class CarsFactory { + + public static Car getCar(CarType type) { + return type.getConstructor().get(); + } +} +``` + +Now on the client code we can create different types of cars using the factory class. + +```java +var car1 = CarsFactory.getCar(CarType.FORD); +var car2 = CarsFactory.getCar(CarType.FERRARI); +LOGGER.info(car1.getDescription()); +LOGGER.info(car2.getDescription()); +``` + +Program output: + +```java +This is Ford. +This Ferrari. +``` + +## Class Diagram + +![alt text](./etc/factory.urm.png "Factory pattern class diagram") + +### Applicability + +Use the Simple Factory pattern when you only care about the creation of a object, not how to create +and manage it. + +Pros + +* Allows keeping all objects creation in one place and avoid of spreading 'new' keyword across codebase. +* Allows to write loosely coupled code. Some of its main advantages include better testability, easy-to-understand code, swappable components, scalability and isolated features. + +Cons + +* The code becomes more complicated than it should be. + +## Real world examples + +* [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) +* [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) +* [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) +* [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) +* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (Returns different singleton objects, depending on a protocol) +* [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E)) +* [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) and other similar methods. + +### Related patterns + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/) +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) + + +## Factory Kit +[⬆](#patterns) +--- +layout: pattern +title: Factory Kit +folder: factory-kit +permalink: /patterns/factory-kit/ +categories: Creational +tags: + - Extensibility +--- + +### Intent +Define a factory of immutable content with separated builder and factory interfaces. + +### Class diagram +![alt text](./etc/factory-kit.png "Factory Kit") + +### Applicability +Use the Factory Kit pattern when + +* a class can't anticipate the class of objects it must create +* you just want a new instance of a custom builder instead of the global one +* you explicitly want to define types of objects, that factory can build +* you want a separated builder and creator interface + +### Credits + +* [Design Pattern Reloaded by Remi Forax: ](https://www.youtube.com/watch?v=-k2X7guaArU) + +## Factory Method +[⬆](#patterns) +--- +layout: pattern +title: Factory Method +folder: factory-method +permalink: /patterns/factory-method/ +categories: Creational +tags: + - Extensibility + - Gang Of Four +--- + +### Also known as + +Virtual Constructor + +### Intent + +Define an interface for creating an object, but let subclasses decide which class to instantiate. +Factory Method lets a class defer instantiation to subclasses. + +### Explanation + +Real world example + +> Blacksmith manufactures weapons. Elves require Elvish weapons and orcs require Orcish weapons. +> Depending on the customer at hand the right type of blacksmith is summoned. + +In plain words + +> It provides a way to delegate the instantiation logic to child classes. + +Wikipedia says + +> In class-based programming, the factory method pattern is a creational pattern that uses factory +> methods to deal with the problem of creating objects without having to specify the exact class of +> the object that will be created. This is done by creating objects by calling a factory method +> — either specified in an interface and implemented by child classes, or implemented in a base +> class and optionally overridden by derived classes—rather than by calling a constructor. + + **Programmatic Example** + +Taking our blacksmith example above. First of all we have a `Blacksmith` interface and some +implementations for it: + +```java +public interface Blacksmith { + Weapon manufactureWeapon(WeaponType weaponType); +} + +public class ElfBlacksmith implements Blacksmith { + public Weapon manufactureWeapon(WeaponType weaponType) { + return ELFARSENAL.get(weaponType); + } +} + +public class OrcBlacksmith implements Blacksmith { + public Weapon manufactureWeapon(WeaponType weaponType) { + return ORCARSENAL.get(weaponType); + } +} +``` + +When the customers come, the correct type of blacksmith is summoned and requested weapons are +manufactured: + +```java +var blacksmith = new ElfBlacksmith(); +blacksmith.manufactureWeapon(WeaponType.SPEAR); +blacksmith.manufactureWeapon(WeaponType.AXE); +``` + +Program output: +```java +// Elven spear +// Elven axe +``` + +### Class diagram + +![alt text](./etc/factory-method.urm.png "Factory Method pattern class diagram") + +### Applicability + +Use the Factory Method pattern when: + +* Class cannot anticipate the class of objects it must create. +* Class wants its subclasses to specify the objects it creates. +* Classes delegate responsibility to one of several helper subclasses, and you want to localize the +knowledge of which helper subclass is the delegate. + +## Real world examples + +* [java.util.Calendar](http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) +* [java.util.ResourceBundle](http://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) +* [java.text.NumberFormat](http://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) +* [java.nio.charset.Charset](http://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) +* [java.net.URLStreamHandlerFactory](http://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html#createURLStreamHandler-java.lang.String-) +* [java.util.EnumSet](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of-E-) +* [javax.xml.bind.JAXBContext](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) + + +## Feature Toggle +[⬆](#patterns) + + +--- +layout: pattern +title: Feature Toggle +folder: feature-toggle +permalink: /patterns/feature-toggle/ +categories: Behavioral +tags: + - Extensibility +--- + +### Also known as +Feature Flag + +### Intent +Used to switch code execution paths based on properties or groupings. Allowing new features to be released, tested +and rolled out. Allowing switching back to the older feature quickly if needed. It should be noted that this pattern, +can easily introduce code complexity. There is also cause for concern that the old feature that the toggle is eventually +going to phase out is never removed, causing redundant code smells and increased maintainability. + +### Class diagram +![alt text](./etc/feature-toggle.png "Feature Toggle") + +### Applicability +Use the Feature Toggle pattern when + +* Giving different features to different users. +* Rolling out a new feature incrementally. +* Switching between development and production environments. + +### Credits + +* [Martin Fowler 29 October 2010 (2010-10-29).](http://martinfowler.com/bliki/FeatureToggle.html) + +## Filterer +[⬆](#patterns) + + +--- +layout: pattern +title: Filterer +folder: filterer +permalink: /patterns/filterer/ +description: Design pattern that helps container-like objects to return filtered version of themselves.# short meta description that shows in Google search results +categories: + - Functional +tags: + - Extensibility +--- + +## Name / classification + +Filterer + +### Intent + +The intent of this design pattern is to introduce a functional interface that will add a +functionality for container-like objects to easily return filtered versions of themselves. + +### Explanation + +Real world example + +> We are designing a threat (malware) detection software which can analyze target systems for +> threats that are present in it. In the design we have to take into consideration that new +> Threat types can be added later. Additionally, there is a requirement that the threat detection +> system can filter the detected threats based on different criteria (the target system acts as +> container-like object for threats). + +In plain words + +> Filterer pattern is a design pattern that helps container-like objects return filtered versions +> of themselves. + +**Programmatic Example** + +To model the threat detection example presented above we introduce `Threat` and `ThreatAwareSystem` +interfaces. + +```java +public interface Threat { + String name(); + int id(); + ThreatType type(); +} + +public interface ThreatAwareSystem { + String systemId(); + List threats(); + Filterer filtered(); + +} +``` + +Notice the `filtered` method that returns instance of `Filterer` interface which is defined as: + +```java +@FunctionalInterface +public interface Filterer { + G by(Predicate predicate); +} +``` + +It is used to fulfill the requirement for system to be able to filter itself based on threat +properties. The container-like object (`ThreatAwareSystem` in our case) needs to have a method that +returns an instance of `Filterer`. This helper interface gives ability to covariantly specify a +lower bound of contravariant `Predicate` in the subinterfaces of interfaces representing the +container-like objects. + +In our example we will be able to pass a predicate that takes `? extends Threat` object and +return `? extends ThreatAwareSystem` from `Filtered::by` method. A simple implementation +of `ThreatAwareSystem`: + +```java +public class SimpleThreatAwareSystem implements ThreatAwareSystem { + + private final String systemId; + private final ImmutableList issues; + + public SimpleThreatAwareSystem(final String systemId, final List issues) { + this.systemId = systemId; + this.issues = ImmutableList.copyOf(issues); + } + + @Override + public String systemId() { + return systemId; + } + + @Override + public List threats() { + return new ArrayList<>(issues); + } + + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private ThreatAwareSystem filteredGroup(Predicate predicate) { + return new SimpleThreatAwareSystem(this.systemId, filteredItems(predicate)); + } + + private List filteredItems(Predicate predicate) { + return this.issues.stream() + .filter(predicate) + .collect(Collectors.toList()); + } +} +``` + +The `filtered` method is overridden to filter the threats list by given predicate. + +Now if we introduce a new subtype of `Threat` interface that adds probability with which given +threat can appear: + +```java +public interface ProbableThreat extends Threat { + double probability(); +} +``` + +We can also introduce a new interface that represents a system that is aware of threats with their +probabilities: + +````java +public interface ProbabilisticThreatAwareSystem extends ThreatAwareSystem { + @Override + List threats(); + + @Override + Filterer filtered(); +} +```` + +Notice how we override the `filtered` method in `ProbabilisticThreatAwareSystem` and specify +different return covariant type by specifying different generic types. Our interfaces are clean and +not cluttered by default implementations. We we will be able to filter +`ProbabilisticThreatAwareSystem` by `ProbableThreat` properties: + +```java +public class SimpleProbabilisticThreatAwareSystem implements ProbabilisticThreatAwareSystem { + + private final String systemId; + private final ImmutableList threats; + + public SimpleProbabilisticThreatAwareSystem(final String systemId, final List threats) { + this.systemId = systemId; + this.threats = ImmutableList.copyOf(threats); + } + + @Override + public String systemId() { + return systemId; + } + + @Override + public List threats() { + return threats; + } + + @Override + public Filterer filtered() { + return this::filteredGroup; + } + + private ProbabilisticThreatAwareSystem filteredGroup(final Predicate predicate) { + return new SimpleProbabilisticThreatAwareSystem(this.systemId, filteredItems(predicate)); + } + + private List filteredItems(final Predicate predicate) { + return this.threats.stream() + .filter(predicate) + .collect(Collectors.toList()); + } +} +``` + +Now if we want filter `ThreatAwareSystem` by threat type we can do: + +```java +Threat rootkit = new SimpleThreat(ThreatType.ROOTKIT, 1, "Simple-Rootkit"); +Threat trojan = new SimpleThreat(ThreatType.TROJAN, 2, "Simple-Trojan"); +List threats = List.of(rootkit, trojan); + +ThreatAwareSystem threatAwareSystem = new SimpleThreatAwareSystem("System-1", threats); + +ThreatAwareSystem rootkitThreatAwareSystem = threatAwareSystem.filtered() + .by(threat -> threat.type() == ThreatType.ROOTKIT); +``` + +Or if we want to filter `ProbabilisticThreatAwareSystem`: + +```java +ProbableThreat malwareTroyan = new SimpleProbableThreat("Troyan-ArcBomb", 1, ThreatType.TROJAN, 0.99); +ProbableThreat rootkit = new SimpleProbableThreat("Rootkit-System", 2, ThreatType.ROOTKIT, 0.8); +List probableThreats = List.of(malwareTroyan, rootkit); + +ProbabilisticThreatAwareSystem simpleProbabilisticThreatAwareSystem =new SimpleProbabilisticThreatAwareSystem("System-1", probableThreats); + +ProbabilisticThreatAwareSystem filtered = simpleProbabilisticThreatAwareSystem.filtered() + .by(probableThreat -> Double.compare(probableThreat.probability(), 0.99) == 0); +``` + +### Class diagram + +![Filterer](./etc/filterer.png "Filterer") + +### Applicability + +Pattern can be used when working with container-like objects that use subtyping, instead of +parametrizing (generics) for extensible class structure. It enables you to easily extend filtering +ability of container-like objects as business requirements change. + +### Tutorials + +* [Article about Filterer pattern posted on it's author's blog](https://blog.tlinkowski.pl/2018/filterer-pattern/) +* [Application of Filterer pattern in domain of text analysis](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) + +### Known uses + +One of the uses is present on the blog presented in +[this](https://www.javacodegeeks.com/2019/02/filterer-pattern-10-steps.html) link. It presents how +to use `Filterer` pattern to create text issue analyzer with support for test cases used for unit +testing. + +### Consequences + +Pros: + * You can easily introduce new subtypes for container-like objects and subtypes for objects that are contained within them and still be able to filter easily be new properties of those new subtypes. + +Cons: + * Covariant return types mixed with generics can be sometimes tricky + +### Credits + +* Author of the pattern : [Tomasz Linkowski](https://tlinkowski.pl/) + + +## Fluent Interface +[⬆](#patterns) + + +--- +layout: pattern +title: Fluent Interface +folder: fluentinterface +permalink: /patterns/fluentinterface/ +categories: Functional +tags: + - Reactive +--- + +### Intent + +A fluent interface provides an easy-readable, flowing interface, that often mimics a domain specific +language. Using this pattern results in code that can be read nearly as human language. + +### Explanation + +The Fluent Interface pattern is useful when you want to provide an easy readable, flowing API. Those +interfaces tend to mimic domain specific languages, so they can nearly be read as human languages. + +A fluent interface can be implemented using any of + + * Method chaining - calling a method returns some object on which further methods can be called. + * Static factory methods and imports. + * Named parameters - can be simulated in Java using static factory methods. + +Real world example + +> We need to select numbers based on different criteria from the list. It's a great chance to +> utilize fluent interface pattern to provide readable easy-to-use developer experience. + +In plain words + +> Fluent Interface pattern provides easily readable flowing interface to code. + +Wikipedia says + +> In software engineering, a fluent interface is an object-oriented API whose design relies +> extensively on method chaining. Its goal is to increase code legibility by creating a +> domain-specific language (DSL). + +**Programmatic Example** + +In this example two implementations of a `FluentIterable` interface are given. + +```java +public interface FluentIterable extends Iterable { + + FluentIterable filter(Predicate predicate); + + Optional first(); + + FluentIterable first(int count); + + Optional last(); + + FluentIterable last(int count); + + FluentIterable map(Function function); + + List asList(); + + static List copyToList(Iterable iterable) { + var copy = new ArrayList(); + iterable.forEach(copy::add); + return copy; + } +} +``` + +The `SimpleFluentIterable` evaluates eagerly and would be too costly for real world applications. + +```java +public class SimpleFluentIterable implements FluentIterable { + ... +} +``` + +The `LazyFluentIterable` is evaluated on termination. + +```java +public class LazyFluentIterable implements FluentIterable { + ... +} +``` + +Their usage is demonstrated with a simple number list that is filtered, transformed and collected. The +result is printed afterwards. + +```java + var integerList = List.of(1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68); + + prettyPrint("The initial list contains: ", integerList); + + var firstFiveNegatives = SimpleFluentIterable + .fromCopyOf(integerList) + .filter(negatives()) + .first(3) + .asList(); + prettyPrint("The first three negative values are: ", firstFiveNegatives); + + + var lastTwoPositives = SimpleFluentIterable + .fromCopyOf(integerList) + .filter(positives()) + .last(2) + .asList(); + prettyPrint("The last two positive values are: ", lastTwoPositives); + + SimpleFluentIterable + .fromCopyOf(integerList) + .filter(number -> number % 2 == 0) + .first() + .ifPresent(evenNumber -> LOGGER.info("The first even number is: {}", evenNumber)); + + + var transformedList = SimpleFluentIterable + .fromCopyOf(integerList) + .filter(negatives()) + .map(transformToString()) + .asList(); + prettyPrint("A string-mapped list of negative numbers contains: ", transformedList); + + + var lastTwoOfFirstFourStringMapped = LazyFluentIterable + .from(integerList) + .filter(positives()) + .first(4) + .last(2) + .map(number -> "String[" + valueOf(number) + "]") + .asList(); + prettyPrint("The lazy list contains the last two of the first four positive numbers " + + "mapped to Strings: ", lastTwoOfFirstFourStringMapped); + + LazyFluentIterable + .from(integerList) + .filter(negatives()) + .first(2) + .last() + .ifPresent(number -> LOGGER.info("Last amongst first two negatives: {}", number)); +``` + +Program output: + +```java +The initial list contains: 1, -61, 14, -22, 18, -87, 6, 64, -82, 26, -98, 97, 45, 23, 2, -68. +The first three negative values are: -61, -22, -87. +The last two positive values are: 23, 2. +The first even number is: 14 +A string-mapped list of negative numbers contains: String[-61], String[-22], String[-87], String[-82], String[-98], String[-68]. +The lazy list contains the last two of the first four positive numbers mapped to Strings: String[18], String[6]. +Last amongst first two negatives: -22 +``` + +### Class diagram + +![Fluent Interface](./etc/fluentinterface.png "Fluent Interface") + +### Applicability + +Use the Fluent Interface pattern when + +* You provide an API that would benefit from a DSL-like usage. +* You have objects that are difficult to configure or use. + +### Known uses + +* [Java 8 Stream API](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html) +* [Google Guava FluentIterable](https://github.com/google/guava/wiki/FunctionalExplained) +* [JOOQ](http://www.jooq.org/doc/3.0/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/) +* [Mockito](http://mockito.org/) +* [Java Hamcrest](http://code.google.com/p/hamcrest/wiki/Tutorial) + +### Credits + +* [Fluent Interface - Martin Fowler](http://www.martinfowler.com/bliki/FluentInterface.html) +* [Evolutionary architecture and emergent design: Fluent interfaces - Neal Ford](http://www.ibm.com/developerworks/library/j-eaed14/) +* [Internal DSL](http://www.infoq.com/articles/internal-dsls-java) +* [Domain Specific Languages](https://www.amazon.com/gp/product/0321712943/ref=as_li_tl?ie=UTF8&tag=javadesignpat-20&camp=1789&creative=9325&linkCode=as2&creativeASIN=0321712943&linkId=ad8351d6f5be7d8b7ecdb650731f85df) + +## Flux +[⬆](#patterns) + + +--- +layout: pattern +title: Flux +folder: flux +permalink: /patterns/flux/ +categories: Structural +tags: + - Decoupling +--- + +### Intent +Flux eschews MVC in favor of a unidirectional data flow. When a +user interacts with a view, the view propagates an action through a central +dispatcher, to the various stores that hold the application's data and business +logic, which updates all of the views that are affected. + +### Class diagram +![alt text](./etc/flux.png "Flux") + +### Applicability +Use the Flux pattern when + +* you want to focus on creating explicit and understandable update paths for your application's data, which makes tracing changes during development simpler and makes bugs easier to track down and fix. + +### Credits + +* [Flux - Application architecture for building user interfaces](http://facebook.github.io/flux/) + + +## Flyweight +[⬆](#patterns) + + +--- +layout: pattern +title: Flyweight +folder: flyweight +permalink: /patterns/flyweight/ +categories: Structural +tags: + - Gang Of Four + - Performance +--- + +### Intent + +Use sharing to support large numbers of fine-grained objects efficiently. + +### Explanation + +Real world example + +> Alchemist's shop has shelves full of magic potions. Many of the potions are the same so there is +> no need to create new object for each of them. Instead one object instance can represent multiple +> shelf items so memory footprint remains small. + +In plain words + +> It is used to minimize memory usage or computational expenses by sharing as much as possible with +> similar objects. + +Wikipedia says + +> In computer programming, flyweight is a software design pattern. A flyweight is an object that +> minimizes memory use by sharing as much data as possible with other similar objects; it is a way +> to use objects in large numbers when a simple repeated representation would use an unacceptable +> amount of memory. + +**Programmatic example** + +Translating our alchemist shop example from above. First of all we have different potion types: + +```java +public interface Potion { + void drink(); +} + +public class HealingPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(HealingPotion.class); + @Override + public void drink() { + LOGGER.info("You feel healed. (Potion={})", System.identityHashCode(this)); + } +} + +public class HolyWaterPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(HolyWaterPotion.class); + @Override + public void drink() { + LOGGER.info("You feel blessed. (Potion={})", System.identityHashCode(this)); + } +} + +public class InvisibilityPotion implements Potion { + private static final Logger LOGGER = LoggerFactory.getLogger(InvisibilityPotion.class); + @Override + public void drink() { + LOGGER.info("You become invisible. (Potion={})", System.identityHashCode(this)); + } +} +``` + +Then the actual Flyweight class `PotionFactory`, which is the factory for creating potions. + +```java +public class PotionFactory { + + private final Map potions; + + public PotionFactory() { + potions = new EnumMap<>(PotionType.class); + } + + Potion createPotion(PotionType type) { + var potion = potions.get(type); + if (potion == null) { + switch (type) { + case HEALING: + potion = new HealingPotion(); + potions.put(type, potion); + break; + case HOLY_WATER: + potion = new HolyWaterPotion(); + potions.put(type, potion); + break; + case INVISIBILITY: + potion = new InvisibilityPotion(); + potions.put(type, potion); + break; + default: + break; + } + } + return potion; + } +} +``` + +And it can be used as below: + +```java +var factory = new PotionFactory(); +factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818) +factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364) +factory.createPotion(PotionType.INVISIBILITY).drink(); // You become invisible. (Potion=6566818) +factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489) +factory.createPotion(PotionType.HOLY_WATER).drink(); // You feel blessed. (Potion=1104106489) +factory.createPotion(PotionType.HEALING).drink(); // You feel healed. (Potion=648129364) +``` + +Program output: + +```java +You become invisible. (Potion=6566818) +You feel healed. (Potion=648129364) +You become invisible. (Potion=6566818) +You feel blessed. (Potion=1104106489) +You feel blessed. (Potion=1104106489) +You feel healed. (Potion=648129364) +``` + +### Class diagram + +![alt text](./etc/flyweight.urm.png "Flyweight pattern class diagram") + +### Applicability + +The Flyweight pattern's effectiveness depends heavily on how and where it's used. Apply the +Flyweight pattern when all of the following are true: + +* An application uses a large number of objects. +* Storage costs are high because of the sheer quantity of objects. +* Most object state can be made extrinsic. +* Many groups of objects may be replaced by relatively few shared objects once extrinsic state is +removed. +* The application doesn't depend on object identity. Since flyweight objects may be shared, identity +tests will return true for conceptually distinct objects. + +## Real world examples + +* [java.lang.Integer#valueOf(int)](http://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#valueOf%28int%29) and similarly for Byte, Character and other wrapped types. + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + + +# Les patrons de conception implémentés en Java + +![Java CI with Maven](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI%20with%20Maven/badge.svg) +[![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md) +[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=ncloc)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) +[![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +[![All Contributors](https://img.shields.io/badge/all_contributors-148-orange.svg?style=flat-square)](#contributors-) + + +# Introduction + +Le patron de conception est la meilleure formatalisation qu'un programmeur +peut utiliser pour résoudre un problème lors d'une conception d'une application/system. + +Le patron de conception (design pattern) est là pour accélérer le processus de +développement en fournissant des paradigmes éprouvés. + +La réutilisation de patron de conception aide à prévenir des problèmes subtiles mais +qui sont à l'origine de problèmes majeures, comme cette pratique augmente la lisibilitée +du code par les développeurs/architectes familiers avec l'utilisation de ces concepts. + +# Commencer + +Ce site présente des modèles de conception Java. Les solutions ont été développées par des +développeurs et architectes expérimentés de la communauté open source. Les modèles peuvent être parcourus par leurs descriptions de haut niveau ou en regardant leur code source. Les exemples de code source sont bien commentés et peuvent être considérés comme tutoriels de programmation sur la façon d'implémenter un modèle spécifique. Nous utilisons le plus technologies Java open source éprouvées au combat. + +Avant de plonger dans le matériau, vous devez vous familiariser avec divers +[Principes de conception de logiciels](https://java-design-patterns.com/principles/). + +Toutes les conceptions doivent être aussi simples que possible. Vous devriez commencer par KISS, YAGNI, +et faire la chose la plus simple qui pourrait éventuellement fonctionner principes. Complexité et +les modèles ne devraient être introduits que lorsqu'ils sont nécessaires pour +extensibilité. + +Une fois que vous êtes familiarisé avec ces concepts, vous pouvez commencer à explorer +[modèles de conception disponibles](https://java-design-patterns.com/patterns/) par tout +des approches suivantes + + - Recherchez un modèle spécifique par son nom. Vous n'en trouvez pas? Veuillez signaler un nouveau modèle [ici](https://github.com/iluwatar/java-design-patterns/issues). + - Utilisation de balises telles que `Performance`, `Gang of Four` ou `Data access`. + - Utilisation des catégories de modèles, `Créatif`, `Comportemental` et autres. + +J'espère que les solutions orientées objet présentées sur ce site vous seront utiles +dans vos architectures et ayez autant de plaisir à les apprendre que nous en avons eu à les développer. + +# Comment contribuer + +Si vous souhaitez contribuer au projet, vous trouverez les informations pertinentes dans +notre [wiki développeur](https://github.com/iluwatar/java-design-patterns/wiki). Nous aiderons +vous et répondez à vos questions dans le [Gitter chatroom](https://gitter.im/iluwatar/java-design-patterns). + +# Licence + +Ce projet est concédé sous les termes de la licence MIT. + +## Front Controller +[⬆](#patterns) + + +--- +layout: pattern +title: Front Controller +folder: front-controller +permalink: /patterns/front-controller/ +categories: Structural +tags: + - Decoupling +--- + +### Intent +Introduce a common handler for all requests for a web site. This +way we can encapsulate common functionality such as security, +internationalization, routing and logging in a single place. + +### Class diagram +![alt text](./etc/front-controller.png "Front Controller") + +### Applicability +Use the Front Controller pattern when + +* you want to encapsulate common request handling functionality in single place +* you want to implements dynamic request handling i.e. change routing without modifying code +* make web server configuration portable, you only need to register the handler web server specific way + +## Real world examples + +* [Apache Struts](https://struts.apache.org/) + +### Credits + +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Presentation Tier Patterns](http://www.javagyan.com/tutorials/corej2eepatterns/presentation-tier-patterns) +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) + +## Game Loop +[⬆](#patterns) +--- +layout: pattern +title: Game Loop +folder: game-loop +permalink: /patterns/game-loop/ +categories: Behavioral +tags: + - Game programming +--- + +### Intent + +A game loop runs continuously during gameplay. Each turn of the loop, it processes user input +without blocking, updates the game state, and renders the game. It tracks the passage of time to +control the rate of gameplay. + +This pattern decouples progression of game time from user input and processor speed. + +### Applicability + +This pattern is used in every game engine. + +### Explanation + +Real world example + +> Game loop is the main process of all the game rendering threads. It's present in all modern games. +> It drives input process, internal status update, rendering, AI and all the other processes. + +In plain words + +> Game Loop pattern ensures that game time progresses in equal speed in all different hardware +> setups. + +Wikipedia says + +> The central component of any game, from a programming standpoint, is the game loop. The game loop +> allows the game to run smoothly regardless of a user's input, or lack thereof. + +**Programmatic Example** + +Let's start with something simple. Here's `Bullet` class. Bullets will move in our game. For +demonstration purposes it's enough that it has 1-dimensional position. + +```java +public class Bullet { + + private float position; + + public Bullet() { + position = 0.0f; + } + + public float getPosition() { + return position; + } + + public void setPosition(float position) { + this.position = position; + } +} +``` + +`GameController` is responsible for moving objects in the game, including the aforementioned bullet. + +```java +public class GameController { + + protected final Bullet bullet; + + public GameController() { + bullet = new Bullet(); + } + + public void moveBullet(float offset) { + var currentPosition = bullet.getPosition(); + bullet.setPosition(currentPosition + offset); + } + + public float getBulletPosition() { + return bullet.getPosition(); + } +} +``` + +Now we introduce the game loop. Or actually in this demo we have 3 different game loops. Let's see +the base class `GameLoop` first. + +```java +public enum GameStatus { + + RUNNING, STOPPED +} + +public abstract class GameLoop { + + protected final Logger logger = LoggerFactory.getLogger(this.getClass()); + + protected volatile GameStatus status; + + protected GameController controller; + + private Thread gameThread; + + public GameLoop() { + controller = new GameController(); + status = GameStatus.STOPPED; + } + + public void run() { + status = GameStatus.RUNNING; + gameThread = new Thread(this::processGameLoop); + gameThread.start(); + } + + public void stop() { + status = GameStatus.STOPPED; + } + + public boolean isGameRunning() { + return status == GameStatus.RUNNING; + } + + protected void processInput() { + try { + var lag = new Random().nextInt(200) + 50; + Thread.sleep(lag); + } catch (InterruptedException e) { + logger.error(e.getMessage()); + } + } + + protected void render() { + var position = controller.getBulletPosition(); + logger.info("Current bullet position: " + position); + } + + protected abstract void processGameLoop(); +} +``` + +Here's the first game loop implementation, `FrameBasedGameLoop`: + +```java +public class FrameBasedGameLoop extends GameLoop { + + @Override + protected void processGameLoop() { + while (isGameRunning()) { + processInput(); + update(); + render(); + } + } + + protected void update() { + controller.moveBullet(0.5f); + } +} +``` + +Finally, we show all the game loops in action. + +```java + try { + LOGGER.info("Start frame-based game loop:"); + var frameBasedGameLoop = new FrameBasedGameLoop(); + frameBasedGameLoop.run(); + Thread.sleep(GAME_LOOP_DURATION_TIME); + frameBasedGameLoop.stop(); + LOGGER.info("Stop frame-based game loop."); + + LOGGER.info("Start variable-step game loop:"); + var variableStepGameLoop = new VariableStepGameLoop(); + variableStepGameLoop.run(); + Thread.sleep(GAME_LOOP_DURATION_TIME); + variableStepGameLoop.stop(); + LOGGER.info("Stop variable-step game loop."); + + LOGGER.info("Start fixed-step game loop:"); + var fixedStepGameLoop = new FixedStepGameLoop(); + fixedStepGameLoop.run(); + Thread.sleep(GAME_LOOP_DURATION_TIME); + fixedStepGameLoop.stop(); + LOGGER.info("Stop variable-step game loop."); + + } catch (InterruptedException e) { + LOGGER.error(e.getMessage()); + } +``` + +Program output: + +```java +Start frame-based game loop: +Current bullet position: 0.5 +Current bullet position: 1.0 +Current bullet position: 1.5 +Current bullet position: 2.0 +Current bullet position: 2.5 +Current bullet position: 3.0 +Current bullet position: 3.5 +Current bullet position: 4.0 +Current bullet position: 4.5 +Current bullet position: 5.0 +Current bullet position: 5.5 +Current bullet position: 6.0 +Stop frame-based game loop. +Start variable-step game loop: +Current bullet position: 6.5 +Current bullet position: 0.038 +Current bullet position: 0.084 +Current bullet position: 0.145 +Current bullet position: 0.1805 +Current bullet position: 0.28 +Current bullet position: 0.32 +Current bullet position: 0.42549998 +Current bullet position: 0.52849996 +Current bullet position: 0.57799995 +Current bullet position: 0.63199997 +Current bullet position: 0.672 +Current bullet position: 0.778 +Current bullet position: 0.848 +Current bullet position: 0.8955 +Current bullet position: 0.9635 +Stop variable-step game loop. +Start fixed-step game loop: +Current bullet position: 0.0 +Current bullet position: 1.086 +Current bullet position: 0.059999995 +Current bullet position: 0.12999998 +Current bullet position: 0.24000004 +Current bullet position: 0.33999994 +Current bullet position: 0.36999992 +Current bullet position: 0.43999985 +Current bullet position: 0.5399998 +Current bullet position: 0.65999967 +Current bullet position: 0.68999964 +Current bullet position: 0.7299996 +Current bullet position: 0.79999954 +Current bullet position: 0.89999944 +Current bullet position: 0.98999935 +Stop variable-step game loop. +``` + +### Class diagram + +![alt text](./etc/game-loop.urm.png "Game Loop pattern class diagram") + +### Credits + +* [Game Programming Patterns - Game Loop](http://gameprogrammingpatterns.com/game-loop.html) +* [Game Programming Patterns](https://www.amazon.com/gp/product/0990582906/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0990582906&linkId=1289749a703b3fe0e24cd8d604d7c40b) +* [Game Engine Architecture, Third Edition](https://www.amazon.com/gp/product/1138035459/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1138035459&linkId=94502746617211bc40e0ef49d29333ac) + +## Guarded Suspension +[⬆](#patterns) +--- +layout: pattern +title: Guarded Suspension +folder: guarded-suspension +permalink: /patterns/guarded-suspension/ +categories: Concurrency +tags: + - Decoupling +--- + +### Intent +Use Guarded suspension pattern to handle a situation when you want to execute a method on object which is not in a proper state. + +### Class diagram +![Guarded Suspension diagram](./etc/guarded-suspension.png) + +### Applicability +Use Guarded Suspension pattern when the developer knows that the method execution will be blocked for a finite period of time + +### Related patterns + +* Balking + + +## Half Sync/Half Async +[⬆](#patterns) +--- +layout: pattern +title: Half-Sync/Half-Async +folder: half-sync-half-async +permalink: /patterns/half-sync-half-async/ +categories: Concurrency +tags: + - Performance +--- + +### Intent +The Half-Sync/Half-Async pattern decouples synchronous I/O from +asynchronous I/O in a system to simplify concurrent programming effort without +degrading execution efficiency. + +### Class diagram +![Half-Sync/Half-Async class diagram](./etc/half-sync-half-async.png) + +### Applicability +Use Half-Sync/Half-Async pattern when + +* a system possesses following characteristics: + * the system must perform tasks in response to external events that occur asynchronously, like hardware interrupts in OS + * it is inefficient to dedicate separate thread of control to perform synchronous I/O for each external source of event + * the higher level tasks in the system can be simplified significantly if I/O is performed synchronously. +* one or more tasks in a system must run in a single thread of control, while other tasks may benefit from multi-threading. + +## Real world examples + +* [BSD Unix networking subsystem](https://www.dre.vanderbilt.edu/~schmidt/PDF/PLoP-95.pdf) +* [Real Time CORBA](http://www.omg.org/news/meetings/workshops/presentations/realtime2001/4-3_Pyarali_thread-pool.pdf) +* [Android AsyncTask framework](http://developer.android.com/reference/android/os/AsyncTask.html) + +### Credits + +* [Douglas C. Schmidt and Charles D. Cranor - Half Sync/Half Async](https://www.dre.vanderbilt.edu/~schmidt/PDF/PLoP-95.pdf) +* [Pattern Oriented Software Architecture Volume 2: Patterns for Concurrent and Networked Objects](https://www.amazon.com/gp/product/0471606952/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0471606952&linkCode=as2&tag=javadesignpat-20&linkId=889e4af72dca8261129bf14935e0f8dc) + +## Hexagonal Architecture +[⬆](#patterns) +--- +layout: pattern +title: Hexagonal Architecture +folder: hexagonal +permalink: /patterns/hexagonal/ +pumlformat: svg +categories: Architectural +tags: + - Decoupling +--- + +### Also known as + +* Ports and Adapters +* Clean Architecture +* Onion Architecture + +### Intent +Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases. + +### Class diagram +![Hexagonal Architecture class diagram](./etc/hexagonal.png) + +### Applicability +Use Hexagonal Architecture pattern when + +* When the application needs to be independent of any frameworks +* When it is important that the application highly maintainable and fully testable + +### Tutorials + +* [Build Maintainable Systems With Hexagonal Architecture](http://java-design-patterns.com/blog/build-maintainable-systems-with-hexagonal-architecture/) + +## Real world examples + +* [Apache Isis](https://isis.apache.org/) builds generic UI and REST API directly from the underlying domain objects + +### Credits + +* [Alistair Cockburn - Hexagonal Architecture](http://alistair.cockburn.us/Hexagonal+architecture) + +## Intercepting Filter +[⬆](#patterns) +--- +layout: pattern +title: Intercepting Filter +folder: intercepting-filter +permalink: /patterns/intercepting-filter/ +categories: Behavioral +tags: + - Decoupling +--- + +### Intent +Provide pluggable filters to conduct necessary pre-processing and +post-processing to requests from a client to a target + +### Class diagram +![alt text](./etc/intercepting-filter.png "Intercepting Filter") + +### Applicability +Use the Intercepting Filter pattern when + +* a system uses pre-processing or post-processing requests +* a system should do the authentication/ authorization/ logging or tracking of request and then pass the requests to corresponding handlers +* you want a modular approach to configuring pre-processing and post-processing schemes + +### Tutorials + +* [Introduction to Intercepting Filter Pattern in Java](https://www.baeldung.com/intercepting-filter-pattern-in-java) + +## Real world examples + +* [javax.servlet.FilterChain](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/FilterChain.html) and [javax.servlet.Filter](https://tomcat.apache.org/tomcat-8.0-doc/servletapi/javax/servlet/Filter.html) +* [Struts 2 - Interceptors](https://struts.apache.org/core-developers/interceptors.html) + +### Credits + +* [TutorialsPoint - Intercepting Filter](http://www.tutorialspoint.com/design_pattern/intercepting_filter_pattern.htm) + +## Interpreter +[⬆](#patterns) +--- +layout: pattern +title: Interpreter +folder: interpreter +permalink: /patterns/interpreter/ +categories: Behavioral +tags: + - Gang of Four +--- + +### Intent +Given a language, define a representation for its grammar along +with an interpreter that uses the representation to interpret sentences in the +language. + +### Class diagram +![alt text](./etc/interpreter_1.png "Interpreter") + +### Applicability +Use the Interpreter pattern when there is a language to +interpret, and you can represent statements in the language as abstract syntax +trees. The Interpreter pattern works best when + +* the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable. Tools such as parser generators are a better alternative in such cases. They can interpret expressions without building abstract syntax trees, which can save space and possibly time +* efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting parse trees directly but by first translating them into another form. For example, regular expressions are often transformed into state machines. But even then, the translator can be implemented by the Interpreter pattern, so the pattern is still applicable + +## Real world examples + +* [java.util.Pattern](http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) +* [java.text.Normalizer](http://docs.oracle.com/javase/8/docs/api/java/text/Normalizer.html) +* All subclasses of [java.text.Format](http://docs.oracle.com/javase/8/docs/api/java/text/Format.html) +* [javax.el.ELResolver](http://docs.oracle.com/javaee/7/api/javax/el/ELResolver.html) + + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) + +## Iterator +[⬆](#patterns) +--- +layout: pattern +title: Iterator +folder: iterator +permalink: /patterns/iterator/ +categories: Behavioral +tags: + - Gang of Four +--- + +### Also known as + +Cursor + +### Intent +Provide a way to access the elements of an aggregate object sequentially without exposing its +underlying representation. + +### Explanation + +Real world example + +> Treasure chest contains a set of magical items. There multiple types of items such as rings, +> potions and weapons. The items can be browsed by type using an iterator the treasure chest +> provides. + +In plain words + +> Containers can provide a representation agnostic iterator interface to provide access to the +> elements. + +Wikipedia says + +> In object-oriented programming, the iterator pattern is a design pattern in which an iterator is +> used to traverse a container and access the container's elements. + +**Programmatic Example** + +The main class in our example is the `TreasureChest` that contains items. + +```java +public class TreasureChest { + + private final List items; + + public TreasureChest() { + items = List.of( + new Item(ItemType.POTION, "Potion of courage"), + new Item(ItemType.RING, "Ring of shadows"), + new Item(ItemType.POTION, "Potion of wisdom"), + new Item(ItemType.POTION, "Potion of blood"), + new Item(ItemType.WEAPON, "Sword of silver +1"), + new Item(ItemType.POTION, "Potion of rust"), + new Item(ItemType.POTION, "Potion of healing"), + new Item(ItemType.RING, "Ring of armor"), + new Item(ItemType.WEAPON, "Steel halberd"), + new Item(ItemType.WEAPON, "Dagger of poison")); + } + + public Iterator iterator(ItemType itemType) { + return new TreasureChestItemIterator(this, itemType); + } + + public List getItems() { + return new ArrayList<>(items); + } +} +``` + +Here's the `Item` class: + +```java +public class Item { + + private ItemType type; + private final String name; + + public Item(ItemType type, String name) { + this.setType(type); + this.name = name; + } + + @Override + public String toString() { + return name; + } + + public ItemType getType() { + return type; + } + + public final void setType(ItemType type) { + this.type = type; + } +} + +public enum ItemType { + + ANY, WEAPON, RING, POTION + +} +``` + +The `Iterator` interface is extremely simple. + +```java +public interface Iterator { + + boolean hasNext(); + + T next(); +} +``` + +In the following example we iterate through the ring type items found in the chest. + +```java +var itemIterator = TREASURE_CHEST.iterator(ItemType.RING); +while (itemIterator.hasNext()) { + LOGGER.info(itemIterator.next().toString()); +} +``` + +Program output: + +```java +Ring of shadows +Ring of armor +``` + +### Class diagram + +![alt text](./etc/iterator_1.png "Iterator") + +### Applicability + +Use the Iterator pattern + +* To access an aggregate object's contents without exposing its internal representation. +* To support multiple traversals of aggregate objects. +* To provide a uniform interface for traversing different aggregate structures. + +### Tutorials + +* [How to Use Iterator?](http://www.tutorialspoint.com/java/java_using_iterator.htm) + +## Real world examples + +* [java.util.Iterator](http://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html) +* [java.util.Enumeration](http://docs.oracle.com/javase/8/docs/api/java/util/Enumeration.html) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + + +# 자바로 구현된 디자인 패턴 + +![Java CI with Maven](https://github.com/iluwatar/java-design-patterns/workflows/Java%20CI%20with%20Maven/badge.svg)[](https://raw.githubusercontent.com/iluwatar/java-design-patterns/master/LICENSE.md)![License MIT](https://img.shields.io/badge/license-MIT-blue.svg)[](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns)![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg) + + +## Layers +[⬆](#patterns) +--- +layout: pattern +title: Layers +folder: layers +permalink: /patterns/layers/ +pumlformat: svg +categories: Architectural +tags: + - Decoupling +--- + +### Intent + +Layers is an architectural pattern where software responsibilities are divided among the different +layers of the application. + +### Explanation + +Real world example + +> Consider a web site displaying decorated cakes for weddings and such. Instead of the web page +> directly reaching into the database, it relies on a service to deliver this information. The +> service then queries the data layer to assimilate the needed information. + +In plain words + +> With Layers architectural pattern different concerns reside on separate layers. View layer is +> interested only in rendering, service layer assembles the requested data from various sources, and +> data layer gets the bits from the data storage. + +Wikipedia says + +> In software engineering, multitier architecture (often referred to as n-tier architecture) or +> multilayered architecture is a client–server architecture in which presentation, application +> processing, and data management functions are physically separated. + +**Programmatic Example** + +On the data layer, we keep our cake building blocks. `Cake` consist of layers and topping. + +```java +@Entity +public class Cake { + + @Id + @GeneratedValue + private Long id; + + @OneToOne(cascade = CascadeType.REMOVE) + private CakeTopping topping; + + @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.EAGER) + private Set layers; +} +``` + +The service layer offers `CakeBakingService` for easy access to different aspects of cakes. + +```java +public interface CakeBakingService { + + void bakeNewCake(CakeInfo cakeInfo) throws CakeBakingException; + + List getAllCakes(); + + void saveNewTopping(CakeToppingInfo toppingInfo); + + List getAvailableToppings(); + + void saveNewLayer(CakeLayerInfo layerInfo); + + List getAvailableLayers(); +} +``` + +On the top we have our `View` responsible of rendering the cakes. + +```java +public interface View { + + void render(); + +} + +public class CakeViewImpl implements View { + + private static final Logger LOGGER = LoggerFactory.getLogger(CakeViewImpl.class); + + private final CakeBakingService cakeBakingService; + + public CakeViewImpl(CakeBakingService cakeBakingService) { + this.cakeBakingService = cakeBakingService; + } + + public void render() { + cakeBakingService.getAllCakes().forEach(cake -> LOGGER.info(cake.toString())); + } +} +``` + +### Class diagram + +![alt text](./etc/layers.png "Layers") + +### Applicability + +Use the Layers architecture when + +* You want clearly divide software responsibilities into different parts of the program. +* You want to prevent a change from propagating throughout the application. +* You want to make your application more maintainable and testable. + +### Credits + +* [Pattern Oriented Software Architecture Volume 1: A System of Patterns](https://www.amazon.com/gp/product/0471958697/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0471958697&linkCode=as2&tag=javadesignpat-20&linkId=e3f42d7a2a4cc8c619bbc0136b20dadb) + +## Lazy Loading +[⬆](#patterns) +--- +layout: pattern +title: Lazy Loading +folder: lazy-loading +permalink: /patterns/lazy-loading/ +categories: Idiom +tags: + - Performance +--- + +### Intent +Lazy loading is a design pattern commonly used to defer +initialization of an object until the point at which it is needed. It can +contribute to efficiency in the program's operation if properly and +appropriately used. + +### Class diagram +![alt text](./etc/lazy-loading.png "Lazy Loading") + +### Applicability +Use the Lazy Loading idiom when + +* eager loading is expensive or the object to be loaded might not be needed at all + +## Real world examples + +* JPA annotations @OneToOne, @OneToMany, @ManyToOne, @ManyToMany and fetch = FetchType.LAZY + +### Credits + +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a) + +## Leader Election +[⬆](#patterns) +--- +layout: pattern +title: Leader Election +folder: leader-election +permalink: /patterns/leader-election/ +categories: Behavioral +tags: + - Cloud distributed +--- + +### Intent +Leader Election pattern is commonly used in cloud system design. It can help to ensure that task instances select the leader instance correctly and do not conflict with each other, cause contention for shared resources, or inadvertently interfere with the work that other task instances are performing. + +### Class diagram +![alt text](./etc/leader-election.urm.png "Leader Election pattern class diagram") + +### Applicability +Use this pattern when + +* the tasks in a distributed application, such as a cloud-hosted solution, require careful coordination and there is no natural leader. + +Do not use this pattern when + +* there is a natural leader or dedicated process that can always act as the leader. For example, it may be possible to implement a singleton process that coordinates the task instances. If this process fails or becomes unhealthy, the system can shut it down and restart it. +* the coordination between tasks can be easily achieved by using a more lightweight mechanism. For example, if several task instances simply require coordinated access to a shared resource, a preferable solution might be to use optimistic or pessimistic locking to control access to that resource. + +## Real world examples + +* [Raft Leader Election](https://github.com/ronenhamias/raft-leader-election) + +### Credits + +* [Leader Election pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/leader-election) + +## Leader Followers +[⬆](#patterns) +--- +layout: pattern +title: Leader/Followers +folder: leader-followers +permalink: /patterns/leader-followers/ +categories: Concurrency +tags: + - Performance +--- + +### Intent +The Leader/Followers pattern provides a concurrency model where multiple +threads can efficiently de-multiplex events and dispatch event handlers +that process I/O handles shared by the threads. + +### Class diagram +![Leader/Followers class diagram](./etc/leader-followers.png) + +### Applicability +Use Leader-Followers pattern when + +* multiple threads take turns sharing a set of event sources in order to detect, de-multiplex, dispatch and process service requests that occur on the event sources. + +## Real world examples + +* [ACE Thread Pool Reactor framework](https://www.dre.vanderbilt.edu/~schmidt/PDF/HPL.pdf) +* [JAWS](http://www.dre.vanderbilt.edu/~schmidt/PDF/PDCP.pdf) +* [Real-time CORBA](http://www.dre.vanderbilt.edu/~schmidt/PDF/RTS.pdf) + +### Credits + +* [Douglas C. Schmidt and Carlos O’Ryan - Leader/Followers](http://www.kircher-schwanninger.de/michael/publications/lf.pdf) + +## Marker Interface +[⬆](#patterns) +--- +layout: pattern +title: Marker Interface +folder: marker +permalink: /patterns/marker/ +categories: Structural +tags: + - Decoupling +--- + +### Intent +Using empty interfaces as markers to distinguish special treated objects. + +### Class diagram +![alt text](./etc/MarkerDiagram.png "Marker Interface") + +### Applicability +Use the Marker Interface pattern when + +* you want to identify the special objects from normal objects (to treat them differently) +* you want to mark that some object is available for certain sort of operations + +## Real world examples + +* [javase.8.docs.api.java.io.Serializable](https://docs.oracle.com/javase/8/docs/api/java/io/Serializable.html) +* [javase.8.docs.api.java.lang.Cloneable](https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html) + +### Credits + +* [Effective Java](https://www.amazon.com/gp/product/0134685997/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0134685997&linkCode=as2&tag=javadesignpat-20&linkId=4e349f4b3ff8c50123f8147c828e53eb) + +## Master Worker +[⬆](#patterns) +--- +layout: pattern +title: Master-Worker +folder: master-worker-pattern +permalink: /patterns/master-worker-pattern/ +categories: Concurrency +tags: + - Performance +--- + +### Also known as + +> Master-slave or Map-reduce + +### Intent + +> Used for centralised parallel processing. + +### Class diagram +![alt text](./etc/master-worker-pattern.urm.png "Master-Worker pattern class diagram") + +### Applicability +This pattern can be used when data can be divided into multiple parts, all of which need to go through the same computation to give a result, which need to be aggregated to get the final result. + +### Explanation +In this pattern, parallel processing is performed using a system consisting of a master and some number of workers, where a master divides the work among the workers, gets the result back from them and assimilates all the results to give final result. The only communication is between the master and the worker - none of the workers communicate among one another and the user only communicates with the master to get the required job done. The master has to maintain a record of how the divided data has been distributed, how many workers have finished their work and returned a result, and the results themselves to be able to aggregate the data correctly. + +### Credits + +* [https://docs.gigaspaces.com/sbp/master-worker-pattern.html] +* [http://www.cs.sjsu.edu/~pearce/oom/patterns/behavioral/masterslave.htm] + +## Mediator +[⬆](#patterns) +--- +layout: pattern +title: Mediator +folder: mediator +permalink: /patterns/mediator/ +categories: Behavioral +tags: + - Gang Of Four + - Decoupling +--- + +### Intent +Define an object that encapsulates how a set of objects interact. +Mediator promotes loose coupling by keeping objects from referring to each +other explicitly, and it lets you vary their interaction independently. + +### Class diagram +![alt text](./etc/mediator_1.png "Mediator") + +### Applicability +Use the Mediator pattern when + +* a set of objects communicate in well-defined but complex ways. The resulting interdependencies are unstructured and difficult to understand +* reusing an object is difficult because it refers to and communicates with many other objects +* a behavior that's distributed between several classes should be customizable without a lot of subclassing + +## Real world examples + +* All scheduleXXX() methods of [java.util.Timer](http://docs.oracle.com/javase/8/docs/api/java/util/Timer.html) +* [java.util.concurrent.Executor#execute()](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Executor.html#execute-java.lang.Runnable-) +* submit() and invokeXXX() methods of [java.util.concurrent.ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html) +* scheduleXXX() methods of [java.util.concurrent.ScheduledExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html) +* [java.lang.reflect.Method#invoke()](http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html#invoke-java.lang.Object-java.lang.Object...-) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + +## Memento +[⬆](#patterns) +--- +layout: pattern +title: Memento +folder: memento +permalink: /patterns/memento/ +categories: Behavioral +tags: + - Gang of Four +--- + +### Also known as + +Token + +### Intent + +Without violating encapsulation, capture and externalize an object's internal state so that the +object can be restored to this state later. + +### Explanation + +Real world example + +> We are working on astrology application where we need to analyze star properties over time. We are +> creating snapshots of star state using Memento pattern. + +In plain words + +> Memento pattern captures object internal state making it easy to store and restore objects in any +> point of time. + +Wikipedia says + +> The memento pattern is a software design pattern that provides the ability to restore an object to +> its previous state (undo via rollback). + +**Programmatic Example** + +Let's first define the types of stars we are capable to handle. + +```java +public enum StarType { + SUN("sun"), + RED_GIANT("red giant"), + WHITE_DWARF("white dwarf"), + SUPERNOVA("supernova"), + DEAD("dead star"); + ... +} +``` + +Next, let's jump straight to the essentials. Here's the `Star` class along with the mementos that we +need manipulate. Especially pay attention to `getMemento` and `setMemento` methods. + +```java +public interface StarMemento { +} + +public class Star { + + private StarType type; + private int ageYears; + private int massTons; + + public Star(StarType startType, int startAge, int startMass) { + this.type = startType; + this.ageYears = startAge; + this.massTons = startMass; + } + + public void timePasses() { + ageYears *= 2; + massTons *= 8; + switch (type) { + case RED_GIANT: + type = StarType.WHITE_DWARF; + break; + case SUN: + type = StarType.RED_GIANT; + break; + case SUPERNOVA: + type = StarType.DEAD; + break; + case WHITE_DWARF: + type = StarType.SUPERNOVA; + break; + case DEAD: + ageYears *= 2; + massTons = 0; + break; + default: + break; + } + } + + StarMemento getMemento() { + var state = new StarMementoInternal(); + state.setAgeYears(ageYears); + state.setMassTons(massTons); + state.setType(type); + return state; + } + + void setMemento(StarMemento memento) { + var state = (StarMementoInternal) memento; + this.type = state.getType(); + this.ageYears = state.getAgeYears(); + this.massTons = state.getMassTons(); + } + + @Override + public String toString() { + return String.format("%s age: %d years mass: %d tons", type.toString(), ageYears, massTons); + } + + private static class StarMementoInternal implements StarMemento { + + private StarType type; + private int ageYears; + private int massTons; + + // setters and getters -> + ... + } +} +``` + +And finally here's how we use the mementos to store and restore star states. + +```java + var states = new Stack<>(); + var star = new Star(StarType.SUN, 10000000, 500000); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + states.add(star.getMemento()); + star.timePasses(); + LOGGER.info(star.toString()); + while (states.size() > 0) { + star.setMemento(states.pop()); + LOGGER.info(star.toString()); + } +``` + +Program output: + +``` +sun age: 10000000 years mass: 500000 tons +red giant age: 20000000 years mass: 4000000 tons +white dwarf age: 40000000 years mass: 32000000 tons +supernova age: 80000000 years mass: 256000000 tons +dead star age: 160000000 years mass: 2048000000 tons +supernova age: 80000000 years mass: 256000000 tons +white dwarf age: 40000000 years mass: 32000000 tons +red giant age: 20000000 years mass: 4000000 tons +sun age: 10000000 years mass: 500000 tons +``` + +### Class diagram + +![alt text](./etc/memento.png "Memento") + +### Applicability + +Use the Memento pattern when + +* A snapshot of an object's state must be saved so that it can be restored to that state later, and +* A direct interface to obtaining the state would expose implementation details and break the +object's encapsulation + +## Real world examples + +* [java.util.Date](http://docs.oracle.com/javase/8/docs/api/java/util/Date.html) + +### Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) + + +## Model View Controller +[⬆](#patterns) +--- +layout: pattern +title: Model-View-Controller +folder: model-view-controller +permalink: /patterns/model-view-controller/ +categories: Architectural +tags: + - Decoupling +--- + +### Intent +Separate the user interface into three interconnected components: +the model, the view and the controller. Let the model manage the data, the view +display the data and the controller mediate updating the data and redrawing the +display. + +### Class diagram +![alt text](./etc/model-view-controller.png "Model-View-Controller") + +### Applicability +Use the Model-View-Controller pattern when + +* You want to clearly separate the domain data from its user interface representation + +### Credits + +* [Trygve Reenskaug - Model-view-controller](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321127420&linkCode=as2&tag=javadesignpat-20&linkId=d9f7d37b032ca6e96253562d075fcc4a) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) + +## Model View Presenter +[⬆](#patterns) +--- +layout: pattern +title: Model-View-Presenter +folder: model-view-presenter +permalink: /patterns/model-view-presenter/ +categories: Architectural +tags: + - Decoupling +--- + +### Intent +Apply a "Separation of Concerns" principle in a way that allows +developers to build and test user interfaces. + +### Class diagram +![alt text](./etc/model-view-presenter_1.png "Model-View-Presenter") + +### Applicability +Use the Model-View-Presenter in any of the following +situations + +* When you want to improve the "Separation of Concerns" principle in presentation logic +* When a user interface development and testing is necessary. + +## Real world examples + +* [MVP4J](https://github.com/amineoualialami/mvp4j) + +## Model View View Model +[⬆](#patterns) +--- +layout: pattern +title: Model-View-ViewModel +folder: model-view-viewmodel +permalink: /patterns/model-view-viewmodel/ +categories: Architectural +tags: +- Decoupling +--- + +## Also known as + +Model–View–Binder + +## Intent + +To apply "[Separation of Concerns](https://java-design-patterns.com/principles/#separation-of-concerns)" to separate the logic from the UI components and allow developers to work on UI without affecting the logic and vice versa. + +## Explanation + +Wikipedia says + +> Model–view–viewmodel (MVVM) is a software architectural pattern that facilitates the separation of the development of the graphical user interface (the view) – be it via a markup language or GUI code – from the development of the business logic or back-end logic (the model) so that the view is not dependent on any specific model platform. + +**Programmatic Example** + +Zkoss implementation: + +> ViewModel will hold the business logic and expose the data from model to View + +```java +public class BookViewModel { + @WireVariable + private List bookList; + private Book selectedBook; + private BookService bookService = new BookServiceImpl(); + + public Book getSelectedBook() { + return selectedBook; + } + + @NotifyChange("selectedBook") + public void setSelectedBook(Book selectedBook) { + this.selectedBook = selectedBook; + } + + public List getBookList() { + return bookService.load(); + } + + /** Deleting a book. + */ + @Command + @NotifyChange({"selectedBook","bookList"}) + public void deleteBook() { + if (selectedBook != null) { + getBookList().remove(selectedBook); + selectedBook = null; + } +} +``` + +> View will have no logic, only UI elements + +```xml + + + + + + + + + + + + +