diff --git a/cqrs/README.md b/command-query-responsibility-segregation/README.md similarity index 100% rename from cqrs/README.md rename to command-query-responsibility-segregation/README.md diff --git a/command-query-responsibility-segregation/etc/command-query-responsibility-segregation.urm.puml b/command-query-responsibility-segregation/etc/command-query-responsibility-segregation.urm.puml new file mode 100644 index 000000000..aef8eef5c --- /dev/null +++ b/command-query-responsibility-segregation/etc/command-query-responsibility-segregation.urm.puml @@ -0,0 +1,136 @@ +@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) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getEmail() : String + + getName() : String + + getUsername() : String + + hashCode() : int + + toString() : String + } + class Book { + - price : double + - title : String + + Book() + + Book(title : String, price : double) + # canEqual(other : Object) : boolean + + equals(o : Object) : boolean + + getPrice() : double + + getTitle() : String + + hashCode() : int + + toString() : String + } +} +package com.iluwatar.cqrs.commandes { + interface CommandService { + + 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} + } + 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 + } +} +package com.iluwatar.cqrs.queries { + interface QueryService { + + 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 ..|> CommandService +QueryServiceImpl ..|> QueryService +@enduml \ No newline at end of file diff --git a/cqrs/etc/cqrs.png b/command-query-responsibility-segregation/etc/cqrs.png similarity index 100% rename from cqrs/etc/cqrs.png rename to command-query-responsibility-segregation/etc/cqrs.png diff --git a/cqrs/etc/cqrs.ucls b/command-query-responsibility-segregation/etc/cqrs.ucls similarity index 100% rename from cqrs/etc/cqrs.ucls rename to command-query-responsibility-segregation/etc/cqrs.ucls diff --git a/cqrs/etc/cqrs.urm.puml b/command-query-responsibility-segregation/etc/cqrs.urm.puml similarity index 100% rename from cqrs/etc/cqrs.urm.puml rename to command-query-responsibility-segregation/etc/cqrs.urm.puml diff --git a/cqrs/pom.xml b/command-query-responsibility-segregation/pom.xml similarity index 97% rename from cqrs/pom.xml rename to command-query-responsibility-segregation/pom.xml index ec78265cf..bc2659cdc 100644 --- a/cqrs/pom.xml +++ b/command-query-responsibility-segregation/pom.xml @@ -32,7 +32,7 @@ java-design-patterns 1.26.0-SNAPSHOT - cqrs + command-query-responsibility-segregation org.junit.jupiter diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/app/App.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/app/App.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/app/App.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/app/App.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandService.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/commandes/CommandServiceImpl.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/constants/AppConstants.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Author.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Author.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Author.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Book.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/domain/model/Book.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/domain/model/Book.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Author.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/dto/Author.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Author.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Book.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/dto/Book.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/dto/Book.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryService.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryService.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryService.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryService.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/queries/QueryServiceImpl.java diff --git a/cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java b/command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java similarity index 100% rename from cqrs/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java rename to command-query-responsibility-segregation/src/main/java/com/iluwatar/cqrs/util/HibernateUtil.java diff --git a/cqrs/src/main/resources/hibernate.cfg.xml b/command-query-responsibility-segregation/src/main/resources/hibernate.cfg.xml similarity index 100% rename from cqrs/src/main/resources/hibernate.cfg.xml rename to command-query-responsibility-segregation/src/main/resources/hibernate.cfg.xml diff --git a/cqrs/src/main/resources/logback.xml b/command-query-responsibility-segregation/src/main/resources/logback.xml similarity index 100% rename from cqrs/src/main/resources/logback.xml rename to command-query-responsibility-segregation/src/main/resources/logback.xml diff --git a/cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java b/command-query-responsibility-segregation/src/test/java/com/iluwatar/cqrs/IntegrationTest.java similarity index 100% rename from cqrs/src/test/java/com/iluwatar/cqrs/IntegrationTest.java rename to command-query-responsibility-segregation/src/test/java/com/iluwatar/cqrs/IntegrationTest.java diff --git a/cqrs/src/test/resources/hibernate.cfg.xml b/command-query-responsibility-segregation/src/test/resources/hibernate.cfg.xml similarity index 100% rename from cqrs/src/test/resources/hibernate.cfg.xml rename to command-query-responsibility-segregation/src/test/resources/hibernate.cfg.xml diff --git a/cqrs/src/test/resources/logback.xml b/command-query-responsibility-segregation/src/test/resources/logback.xml similarity index 100% rename from cqrs/src/test/resources/logback.xml rename to command-query-responsibility-segregation/src/test/resources/logback.xml diff --git a/commander/src/main/java/com/iluwatar/commander/RetryParams.java b/commander/src/main/java/com/iluwatar/commander/RetryParams.java index d6cf5dfec..ee3bf537f 100644 --- a/commander/src/main/java/com/iluwatar/commander/RetryParams.java +++ b/commander/src/main/java/com/iluwatar/commander/RetryParams.java @@ -1,3 +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. + */ package com.iluwatar.commander; /** diff --git a/commander/src/main/java/com/iluwatar/commander/TimeLimits.java b/commander/src/main/java/com/iluwatar/commander/TimeLimits.java index 6de079edd..bdb7caaf4 100644 --- a/commander/src/main/java/com/iluwatar/commander/TimeLimits.java +++ b/commander/src/main/java/com/iluwatar/commander/TimeLimits.java @@ -1,3 +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. + */ package com.iluwatar.commander; /** diff --git a/crtp/README.md b/curiously-recurring-template-pattern/README.md similarity index 97% rename from crtp/README.md rename to curiously-recurring-template-pattern/README.md index b767065ec..b1a382e56 100644 --- a/crtp/README.md +++ b/curiously-recurring-template-pattern/README.md @@ -1,180 +1,180 @@ ---- -title: Curiously Recurring Template Pattern -language: en -category: Structural -tag: - - Extensibility - - Idiom - - Instantiation ---- - -## Also known as - -* CRTP -* Mixin Inheritance -* Recursive Type Bound -* Recursive Generic -* Static Polymorphism - -## Intent - -Curiously Recurring Template Pattern (CRTP) is used to achieve a form of static polymorphism by having a class template derive from a template instantiation of its own class, allowing method overriding and polymorphic behavior at compile time rather than at runtime. - -## Explanation - -Real-world example - -> For a mixed martial arts promotion that is planning an event, ensuring that the fights are organized between athletes of the same weight class is crucial. This prevents mismatches between fighters of significantly different sizes, such as a heavyweight facing off against a bantamweight. - -In plain words - -> Make certain methods within a type to accept arguments specific to its subtypes. - -Wikipedia says - -> The curiously recurring template pattern (CRTP) is an idiom, originally in C++, in which a class X derives from a class template instantiation using X itself as a template argument. - -**Programmatic example** - -Let's define the generic interface Fighter. - -```java -public interface Fighter { - - void fight(T t); - -} -``` - -The MMAFighter class is used to instantiate fighters distinguished by their weight class. - -```java -public class MmaFighter> implements Fighter { - - private final String - name; - private final String - surname; - private final String - nickName; - private final String - speciality; - - public MmaFighter( - String name, - String surname, - String nickName, - String speciality) { - this.name = - name; - this.surname = - surname; - this.nickName = - nickName; - this.speciality = - speciality; - } - - @Override - public void fight( - T opponent) { - LOGGER.info( - "{} is going to fight against {}", - this, - opponent); - } - - @Override - public String toString() { - return - name + - " \"" + - nickName + - "\" " + - surname; - } -} -``` - -The followings are some subtypes of MmaFighter. - -```java -class MmaBantamweightFighter extends MmaFighter { - - public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} - -public class MmaHeavyweightFighter extends MmaFighter { - - public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} -``` - -A fighter is allowed to fight an opponent of the same weight classes. If the opponent is of a different weight class, an error is raised. - -```java -MmaBantamweightFighter fighter1=new MmaBantamweightFighter("Joe","Johnson","The Geek","Muay Thai"); - MmaBantamweightFighter fighter2=new MmaBantamweightFighter("Ed","Edwards","The Problem Solver","Judo"); - fighter1.fight(fighter2); // This is fine - - MmaHeavyweightFighter fighter3=new MmaHeavyweightFighter("Dave","Davidson","The Bug Smasher","Kickboxing"); - MmaHeavyweightFighter fighter4=new MmaHeavyweightFighter("Jack","Jackson","The Pragmatic","Brazilian Jiu-Jitsu"); - fighter3.fight(fighter4); // This is fine too - - fighter1.fight(fighter3); // This will raise a compilation error -``` - -## Class diagram - -![alt text](./etc/crtp.png "CRTP class diagram") - -## Applicability - -* When you need to extend the functionality of a class through inheritance but prefer compile-time polymorphism to runtime polymorphism for efficiency reasons. -* When you want to avoid the overhead of virtual functions but still achieve polymorphic behavior. -* In template metaprogramming to provide implementations of functions or policies that can be selected at compile time. -* You have type conflicts when chaining methods in an object hierarchy. -* You want to use a parameterized class method that can accept subclasses of the class as arguments, allowing it to be applied to objects that inherit from the class. -* You want certain methods to work only with instances of the same type, such as for achieving mutual comparability. - -## Tutorials - -* [The NuaH Blog](https://nuah.livejournal.com/328187.html) -* Yogesh Umesh Vaity's answer to [What does "Recursive type bound" in Generics mean?](https://stackoverflow.com/questions/7385949/what-does-recursive-type-bound-in-generics-mean) - -## Known uses - -* Implementing compile-time polymorphic interfaces in template libraries. -* Enhancing code reuse in libraries where performance is critical, like in mathematical computations, embedded systems, and real-time processing applications. -* [java.lang.Enum](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Enum.html) - -## Consequences - -Benefits: - -* Elimination of virtual function call overhead, enhancing performance. -* Safe reuse of the base class code without the risks associated with multiple inheritances. -* Greater flexibility and extensibility in compile-time polymorphism scenarios. - -Trade-offs: - -* Increased complexity in understanding and debugging due to the interplay of templates and inheritance. -* Can lead to code bloat because each instantiation of a template results in a new class. -* Less flexibility compared to runtime polymorphism as the behavior must be determined entirely at compile time. - -## Related Patterns - -* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): Can be used in conjunction with CRTP to instantiate derived classes without knowing their specific types. -* [Strategy](https://java-design-patterns.com/patterns/strategy/): CRTP can implement compile-time strategy selection. -* [Template Method](https://java-design-patterns.com/patterns/template-method/): Similar in structure but differs in that CRTP achieves behavior variation through compile-time polymorphism. - -## 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) -* [How do I decrypt "Enum>"?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106) +--- +title: Curiously Recurring Template Pattern +language: en +category: Structural +tag: + - Extensibility + - Idiom + - Instantiation +--- + +## Also known as + +* CRTP +* Mixin Inheritance +* Recursive Type Bound +* Recursive Generic +* Static Polymorphism + +## Intent + +Curiously Recurring Template Pattern (CRTP) is used to achieve a form of static polymorphism by having a class template derive from a template instantiation of its own class, allowing method overriding and polymorphic behavior at compile time rather than at runtime. + +## Explanation + +Real-world example + +> For a mixed martial arts promotion that is planning an event, ensuring that the fights are organized between athletes of the same weight class is crucial. This prevents mismatches between fighters of significantly different sizes, such as a heavyweight facing off against a bantamweight. + +In plain words + +> Make certain methods within a type to accept arguments specific to its subtypes. + +Wikipedia says + +> The curiously recurring template pattern (CRTP) is an idiom, originally in C++, in which a class X derives from a class template instantiation using X itself as a template argument. + +**Programmatic example** + +Let's define the generic interface Fighter. + +```java +public interface Fighter { + + void fight(T t); + +} +``` + +The MMAFighter class is used to instantiate fighters distinguished by their weight class. + +```java +public class MmaFighter> implements Fighter { + + private final String + name; + private final String + surname; + private final String + nickName; + private final String + speciality; + + public MmaFighter( + String name, + String surname, + String nickName, + String speciality) { + this.name = + name; + this.surname = + surname; + this.nickName = + nickName; + this.speciality = + speciality; + } + + @Override + public void fight( + T opponent) { + LOGGER.info( + "{} is going to fight against {}", + this, + opponent); + } + + @Override + public String toString() { + return + name + + " \"" + + nickName + + "\" " + + surname; + } +} +``` + +The followings are some subtypes of MmaFighter. + +```java +class MmaBantamweightFighter extends MmaFighter { + + public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} + +public class MmaHeavyweightFighter extends MmaFighter { + + public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} +``` + +A fighter is allowed to fight an opponent of the same weight classes. If the opponent is of a different weight class, an error is raised. + +```java +MmaBantamweightFighter fighter1=new MmaBantamweightFighter("Joe","Johnson","The Geek","Muay Thai"); + MmaBantamweightFighter fighter2=new MmaBantamweightFighter("Ed","Edwards","The Problem Solver","Judo"); + fighter1.fight(fighter2); // This is fine + + MmaHeavyweightFighter fighter3=new MmaHeavyweightFighter("Dave","Davidson","The Bug Smasher","Kickboxing"); + MmaHeavyweightFighter fighter4=new MmaHeavyweightFighter("Jack","Jackson","The Pragmatic","Brazilian Jiu-Jitsu"); + fighter3.fight(fighter4); // This is fine too + + fighter1.fight(fighter3); // This will raise a compilation error +``` + +## Class diagram + +![alt text](./etc/crtp.png "CRTP class diagram") + +## Applicability + +* When you need to extend the functionality of a class through inheritance but prefer compile-time polymorphism to runtime polymorphism for efficiency reasons. +* When you want to avoid the overhead of virtual functions but still achieve polymorphic behavior. +* In template metaprogramming to provide implementations of functions or policies that can be selected at compile time. +* You have type conflicts when chaining methods in an object hierarchy. +* You want to use a parameterized class method that can accept subclasses of the class as arguments, allowing it to be applied to objects that inherit from the class. +* You want certain methods to work only with instances of the same type, such as for achieving mutual comparability. + +## Tutorials + +* [The NuaH Blog](https://nuah.livejournal.com/328187.html) +* Yogesh Umesh Vaity's answer to [What does "Recursive type bound" in Generics mean?](https://stackoverflow.com/questions/7385949/what-does-recursive-type-bound-in-generics-mean) + +## Known uses + +* Implementing compile-time polymorphic interfaces in template libraries. +* Enhancing code reuse in libraries where performance is critical, like in mathematical computations, embedded systems, and real-time processing applications. +* [java.lang.Enum](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Enum.html) + +## Consequences + +Benefits: + +* Elimination of virtual function call overhead, enhancing performance. +* Safe reuse of the base class code without the risks associated with multiple inheritances. +* Greater flexibility and extensibility in compile-time polymorphism scenarios. + +Trade-offs: + +* Increased complexity in understanding and debugging due to the interplay of templates and inheritance. +* Can lead to code bloat because each instantiation of a template results in a new class. +* Less flexibility compared to runtime polymorphism as the behavior must be determined entirely at compile time. + +## Related Patterns + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): Can be used in conjunction with CRTP to instantiate derived classes without knowing their specific types. +* [Strategy](https://java-design-patterns.com/patterns/strategy/): CRTP can implement compile-time strategy selection. +* [Template Method](https://java-design-patterns.com/patterns/template-method/): Similar in structure but differs in that CRTP achieves behavior variation through compile-time polymorphism. + +## 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) +* [How do I decrypt "Enum>"?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106) diff --git a/crtp/etc/crtp.png b/curiously-recurring-template-pattern/etc/crtp.png similarity index 100% rename from crtp/etc/crtp.png rename to curiously-recurring-template-pattern/etc/crtp.png diff --git a/crtp/etc/crtp.urm.puml b/curiously-recurring-template-pattern/etc/crtp.urm.puml similarity index 100% rename from crtp/etc/crtp.urm.puml rename to curiously-recurring-template-pattern/etc/crtp.urm.puml diff --git a/curiously-recurring-template-pattern/etc/curiously-recurring-template-pattern.urm.puml b/curiously-recurring-template-pattern/etc/curiously-recurring-template-pattern.urm.puml new file mode 100644 index 000000000..02af47ddf --- /dev/null +++ b/curiously-recurring-template-pattern/etc/curiously-recurring-template-pattern.urm.puml @@ -0,0 +1,2 @@ +@startuml +@enduml \ No newline at end of file diff --git a/crtp/pom.xml b/curiously-recurring-template-pattern/pom.xml similarity index 96% rename from crtp/pom.xml rename to curiously-recurring-template-pattern/pom.xml index 1869f7b37..5f2227684 100644 --- a/crtp/pom.xml +++ b/curiously-recurring-template-pattern/pom.xml @@ -1,64 +1,64 @@ - - - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - crtp - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.crtp.App - - - - - - - - - + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + curiously-recurring-template-pattern + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.crtp.App + + + + + + + + + diff --git a/crtp/src/main/java/crtp/App.java b/curiously-recurring-template-pattern/src/main/java/crtp/App.java similarity index 100% rename from crtp/src/main/java/crtp/App.java rename to curiously-recurring-template-pattern/src/main/java/crtp/App.java diff --git a/crtp/src/main/java/crtp/Fighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/Fighter.java similarity index 97% rename from crtp/src/main/java/crtp/Fighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/Fighter.java index 675a3d975..40a7367ce 100644 --- a/crtp/src/main/java/crtp/Fighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/Fighter.java @@ -1,36 +1,36 @@ -/* - * 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. - */ -package crtp; - -/** - * Fighter interface. - * - * @param The type of fighter. - */ -public interface Fighter { - - void fight(T t); - -} +/* + * 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. + */ +package crtp; + +/** + * Fighter interface. + * + * @param The type of fighter. + */ +public interface Fighter { + + void fight(T t); + +} diff --git a/crtp/src/main/java/crtp/MmaBantamweightFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaBantamweightFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaBantamweightFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaBantamweightFighter.java index 737dcac92..25258c8bc 100644 --- a/crtp/src/main/java/crtp/MmaBantamweightFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaBantamweightFighter.java @@ -1,36 +1,36 @@ -/* - * 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. - */ -package crtp; - -/** - * MmaBantamweightFighter class. - */ -class MmaBantamweightFighter extends MmaFighter { - - public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - +/* + * 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. + */ +package crtp; + +/** + * MmaBantamweightFighter class. + */ +class MmaBantamweightFighter extends MmaFighter { + + public MmaBantamweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + } \ No newline at end of file diff --git a/crtp/src/main/java/crtp/MmaFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaFighter.java index 98f37a673..fd1155a5b 100644 --- a/crtp/src/main/java/crtp/MmaFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaFighter.java @@ -1,49 +1,49 @@ -/* - * 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. - */ -package crtp; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -/** - * MmaFighter class. - * - * @param MmaFighter derived class that uses itself as type parameter. - */ -@Slf4j -@Data -public class MmaFighter> implements Fighter { - - private final String name; - private final String surname; - private final String nickName; - private final String speciality; - - @Override - public void fight(T opponent) { - LOGGER.info("{} is going to fight against {}", this, opponent); - } - -} +/* + * 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. + */ +package crtp; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +/** + * MmaFighter class. + * + * @param MmaFighter derived class that uses itself as type parameter. + */ +@Slf4j +@Data +public class MmaFighter> implements Fighter { + + private final String name; + private final String surname; + private final String nickName; + private final String speciality; + + @Override + public void fight(T opponent) { + LOGGER.info("{} is going to fight against {}", this, opponent); + } + +} diff --git a/crtp/src/main/java/crtp/MmaHeavyweightFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaHeavyweightFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaHeavyweightFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaHeavyweightFighter.java index 4df63ef14..74c1f9147 100644 --- a/crtp/src/main/java/crtp/MmaHeavyweightFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaHeavyweightFighter.java @@ -1,36 +1,36 @@ -/* - * 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. - */ -package crtp; - -/** - * MmaHeavyweightFighter. - */ -public class MmaHeavyweightFighter extends MmaFighter { - - public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} +/* + * 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. + */ +package crtp; + +/** + * MmaHeavyweightFighter. + */ +public class MmaHeavyweightFighter extends MmaFighter { + + public MmaHeavyweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} diff --git a/crtp/src/main/java/crtp/MmaLightweightFighter.java b/curiously-recurring-template-pattern/src/main/java/crtp/MmaLightweightFighter.java similarity index 97% rename from crtp/src/main/java/crtp/MmaLightweightFighter.java rename to curiously-recurring-template-pattern/src/main/java/crtp/MmaLightweightFighter.java index c9afd5481..4a3d606a8 100644 --- a/crtp/src/main/java/crtp/MmaLightweightFighter.java +++ b/curiously-recurring-template-pattern/src/main/java/crtp/MmaLightweightFighter.java @@ -1,36 +1,36 @@ -/* - * 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. - */ -package crtp; - -/** - * MmaLightweightFighter class. - */ -class MmaLightweightFighter extends MmaFighter { - - public MmaLightweightFighter(String name, String surname, String nickName, String speciality) { - super(name, surname, nickName, speciality); - } - -} +/* + * 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. + */ +package crtp; + +/** + * MmaLightweightFighter class. + */ +class MmaLightweightFighter extends MmaFighter { + + public MmaLightweightFighter(String name, String surname, String nickName, String speciality) { + super(name, surname, nickName, speciality); + } + +} diff --git a/crtp/src/test/java/crtp/AppTest.java b/curiously-recurring-template-pattern/src/test/java/crtp/AppTest.java similarity index 100% rename from crtp/src/test/java/crtp/AppTest.java rename to curiously-recurring-template-pattern/src/test/java/crtp/AppTest.java diff --git a/crtp/src/test/java/crtp/FightTest.java b/curiously-recurring-template-pattern/src/test/java/crtp/FightTest.java similarity index 97% rename from crtp/src/test/java/crtp/FightTest.java rename to curiously-recurring-template-pattern/src/test/java/crtp/FightTest.java index 9c6a2ee61..279730d48 100644 --- a/crtp/src/test/java/crtp/FightTest.java +++ b/curiously-recurring-template-pattern/src/test/java/crtp/FightTest.java @@ -1,74 +1,74 @@ -/* - * 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. - */ -package crtp; - -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Slf4j -public class FightTest { - - /** - * A fighter has signed a contract with a promotion, and he will face some other fighters. A list of opponents is ready - * but for some reason not all of them belong to the same weight class. Let's ensure that the fighter will only face - * opponents in the same weight class. - */ - @Test - void testFighterCanFightOnlyAgainstSameWeightOpponents() { - MmaBantamweightFighter fighter = new MmaBantamweightFighter("Joe", "Johnson", "The Geek", "Muay Thai"); - List> opponents = getOpponents(); - List> challenged = new ArrayList<>(); - - opponents.forEach(challenger -> { - try { - ((MmaBantamweightFighter) challenger).fight(fighter); - challenged.add(challenger); - } catch (ClassCastException e) { - LOGGER.error(e.getMessage()); - } - }); - - assertFalse(challenged.isEmpty()); - assertTrue(challenged.stream().allMatch(c -> c instanceof MmaBantamweightFighter)); - } - - private static List> getOpponents() { - return List.of( - new MmaBantamweightFighter("Ed", "Edwards", "The Problem Solver", "Judo"), - new MmaLightweightFighter("Evan", "Evans", "Clean Coder", "Sambo"), - new MmaHeavyweightFighter("Dave", "Davidson", "The Bug Smasher", "Kickboxing"), - new MmaBantamweightFighter("Ray", "Raymond", "Scrum Master", "Karate"), - new MmaHeavyweightFighter("Jack", "Jackson", "The Pragmatic", "Brazilian Jiu-Jitsu") - ); - } - - -} +/* + * 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. + */ +package crtp; + +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Slf4j +public class FightTest { + + /** + * A fighter has signed a contract with a promotion, and he will face some other fighters. A list of opponents is ready + * but for some reason not all of them belong to the same weight class. Let's ensure that the fighter will only face + * opponents in the same weight class. + */ + @Test + void testFighterCanFightOnlyAgainstSameWeightOpponents() { + MmaBantamweightFighter fighter = new MmaBantamweightFighter("Joe", "Johnson", "The Geek", "Muay Thai"); + List> opponents = getOpponents(); + List> challenged = new ArrayList<>(); + + opponents.forEach(challenger -> { + try { + ((MmaBantamweightFighter) challenger).fight(fighter); + challenged.add(challenger); + } catch (ClassCastException e) { + LOGGER.error(e.getMessage()); + } + }); + + assertFalse(challenged.isEmpty()); + assertTrue(challenged.stream().allMatch(c -> c instanceof MmaBantamweightFighter)); + } + + private static List> getOpponents() { + return List.of( + new MmaBantamweightFighter("Ed", "Edwards", "The Problem Solver", "Judo"), + new MmaLightweightFighter("Evan", "Evans", "Clean Coder", "Sambo"), + new MmaHeavyweightFighter("Dave", "Davidson", "The Bug Smasher", "Kickboxing"), + new MmaBantamweightFighter("Ray", "Raymond", "Scrum Master", "Karate"), + new MmaHeavyweightFighter("Jack", "Jackson", "The Pragmatic", "Brazilian Jiu-Jitsu") + ); + } + + +} diff --git a/dao/README.md b/data-access-object/README.md similarity index 100% rename from dao/README.md rename to data-access-object/README.md diff --git a/dao/etc/dao.png b/data-access-object/etc/dao.png similarity index 100% rename from dao/etc/dao.png rename to data-access-object/etc/dao.png diff --git a/dao/etc/dao.ucls b/data-access-object/etc/dao.ucls similarity index 100% rename from dao/etc/dao.ucls rename to data-access-object/etc/dao.ucls diff --git a/dao/etc/dao.urm.puml b/data-access-object/etc/dao.urm.puml similarity index 100% rename from dao/etc/dao.urm.puml rename to data-access-object/etc/dao.urm.puml diff --git a/data-access-object/etc/data-access-object.urm.puml b/data-access-object/etc/data-access-object.urm.puml new file mode 100644 index 000000000..5c6e5f703 --- /dev/null +++ b/data-access-object/etc/data-access-object.urm.puml @@ -0,0 +1,69 @@ +@startuml +package com.iluwatar.dao { + class App { + - ALL_CUSTOMERS : String {static} + - DB_URL : String {static} + - LOGGER : 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) + # canEqual(other : Object) : boolean + + equals(o : 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/dao/pom.xml b/data-access-object/pom.xml similarity index 98% rename from dao/pom.xml rename to data-access-object/pom.xml index 1d75f1f83..9685cbb96 100644 --- a/dao/pom.xml +++ b/data-access-object/pom.xml @@ -32,7 +32,7 @@ java-design-patterns 1.26.0-SNAPSHOT - dao + data-access-object org.junit.jupiter diff --git a/dao/src/main/java/com/iluwatar/dao/App.java b/data-access-object/src/main/java/com/iluwatar/dao/App.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/App.java rename to data-access-object/src/main/java/com/iluwatar/dao/App.java diff --git a/dao/src/main/java/com/iluwatar/dao/CustomException.java b/data-access-object/src/main/java/com/iluwatar/dao/CustomException.java similarity index 97% rename from dao/src/main/java/com/iluwatar/dao/CustomException.java rename to data-access-object/src/main/java/com/iluwatar/dao/CustomException.java index ce8ca5642..de907a641 100644 --- a/dao/src/main/java/com/iluwatar/dao/CustomException.java +++ b/data-access-object/src/main/java/com/iluwatar/dao/CustomException.java @@ -1,40 +1,40 @@ -/* - * 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. - */ -package com.iluwatar.dao; - -import java.io.Serial; - -/** - * Custom exception. - */ -public class CustomException extends Exception { - - @Serial - private static final long serialVersionUID = 1L; - - public CustomException(String message, Throwable cause) { - super(message, cause); - } -} +/* + * 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. + */ +package com.iluwatar.dao; + +import java.io.Serial; + +/** + * Custom exception. + */ +public class CustomException extends Exception { + + @Serial + private static final long serialVersionUID = 1L; + + public CustomException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/dao/src/main/java/com/iluwatar/dao/Customer.java b/data-access-object/src/main/java/com/iluwatar/dao/Customer.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/Customer.java rename to data-access-object/src/main/java/com/iluwatar/dao/Customer.java diff --git a/dao/src/main/java/com/iluwatar/dao/CustomerDao.java b/data-access-object/src/main/java/com/iluwatar/dao/CustomerDao.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/CustomerDao.java rename to data-access-object/src/main/java/com/iluwatar/dao/CustomerDao.java diff --git a/dao/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java b/data-access-object/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java rename to data-access-object/src/main/java/com/iluwatar/dao/CustomerSchemaSql.java diff --git a/dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java b/data-access-object/src/main/java/com/iluwatar/dao/DbCustomerDao.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/DbCustomerDao.java rename to data-access-object/src/main/java/com/iluwatar/dao/DbCustomerDao.java diff --git a/dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java b/data-access-object/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java similarity index 100% rename from dao/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java rename to data-access-object/src/main/java/com/iluwatar/dao/InMemoryCustomerDao.java diff --git a/dao/src/test/java/com/iluwatar/dao/AppTest.java b/data-access-object/src/test/java/com/iluwatar/dao/AppTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/AppTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/AppTest.java diff --git a/dao/src/test/java/com/iluwatar/dao/CustomerTest.java b/data-access-object/src/test/java/com/iluwatar/dao/CustomerTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/CustomerTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/CustomerTest.java diff --git a/dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java b/data-access-object/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/DbCustomerDaoTest.java diff --git a/dao/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java b/data-access-object/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java similarity index 100% rename from dao/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java rename to data-access-object/src/test/java/com/iluwatar/dao/InMemoryCustomerDaoTest.java diff --git a/master-worker/etc/master-worker.urm.puml b/master-worker/etc/master-worker.urm.puml new file mode 100644 index 000000000..d5fc9e5d0 --- /dev/null +++ b/master-worker/etc/master-worker.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 : List + ~ Master(numOfWorkers : int) + ~ aggregateData() : Result {abstract} + - collectResult(data : Result, workerId : int) + - divideWork(input : Input) + + doWork(input : Input) + ~ getAllResultData() : Hashtable> + ~ getExpectedNumResults() : int + + getFinalResult() : Result + ~ getWorkers() : List + + receiveData(data : Result, w : Worker) + ~ setWorkers(int) : List {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) : List> + ~ makeDivisions(data : int[][], num : int) : int[] {static} + } + class ArrayResult { + + ArrayResult(data : int[][]) + } + class ArrayUtilityMethods { + - LOGGER : Logger {static} + - RANDOM : SecureRandom {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) : List> {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/module/.gitignore b/module/.gitignore deleted file mode 100644 index ecfa5dd46..000000000 --- a/module/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -error.txt -output.txt diff --git a/module/README.md b/module/README.md deleted file mode 100644 index feb1533ee..000000000 --- a/module/README.md +++ /dev/null @@ -1,163 +0,0 @@ ---- -title: Module -category: Structural -language: en -tag: - - Decoupling - - Encapsulation - - Layered architecture - - Object composition ---- - -## Intent - -The Module pattern aims to encapsulate a group of related elements, such as classes, functions, and variables, into a single unit or module, enhancing cohesion and reducing dependencies between different parts of an application. - -## Explanation - -Real-world example - -> Consider the organization of a modern kitchen as a real-world analogy to the Module pattern. In a kitchen, different sections are dedicated to specific functions: there's a cooking module with stoves and ovens, a cleaning module with sinks and dishwashers, and a storage module with refrigerators and cabinets. Each module encapsulates all the tools and equipment needed for its specific function, ensuring they are not intermingled with those of other modules. This organization enhances efficiency, as each section has everything necessary for its tasks, and reduces confusion by keeping unrelated items separate. This modular approach mirrors the Module pattern in software, where different functionalities are grouped into distinct, self-contained units that manage their own resources and dependencies. - -In plain words - -> The Module pattern encapsulates related functions and data into a single unit, allowing for organized and manageable software components. - -Wikipedia says - -> In software engineering, the module pattern is a design pattern used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept. -> -> This pattern can be implemented in several ways depending on the host programming language, such as the singleton design pattern, object-oriented static members in a class and procedural global functions. In Python, the pattern is built into the language, and each .py file is automatically a module. The same applies to Ada, where the package can be considered a module (similar to a static class). - -**Programmatic Example** - -The Module design pattern is a design pattern that provides a way to wrap a set of related functionalities into a single unit, which can be an object or a function. This pattern is particularly useful in large systems where it's necessary to group related functionality and data to improve code organization and readability. - -In the provided code, we have a great example of the Module pattern. The pattern is implemented using two modules: `FileLoggerModule` and `ConsoleLoggerModule`. Both of these modules are singletons, meaning that only one instance of each module can exist at a time. - -Here's a simplified version of the `FileLoggerModule`: - -```java -class FileLoggerModule extends Logger { - private static final String OUTPUT_FILE = "output.log"; - private static final String ERROR_FILE = "error.log"; - - private static FileLoggerModule instance; - - private FileLoggerModule() { - this.output = OUTPUT_FILE; - this.error = ERROR_FILE; - } - - public static FileLoggerModule getSingleton() { - if (instance == null) { - instance = new FileLoggerModule(); - } - return instance; - } - - @Override - public void printString(String message) { - System.out.println("Writing to " + output + ": " + message); - } - - @Override - public void printErrorString(String errorMessage) { - System.out.println("Writing to " + error + ": " + errorMessage); - } -} -``` - -In this module, we have a `getSingleton` method that ensures only one instance of `FileLoggerModule` is created. The `printString` and `printErrorString` methods are used to print messages and errors to the console, simulating writing to a file. - -Similarly, the `ConsoleLoggerModule` is another module that logs messages and errors to the console: - -```java -class ConsoleLoggerModule extends Logger { - private static ConsoleLoggerModule instance; - - private ConsoleLoggerModule() {} - - public static ConsoleLoggerModule getSingleton() { - if (instance == null) { - instance = new ConsoleLoggerModule(); - } - return instance; - } - - @Override - public void printString(String message) { - System.out.println("Console Output: " + message); - } - - @Override - public void printErrorString(String errorMessage) { - System.err.println("Console Error: " + errorMessage); - } -} -``` - -In the `App` class, these modules are used to log messages: - -```java -public class App { - public void prepare() { - FileLoggerModule.getSingleton().prepare(); - ConsoleLoggerModule.getSingleton().prepare(); - } - - public void execute(String message) { - FileLoggerModule.getSingleton().printString(message); - ConsoleLoggerModule.getSingleton().printString(message); - } - - public static void main(String[] args) { - App app = new App(); - app.prepare(); - app.execute("Hello, Module Pattern!"); - app.unprepare(); - } -} -``` - -In the `prepare` method, the `prepare` method of each module is called. In the `execute` method, the `printString` method of each module is used to log a message. This demonstrates how the Module pattern can be used to encapsulate related functionality into a single unit, improving code organization and readability. - -## Class diagram - -![Module](./etc/module.png "Module") - -## Applicability - -* When you need to group related functionality and data to improve code organization and readability. -* To encapsulate internal details of a part of a program, exposing only what is necessary through a well-defined interface. -* Useful in large systems for dividing the codebase into manageable sections. - -## Known Uses - -* Java Platform Module System introduced in Java 9. -* Organizing libraries or frameworks into coherent units. -* Web applications that segment logic into various modules for maintainability. - -## Consequences - -Benefits: - -* Enhances code clarity and maintainability by grouping related features. -* Reduces global scope pollution and namespace clashes. -* Facilitates better testing and debugging by isolating functionalities. - -Trade-offs: - -* Initial complexity in setting up modules and their interactions. -* Over-modularization can lead to unnecessary complexity and overhead. - -## Related Patterns - -* [Facade](https://java-design-patterns.com/patterns/facade/): Simplifies the module's interface for clients. Both aim to simplify usage by hiding complexity. -* [Singleton](https://java-design-patterns.com/patterns/singleton/): Often used within a module to ensure a single instance of a component is used across the system. - -## Credits - -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) -* [Effective Java](https://amzn.to/4cGk2Jz) -* [Java 9 Modularity: Patterns and Practices for Developing Maintainable Applications](https://amzn.to/4b4CWIK) diff --git a/module/etc/module.png b/module/etc/module.png deleted file mode 100644 index a26807d29..000000000 Binary files a/module/etc/module.png and /dev/null differ diff --git a/module/etc/module.ucls b/module/etc/module.ucls deleted file mode 100644 index d2519b856..000000000 --- a/module/etc/module.ucls +++ /dev/null @@ -1,69 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/module/etc/module.urm.puml b/module/etc/module.urm.puml deleted file mode 100644 index b92446ca1..000000000 --- a/module/etc/module.urm.puml +++ /dev/null @@ -1,43 +0,0 @@ -@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/module/pom.xml b/module/pom.xml deleted file mode 100644 index 4f6c0dcb8..000000000 --- a/module/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - module - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.module.App - - - - - - - - - diff --git a/module/src/main/java/com/iluwatar/module/App.java b/module/src/main/java/com/iluwatar/module/App.java deleted file mode 100644 index c0e03608b..000000000 --- a/module/src/main/java/com/iluwatar/module/App.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.module; - -import java.io.FileNotFoundException; - -/** - * The Module pattern can be considered a Creational pattern and a Structural pattern. It manages - * the creation and organization of other elements, and groups them as the structural pattern does. - * An object that applies this pattern can provide the equivalent of a namespace, providing the - * initialization and finalization process of a static class or a class with static members with - * cleaner, more concise syntax and semantics. - * - *

The below example demonstrates a use case for testing two different modules: File Logger and - * Console Logger - */ -public class App { - - private static final String ERROR = "Error"; - private static final String MESSAGE = "Message"; - public static FileLoggerModule fileLoggerModule; - public static ConsoleLoggerModule consoleLoggerModule; - - /** - * Following method performs the initialization. - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - public static void prepare() throws FileNotFoundException { - - /* Create new singleton objects and prepare their modules */ - fileLoggerModule = FileLoggerModule.getSingleton().prepare(); - consoleLoggerModule = ConsoleLoggerModule.getSingleton().prepare(); - } - - /** - * Following method performs the finalization. - */ - public static void unprepare() { - - /* Close all resources */ - fileLoggerModule.unprepare(); - consoleLoggerModule.unprepare(); - } - - /** - * Following method is main executor. - */ - public static void execute() { - - /* Send logs on file system */ - fileLoggerModule.printString(MESSAGE); - fileLoggerModule.printErrorString(ERROR); - - /* Send logs on console */ - consoleLoggerModule.printString(MESSAGE); - consoleLoggerModule.printErrorString(ERROR); - } - - /** - * Program entry point. - * - * @param args command line args. - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - public static void main(final String... args) throws FileNotFoundException { - prepare(); - execute(); - unprepare(); - } -} diff --git a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java b/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java deleted file mode 100644 index c29e57c0e..000000000 --- a/module/src/main/java/com/iluwatar/module/ConsoleLoggerModule.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.module; - -import java.io.PrintStream; -import lombok.extern.slf4j.Slf4j; - -/** - * The ConsoleLoggerModule is responsible for showing logs on System Console. - * - *

The below example demonstrates a Console logger module, which can print simple and error - * messages in two designated formats - */ -@Slf4j -public final class ConsoleLoggerModule { - - private static ConsoleLoggerModule singleton = null; - - public PrintStream output = null; - public PrintStream error = null; - - private ConsoleLoggerModule() { - } - - /** - * Static method to get single instance of class. - * - * @return singleton instance of ConsoleLoggerModule - */ - public static ConsoleLoggerModule getSingleton() { - - if (ConsoleLoggerModule.singleton == null) { - ConsoleLoggerModule.singleton = new ConsoleLoggerModule(); - } - - return ConsoleLoggerModule.singleton; - } - - /** - * Following method performs the initialization. - */ - public ConsoleLoggerModule prepare() { - - LOGGER.debug("ConsoleLoggerModule::prepare();"); - - this.output = new PrintStream(System.out); - this.error = new PrintStream(System.err); - - return this; - } - - /** - * Following method performs the finalization. - */ - public void unprepare() { - - if (this.output != null) { - - this.output.flush(); - this.output.close(); - } - - if (this.error != null) { - - this.error.flush(); - this.error.close(); - } - - LOGGER.debug("ConsoleLoggerModule::unprepare();"); - } - - /** - * Used to print a message. - * - * @param value will be printed on console - */ - public void printString(final String value) { - this.output.println(value); - } - - /** - * Used to print a error message. - * - * @param value will be printed on error console - */ - public void printErrorString(final String value) { - this.error.println(value); - } -} diff --git a/module/src/main/java/com/iluwatar/module/FileLoggerModule.java b/module/src/main/java/com/iluwatar/module/FileLoggerModule.java deleted file mode 100644 index 7a226b643..000000000 --- a/module/src/main/java/com/iluwatar/module/FileLoggerModule.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.module; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.PrintStream; -import lombok.extern.slf4j.Slf4j; - -/** - * The FileLoggerModule is responsible for showing logs on File System. - * - *

The below example demonstrates a File logger module, which can print simple and error - * messages in two designated files - */ -@Slf4j -public final class FileLoggerModule { - - private static FileLoggerModule singleton = null; - - private static final String OUTPUT_FILE = "output.txt"; - private static final String ERROR_FILE = "error.txt"; - - public PrintStream output = null; - public PrintStream error = null; - - private FileLoggerModule() { - } - - /** - * Static method to get single instance of class. - * - * @return singleton instance of FileLoggerModule - */ - public static FileLoggerModule getSingleton() { - - if (FileLoggerModule.singleton == null) { - FileLoggerModule.singleton = new FileLoggerModule(); - } - - return FileLoggerModule.singleton; - } - - /** - * Following method performs the initialization. - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - public FileLoggerModule prepare() throws FileNotFoundException { - - LOGGER.debug("FileLoggerModule::prepare();"); - - this.output = new PrintStream(new FileOutputStream(OUTPUT_FILE)); - this.error = new PrintStream(new FileOutputStream(ERROR_FILE)); - - return this; - } - - /** - * Following method performs the finalization. - */ - public void unprepare() { - - if (this.output != null) { - - this.output.flush(); - this.output.close(); - } - - if (this.error != null) { - - this.error.flush(); - this.error.close(); - } - - LOGGER.debug("FileLoggerModule::unprepare();"); - } - - /** - * Used to print a message. - * - * @param value will be printed in file - */ - public void printString(final String value) { - this.output.println(value); - } - - /** - * Used to print a error message. - * - * @param value will be printed on error file - */ - public void printErrorString(final String value) { - this.error.println(value); - } -} diff --git a/module/src/test/java/com/iluwatar/module/AppTest.java b/module/src/test/java/com/iluwatar/module/AppTest.java deleted file mode 100644 index c385b8d8a..000000000 --- a/module/src/test/java/com/iluwatar/module/AppTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.module; - -import java.io.FileNotFoundException; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.function.Executable; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - -/** - * Tests that Module example runs without errors. - */ -final class AppTest { - - @Test - void shouldExecuteWithoutException() { - assertDoesNotThrow((Executable) App::main); - } -} diff --git a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java b/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java deleted file mode 100644 index 6d05566b4..000000000 --- a/module/src/test/java/com/iluwatar/module/FileLoggerModuleTest.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.module; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNull; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.Test; - -/** - * The Module pattern can be considered a Creational pattern and a Structural pattern. It manages - * the creation and organization of other elements, and groups them as the structural pattern does. - * An object that applies this pattern can provide the equivalent of a namespace, providing the - * initialization and finalization process of a static class or a class with static members with - * cleaner, more concise syntax and semantics. - *

- * The below example demonstrates a JUnit test for testing two different modules: File Logger and - * Console Logger - */ -@Slf4j -public final class FileLoggerModuleTest { - - private static final String OUTPUT_FILE = "output.txt"; - private static final String ERROR_FILE = "error.txt"; - - private static final String MESSAGE = "MESSAGE"; - private static final String ERROR = "ERROR"; - - - /** - * This test verify that 'MESSAGE' is perfectly printed in output file - * - * @throws IOException if program is not able to find log files (output.txt and error.txt) - */ - @Test - void testFileMessage() throws IOException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Print 'Message' in file */ - fileLoggerModule.printString(MESSAGE); - - /* Test if 'Message' is printed in file */ - assertEquals(readFirstLine(OUTPUT_FILE), MESSAGE); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that nothing is printed in output file - * - * @throws IOException if program is not able to find log files (output.txt and error.txt) - */ - @Test - void testNoFileMessage() throws IOException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Test if nothing is printed in file */ - assertNull(readFirstLine(OUTPUT_FILE)); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that 'ERROR' is perfectly printed in error file - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - @Test - void testFileErrorMessage() throws FileNotFoundException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Print 'Error' in file */ - fileLoggerModule.printErrorString(ERROR); - - /* Test if 'Message' is printed in file */ - assertEquals(ERROR, readFirstLine(ERROR_FILE)); - - /* Un-prepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * This test verify that nothing is printed in error file - * - * @throws FileNotFoundException if program is not able to find log files (output.txt and - * error.txt) - */ - @Test - void testNoFileErrorMessage() throws FileNotFoundException { - - /* Get singleton instance of File Logger Module */ - final var fileLoggerModule = FileLoggerModule.getSingleton(); - - /* Prepare the essential sub modules, to perform the sequence of jobs */ - fileLoggerModule.prepare(); - - /* Test if nothing is printed in file */ - assertNull(readFirstLine(ERROR_FILE)); - - /* Unprepare to cleanup the modules */ - fileLoggerModule.unprepare(); - } - - /** - * Utility method to read first line of a file - * - * @param file as file name to be read - * @return a string value as first line in file - */ - private static String readFirstLine(final String file) { - - String firstLine = null; - try (var bufferedReader = new BufferedReader(new FileReader(file))) { - - while (bufferedReader.ready()) { - - /* Read the line */ - firstLine = bufferedReader.readLine(); - } - - LOGGER.info("ModuleTest::readFirstLine() : firstLine : " + firstLine); - - } catch (final IOException e) { - LOGGER.error("ModuleTest::readFirstLine()", e); - } - - return firstLine; - } -} diff --git a/pom.xml b/pom.xml index 6c8a03c18..a22f0ac9c 100644 --- a/pom.xml +++ b/pom.xml @@ -68,7 +68,7 @@ adapter bridge composite - dao + data-access-object data-mapper decorator facade @@ -99,7 +99,6 @@ producer-consumer pipeline poison-pill - reader-writer-lock lazy-loading service-layer specification @@ -131,7 +130,6 @@ factory-kit feature-toggle value-object - module monad mute-idiom hexagonal @@ -150,7 +148,7 @@ balking extension-objects marker - cqrs + command-query-responsibility-segregation event-sourcing data-transfer-object throttling @@ -164,7 +162,6 @@ collection-pipeline master-worker spatial-partition - priority-queue commander type-object bytecode @@ -210,7 +207,7 @@ context-object thread-local-storage optimistic-offline-lock - crtp + curiously-recurring-template-pattern log-aggregation anti-corruption-layer health-check diff --git a/priority-queue/README.md b/priority-queue/README.md deleted file mode 100644 index f034b96b2..000000000 --- a/priority-queue/README.md +++ /dev/null @@ -1,227 +0,0 @@ ---- -title: Priority Queue -category: Concurrency -language: en -tag: - - Performance - - Scalability - - Synchronization - - Thread management ---- - -## Also known as - -* Priority Heap -* Priority List - -## Intent - -The Priority Queue design pattern provides a way to manage a collection of elements where each element has a priority, and elements are accessed and removed based on their priority rather than their insertion order. - -## Explanation - -Real world example - -> Imagine an emergency room in a hospital. Patients arrive with varying degrees of urgency: some have minor injuries, while others have life-threatening conditions. The hospital uses a priority queue system to manage these patients. Instead of treating patients on a first-come, first-served basis, the medical staff assigns a priority level to each patient based on the severity of their condition. Patients with more critical conditions (higher priority) are treated before those with less severe issues, ensuring that urgent cases receive immediate attention. This system efficiently manages resources and prioritizes care, similar to how a priority queue handles elements based on their priority. - -In plain words - -> Priority Queue enables processing of high priority messages first, regardless of queue size or message age. - -Wikipedia says - -> In computer science, a priority queue is an abstract data type similar to regular queue or stack data structure in which each element additionally has a "priority" associated with it. In a priority queue, an element with high priority is served before an element with low priority. - -**Programmatic Example** - -Looking at a video processing example, let's first see the `Message` structure. - -```java -public class Message implements Comparable { - - private final String message; - private final int priority; // define message priority in queue - - public Message(String message, int priority) { - this.message = message; - this.priority = priority; - } - - @Override - public int compareTo(Message o) { - return priority - o.priority; - } - // ... -} -``` - -Here's `PriorityMessageQueue` that handles storing the messages and serving them in priority order. - -```java -public class PriorityMessageQueue { - - // ... - - public T remove() { - if (isEmpty()) { - return null; - } - - final var root = queue[0]; - queue[0] = queue[size - 1]; - size--; - maxHeapifyDown(); - return root; - } - - public void add(T t) { - ensureCapacity(); - queue[size] = t; - size++; - maxHeapifyUp(); - } - - // ... -} -``` - -`QueueManager` has a `PriorityMessageQueue` and makes it easy to `publishMessage` and `receiveMessage`. - -```java -public class QueueManager { - - private final PriorityMessageQueue messagePriorityMessageQueue; - - public QueueManager(int initialCapacity) { - messagePriorityMessageQueue = new PriorityMessageQueue<>(new Message[initialCapacity]); - } - - public void publishMessage(Message message) { - messagePriorityMessageQueue.add(message); - } - - public Message receiveMessage() { - if (messagePriorityMessageQueue.isEmpty()) { - return null; - } - return messagePriorityMessageQueue.remove(); - } -} -``` - -`Worker` constantly polls `QueueManager` for highest priority message and processes it. - -```java - -@Slf4j -public class Worker { - - private final QueueManager queueManager; - - public Worker(QueueManager queueManager) { - this.queueManager = queueManager; - } - - public void run() throws Exception { - while (true) { - var message = queueManager.receiveMessage(); - if (message == null) { - LOGGER.info("No Message ... waiting"); - Thread.sleep(200); - } else { - processMessage(message); - } - } - } - - private void processMessage(Message message) { - LOGGER.info(message.toString()); - } -} -``` - -Here's the full example how we create an instance of `QueueManager` and process messages using `Worker`. - -```java -var queueManager = new QueueManager(100); - -for (var i = 0; i< 100; i++) { - queueManager.publishMessage(new Message("Low Message Priority", 0)); -} - -for(var i = 0; i< 100; i++) { - queueManager.publishMessage(new Message("High Message Priority", 1)); -} - -var worker = new Worker(queueManager); -worker.run(); -``` - -Program output: - -``` -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='High Message Priority', priority=1} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -Message{message='Low Message Priority', priority=0} -No Message ... waiting -No Message ... waiting -No Message ... waiting -``` - -## Class diagram - -![alt text](./etc/priority-queue.urm.png "Priority Queue pattern class diagram") - -## Applicability - -Use the Priority Queue pattern when: - -* You need to manage tasks or elements that have different priorities. -* Applicable in scheduling systems where tasks need to be executed based on their priority. -* Useful in scenarios where you need to handle a large number of elements with varying importance levels efficiently. - -## Known Uses - -* Task scheduling in operating systems. -* Job scheduling in servers and batch processing systems. -* Event simulation systems where events are processed based on their scheduled time. -* Pathfinding algorithms (e.g., Dijkstra's or A* algorithms). - -## Consequences - -Benefits: - -* Efficient management of elements based on priority. -* Enhanced performance for priority-based access and removal operations. -* Improved scalability in systems requiring prioritized task execution. - -Trade-offs: - -* Increased complexity in implementation and maintenance compared to simple queues. -* Potential for higher memory usage due to the underlying data structures. -* Requires careful synchronization in a multi-threaded environment to avoid concurrency issues. - -## Related Patterns - -* Observer: Can be used alongside Priority Queue to notify when elements with high priority are processed. - -## Credits - -* [Priority Queue pattern - Microsoft](https://docs.microsoft.com/en-us/azure/architecture/patterns/priority-queue) diff --git a/priority-queue/etc/priority-queue.urm.png b/priority-queue/etc/priority-queue.urm.png deleted file mode 100644 index e0b4295a5..000000000 Binary files a/priority-queue/etc/priority-queue.urm.png and /dev/null differ diff --git a/priority-queue/etc/priority-queue.urm.puml b/priority-queue/etc/priority-queue.urm.puml deleted file mode 100644 index cee118f57..000000000 --- a/priority-queue/etc/priority-queue.urm.puml +++ /dev/null @@ -1,54 +0,0 @@ -@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/priority-queue/pom.xml b/priority-queue/pom.xml deleted file mode 100644 index 63eed2c90..000000000 --- a/priority-queue/pom.xml +++ /dev/null @@ -1,62 +0,0 @@ - - - - 4.0.0 - priority-queue - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - - - org.junit.jupiter - junit-jupiter-engine - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.priority.queue.Application - - - - - - - - - diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java deleted file mode 100644 index 9d9935ade..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Application.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.priority.queue; - -/** - * Prioritize requests sent to services so that requests with a higher priority are received and - * processed more quickly than those of a lower priority. This pattern is useful in applications - * that offer different service level guarantees to individual clients. Example :Send multiple - * message with different priority to worker queue. Worker execute higher priority message first - * - * @see "https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589794(v=pandp.10)" - */ -public class Application { - /** - * main entry. - */ - public static void main(String[] args) throws Exception { - - var queueManager = new QueueManager(10); - - // push some message to queue - // Low Priority message - for (var i = 0; i < 10; i++) { - queueManager.publishMessage(new Message("Low Message Priority", 0)); - } - - // High Priority message - for (var i = 0; i < 10; i++) { - queueManager.publishMessage(new Message("High Message Priority", 1)); - } - - // run worker - var worker = new Worker(queueManager); - worker.run(); - - - } -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Message.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Message.java deleted file mode 100644 index 09bae85b3..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Message.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.priority.queue; - -/** - * Message bean. - */ -public class Message implements Comparable { - private final String message; - private final int priority; // define message priority in queue - - - public Message(String message, int priority) { - this.message = message; - this.priority = priority; - } - - @Override - public int compareTo(Message o) { - return priority - o.priority; - } - - @Override - public String toString() { - return "Message{" - + "message='" + message + '\'' - + ", priority=" + priority - + '}'; - } -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/PriorityMessageQueue.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/PriorityMessageQueue.java deleted file mode 100644 index 09704f15e..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/PriorityMessageQueue.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.priority.queue; - -import static java.util.Arrays.copyOf; - -import lombok.extern.slf4j.Slf4j; - -/** - * Keep high Priority message on top using maxHeap. - * - * @param : DataType to push in Queue - */ -@Slf4j -public class PriorityMessageQueue { - - private int size = 0; - - private int capacity; - - - private T[] queue; - - public PriorityMessageQueue(T[] queue) { - this.queue = queue; - this.capacity = queue.length; - } - - /** - * Remove top message from queue. - */ - public T remove() { - if (isEmpty()) { - return null; - } - - final var root = queue[0]; - queue[0] = queue[size - 1]; - size--; - maxHeapifyDown(); - return root; - } - - /** - * Add message to queue. - */ - public void add(T t) { - ensureCapacity(); - queue[size] = t; - size++; - maxHeapifyUp(); - } - - /** - * Check queue size. - */ - public boolean isEmpty() { - return size == 0; - } - - - private void maxHeapifyDown() { - var index = 0; - while (hasLeftChild(index)) { - - var smallerIndex = leftChildIndex(index); - - if (hasRightChild(index) && right(index).compareTo(left(index)) > 0) { - smallerIndex = rightChildIndex(index); - } - - if (queue[index].compareTo(queue[smallerIndex]) > 0) { - break; - } else { - swap(index, smallerIndex); - } - - index = smallerIndex; - - - } - - } - - private void maxHeapifyUp() { - var index = size - 1; - while (hasParent(index) && parent(index).compareTo(queue[index]) < 0) { - swap(parentIndex(index), index); - index = parentIndex(index); - } - } - - - // index - private int parentIndex(int pos) { - return (pos - 1) / 2; - } - - private int leftChildIndex(int parentPos) { - return 2 * parentPos + 1; - } - - private int rightChildIndex(int parentPos) { - return 2 * parentPos + 2; - } - - // value - private T parent(int childIndex) { - return queue[parentIndex(childIndex)]; - } - - private T left(int parentIndex) { - return queue[leftChildIndex(parentIndex)]; - } - - private T right(int parentIndex) { - return queue[rightChildIndex(parentIndex)]; - } - - // check - private boolean hasLeftChild(int index) { - return leftChildIndex(index) < size; - } - - private boolean hasRightChild(int index) { - return rightChildIndex(index) < size; - } - - private boolean hasParent(int index) { - return parentIndex(index) >= 0; - } - - private void swap(int fpos, int tpos) { - var tmp = queue[fpos]; - queue[fpos] = queue[tpos]; - queue[tpos] = tmp; - } - - private void ensureCapacity() { - if (size == capacity) { - capacity = capacity * 2; - queue = copyOf(queue, capacity); - } - } - - /** - * For debug .. print current state of queue - */ - public void print() { - for (var i = 0; i <= size / 2; i++) { - LOGGER.info(" PARENT : " + queue[i] + " LEFT CHILD : " - + left(i) + " RIGHT CHILD :" + right(i)); - } - } - -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java deleted file mode 100644 index 2d372c7a8..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/QueueManager.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.priority.queue; - -/** - * Manage priority queue. - */ -public class QueueManager { - /* - Priority message - */ - private final PriorityMessageQueue messagePriorityMessageQueue; - - public QueueManager(int initialCapacity) { - messagePriorityMessageQueue = new PriorityMessageQueue<>(new Message[initialCapacity]); - } - - /** - * Publish message to queue. - */ - public void publishMessage(Message message) { - messagePriorityMessageQueue.add(message); - } - - - /** - * Receive message from queue. - */ - public Message receiveMessage() { - if (messagePriorityMessageQueue.isEmpty()) { - return null; - } - return messagePriorityMessageQueue.remove(); - } - - -} diff --git a/priority-queue/src/main/java/com/iluwatar/priority/queue/Worker.java b/priority-queue/src/main/java/com/iluwatar/priority/queue/Worker.java deleted file mode 100644 index 8bd3ba1e1..000000000 --- a/priority-queue/src/main/java/com/iluwatar/priority/queue/Worker.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.priority.queue; - -import lombok.extern.slf4j.Slf4j; - -/** - * Message Worker. - */ -@Slf4j -public class Worker { - - private final QueueManager queueManager; - - public Worker(QueueManager queueManager) { - this.queueManager = queueManager; - } - - /** - * Keep checking queue for message. - */ - @SuppressWarnings("squid:S2189") - public void run() throws Exception { - while (true) { - var message = queueManager.receiveMessage(); - if (message == null) { - LOGGER.info("No Message ... waiting"); - Thread.sleep(200); - } else { - processMessage(message); - } - } - } - - /** - * Process message. - */ - private void processMessage(Message message) { - LOGGER.info(message.toString()); - } - -} diff --git a/priority-queue/src/test/java/com/iluwatar/priority/queue/PriorityMessageQueueTest.java b/priority-queue/src/test/java/com/iluwatar/priority/queue/PriorityMessageQueueTest.java deleted file mode 100644 index d539e4e8a..000000000 --- a/priority-queue/src/test/java/com/iluwatar/priority/queue/PriorityMessageQueueTest.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.priority.queue; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import org.junit.jupiter.api.Test; - -/** - * Test case for order of messages - */ -class PriorityMessageQueueTest { - - - @Test - void remove() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new String[2]); - var pushMessage = "test"; - stringPriorityMessageQueue.add(pushMessage); - assertEquals(stringPriorityMessageQueue.remove(), pushMessage); - } - - @Test - void add() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new Integer[2]); - stringPriorityMessageQueue.add(1); - stringPriorityMessageQueue.add(5); - stringPriorityMessageQueue.add(10); - stringPriorityMessageQueue.add(3); - assertEquals(10, (int) stringPriorityMessageQueue.remove()); - } - - @Test - void isEmpty() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new Integer[2]); - assertTrue(stringPriorityMessageQueue.isEmpty()); - stringPriorityMessageQueue.add(1); - stringPriorityMessageQueue.remove(); - assertTrue(stringPriorityMessageQueue.isEmpty()); - } - - @Test - void testEnsureSize() { - var stringPriorityMessageQueue = new PriorityMessageQueue<>(new Integer[2]); - assertTrue(stringPriorityMessageQueue.isEmpty()); - stringPriorityMessageQueue.add(1); - stringPriorityMessageQueue.add(2); - stringPriorityMessageQueue.add(2); - stringPriorityMessageQueue.add(3); - assertEquals(3, (int) stringPriorityMessageQueue.remove()); - } -} \ No newline at end of file diff --git a/priority-queue/src/test/java/com/iluwatar/priority/queue/QueueManagerTest.java b/priority-queue/src/test/java/com/iluwatar/priority/queue/QueueManagerTest.java deleted file mode 100644 index c5f2a515b..000000000 --- a/priority-queue/src/test/java/com/iluwatar/priority/queue/QueueManagerTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.priority.queue; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -/** - * Check queue manager - */ -class QueueManagerTest { - - @Test - void publishMessage() { - var queueManager = new QueueManager(2); - var testMessage = new Message("Test Message", 1); - queueManager.publishMessage(testMessage); - var recivedMessage = queueManager.receiveMessage(); - assertEquals(testMessage, recivedMessage); - } - - @Test - void receiveMessage() { - var queueManager = new QueueManager(2); - var testMessage1 = new Message("Test Message 1", 1); - queueManager.publishMessage(testMessage1); - var testMessage2 = new Message("Test Message 2", 2); - queueManager.publishMessage(testMessage2); - var recivedMessage = queueManager.receiveMessage(); - assertEquals(testMessage2, recivedMessage); - } -} \ No newline at end of file diff --git a/reader-writer-lock/README.md b/reader-writer-lock/README.md deleted file mode 100644 index 8bd7214da..000000000 --- a/reader-writer-lock/README.md +++ /dev/null @@ -1,192 +0,0 @@ ---- -title: Reader-Writer Lock -category: Concurrency -language: en -tag: - - Asynchronous - - Concurrency - - Performance - - Resource management - - Synchronization - - Thread management ---- - -## Also known as - -* Shared-Exclusive Lock - -## Intent - -Allow concurrent access to a shared resource for read operations while limiting access for write operations to ensure data consistency. - -## Explanation - -Real world example - -> Imagine a library where patrons frequently come to read books. The library allows multiple people to read the same book simultaneously without any issues. However, when someone wants to update or correct the content of the book, the library ensures that no one else is reading the book during the update process. This ensures that the book's content remains consistent and accurate, similar to how a Reader-Writer Lock allows multiple threads to read a shared resource concurrently while restricting write access to one thread at a time. - -In plain words - -> The Reader-Writer Lock design pattern allows concurrent read access to a shared resource while ensuring exclusive write access to maintain data consistency. - -Wikipedia says - -> In computer science, a readers–writer (single-writer lock, a multi-reader lock, a push lock, or an MRSW lock) is a synchronization primitive that solves one of the readers–writers problems. - -**Programmatic Example** - -The Reader-Writer Lock design pattern allows concurrent read access to a shared resource while ensuring exclusive write access to maintain data consistency. This pattern is particularly useful in scenarios where read operations are more frequent than write operations. - -First, we have the `Reader` class. This class represents a reader that can read a shared resource when it acquires the read lock. The `run` method locks the read lock, performs the read operation, and then unlocks the read lock. - -```java -@Slf4j -public class Reader implements Runnable { - - private Lock readLock; - private String name; - private long readingTime; - - public Reader(String name, Lock readLock, long readingTime) { - this.name = name; - this.readLock = readLock; - this.readingTime = readingTime; - } - - @Override - public void run() { - readLock.lock(); - try { - read(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when reading", e); - Thread.currentThread().interrupt(); - } finally { - readLock.unlock(); - } - } - - public void read() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(readingTime); - LOGGER.info("{} finish after reading {}ms", name, readingTime); - } -} -``` - -Next, we have the `Writer` class. This class represents a writer that can write to a shared resource when it acquires the write lock. Similar to the `Reader` class, the `run` method locks the write lock, performs the write operation, and then unlocks the write lock. - -```java -public class Writer implements Runnable { - - private final Lock writeLock; - private final String name; - private final long writingTime; - - public Writer(String name, Lock writeLock, long writingTime) { - this.name = name; - this.writeLock = writeLock; - this.writingTime = writingTime; - } - - @Override - public void run() { - writeLock.lock(); - try { - write(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when writing", e); - Thread.currentThread().interrupt(); - } finally { - writeLock.unlock(); - } - } - - public void write() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(writingTime); - LOGGER.info("{} finished after writing {}ms", name, writingTime); - } -} -``` - -Finally, we have the `ReadWriteLock` class. This class controls the access to the shared resource. It allows multiple readers to access the resource concurrently if there's no writer that has the lock. On the other hand, it ensures that only one writer can access the resource at a time. - -```java -public class ReadWriteLock implements ReaderWriterLock { - - private final Object readerMutex = new Object(); - private int currentReaderCount; - private final Set globalMutex = new HashSet<>(); - private final ReadLock readerLock = new ReadLock(); - private final WriteLock writerLock = new WriteLock(); - - public Lock readLock() { - return readerLock; - } - - public Lock writeLock() { - return writerLock; - } - - private boolean doesWriterOwnThisLock() { - return globalMutex.contains(writerLock); - } - - private boolean isLockFree() { - return globalMutex.isEmpty(); - } - - private class ReadLock implements Lock { - // Implementation of the read lock - } - - private class WriteLock implements Lock { - // Implementation of the write lock - } -} -``` - -In the `App` class, we create a fixed thread pool and submit `Reader` and `Writer` tasks to it. The `Reader` tasks acquire the read lock to read the shared resource, and the `Writer` tasks acquire the write lock to write to the shared resource. - -## Class diagram - -![Reader-Writer Lock](./etc/reader-writer-lock.png "Reader-Writer Lock") - -## Applicability - -* Use when you need to manage concurrent read and write access to a shared resource. -* Suitable for systems with more frequent read operations than write operations. -* Ideal for situations where read operations can proceed concurrently but write operations require exclusive access. - -## Known Uses - -* Database management systems to allow multiple transactions to read data simultaneously while ensuring exclusive access for data modifications. -* Filesystems to manage concurrent read and write operations on files. -* In-memory caches where read access is predominant over write access. -* [ReentrantReadWriteLock in Java](https://docs.oracle.com/en/java/javase/17/docs//api/java.base/java/util/concurrent/locks/ReentrantReadWriteLock.html) - -## Consequences - -Benefits: - -* Improves performance in scenarios with a high ratio of read operations to write operations. -* Reduces contention and increases concurrency for read operations. - -Trade-offs: - -* More complex to implement compared to simple locks. -* Potential for starvation where write operations could be delayed indefinitely if read operations continue to occur. -* Requires careful handling of thread management and synchronization to avoid deadlocks and ensure data consistency. - -## Related Patterns - -* [Lockable Object](https://java-design-patterns.com/patterns/lockable-object/): Both patterns deal with managing access to shared resources, but Reader-Writer Lock allows higher concurrency for read operations. - -## Credits - -* [Concurrent Programming in Java : Design Principles and Patterns](https://amzn.to/4dIBqxL) -* [Java Concurrency in Practice](https://amzn.to/4aRMruW) -* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) -* [Readers–writer lock - Wikipedia](https://en.wikipedia.org/wiki/Readers%E2%80%93writer_lock) -* [Readers–writers_problem - Wikipedia](https://en.wikipedia.org/wiki/Readers%E2%80%93writers_problem) diff --git a/reader-writer-lock/etc/reader-writer-lock.png b/reader-writer-lock/etc/reader-writer-lock.png deleted file mode 100644 index f7b600530..000000000 Binary files a/reader-writer-lock/etc/reader-writer-lock.png and /dev/null differ diff --git a/reader-writer-lock/etc/reader-writer-lock.ucls b/reader-writer-lock/etc/reader-writer-lock.ucls deleted file mode 100644 index 920904e76..000000000 --- a/reader-writer-lock/etc/reader-writer-lock.ucls +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/reader-writer-lock/etc/reader-writer-lock.urm.puml b/reader-writer-lock/etc/reader-writer-lock.urm.puml deleted file mode 100644 index f0e33ab3c..000000000 --- a/reader-writer-lock/etc/reader-writer-lock.urm.puml +++ /dev/null @@ -1,65 +0,0 @@ -@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/reader-writer-lock/pom.xml b/reader-writer-lock/pom.xml deleted file mode 100644 index 5f0b7b3ac..000000000 --- a/reader-writer-lock/pom.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - - 4.0.0 - - com.iluwatar - java-design-patterns - 1.26.0-SNAPSHOT - - reader-writer-lock - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.mockito - mockito-core - test - - - - - - org.apache.maven.plugins - maven-assembly-plugin - - - - - - com.iluwatar.reader.writer.lock.App - - - - - - - - - diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java deleted file mode 100644 index 48ce50463..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/App.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.TimeUnit; -import lombok.extern.slf4j.Slf4j; - -/** - * In a multiple thread applications, the threads may try to synchronize the shared resources - * regardless of read or write operation. It leads to a low performance especially in a "read more - * write less" system as indeed the read operations are thread-safe to another read operation. - * - *

Reader writer lock is a synchronization primitive that try to resolve this problem. This - * pattern allows concurrent access for read-only operations, while write operations require - * exclusive access. This means that multiple threads can read the data in parallel but an exclusive - * lock is needed for writing or modifying data. When a writer is writing the data, all other - * writers or readers will be blocked until the writer is finished writing. - * - *

This example use two mutex to demonstrate the concurrent access of multiple readers and - * writers. - * - * @author hongshuwei@gmail.com - */ -@Slf4j -public class App { - - /** - * Program entry point. - * - * @param args command line args - */ - public static void main(String[] args) { - - var executeService = Executors.newFixedThreadPool(10); - var lock = new ReaderWriterLock(); - - // Start writers - for (var i = 0; i < 5; i++) { - var writingTime = ThreadLocalRandom.current().nextLong(5000); - executeService.submit(new Writer("Writer " + i, lock.writeLock(), writingTime)); - } - LOGGER.info("Writers added..."); - - // Start readers - for (var i = 0; i < 5; i++) { - var readingTime = ThreadLocalRandom.current().nextLong(10); - executeService.submit(new Reader("Reader " + i, lock.readLock(), readingTime)); - } - LOGGER.info("Readers added..."); - - try { - Thread.sleep(5000L); - } catch (InterruptedException e) { - LOGGER.error("Error sleeping before adding more readers", e); - Thread.currentThread().interrupt(); - } - - // Start readers - for (var i = 6; i < 10; i++) { - var readingTime = ThreadLocalRandom.current().nextLong(10); - executeService.submit(new Reader("Reader " + i, lock.readLock(), readingTime)); - } - LOGGER.info("More readers added..."); - - - // In the system console, it can see that the read operations are executed concurrently while - // write operations are exclusive. - executeService.shutdown(); - try { - executeService.awaitTermination(5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - Thread.currentThread().interrupt(); - } - - } - -} diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java deleted file mode 100644 index a652b8d5f..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Reader.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.concurrent.locks.Lock; -import lombok.extern.slf4j.Slf4j; - -/** - * Reader class, read when it acquired the read lock. - */ -@Slf4j -public class Reader implements Runnable { - - private final Lock readLock; - - private final String name; - - private final long readingTime; - - /** - * Create new Reader. - * - * @param name - Name of the thread owning the reader - * @param readLock - Lock for this reader - * @param readingTime - amount of time (in milliseconds) for this reader to engage reading - */ - public Reader(String name, Lock readLock, long readingTime) { - this.name = name; - this.readLock = readLock; - this.readingTime = readingTime; - } - - /** - * Create new Reader who reads for 250ms. - * - * @param name - Name of the thread owning the reader - * @param readLock - Lock for this reader - */ - public Reader(String name, Lock readLock) { - this(name, readLock, 250L); - } - - @Override - public void run() { - readLock.lock(); - try { - read(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when reading", e); - Thread.currentThread().interrupt(); - } finally { - readLock.unlock(); - } - } - - /** - * Simulate the read operation. - */ - public void read() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(readingTime); - LOGGER.info("{} finish after reading {}ms", name, readingTime); - } -} diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java deleted file mode 100644 index 4c09b1e69..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/ReaderWriterLock.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import lombok.extern.slf4j.Slf4j; - -/** - * Class responsible for control the access for reader or writer - * - *

Allows multiple readers to hold the lock at same time, but if any writer holds the lock then - * readers wait. If reader holds the lock then writer waits. This lock is not fair. - */ -@Slf4j -public class ReaderWriterLock implements ReadWriteLock { - - - private final Object readerMutex = new Object(); - - private int currentReaderCount; - - /** - * Global mutex is used to indicate that whether reader or writer gets the lock in the moment. - * - *

1. When it contains the reference of {@link #readerLock}, it means that the lock is - * acquired by the reader, another reader can also do the read operation concurrently.
2. - * When it contains the reference of reference of {@link #writerLock}, it means that the lock is - * acquired by the writer exclusively, no more reader or writer can get the lock. - * - *

This is the most important field in this class to control the access for reader/writer. - */ - private final Set globalMutex = new HashSet<>(); - - private final ReadLock readerLock = new ReadLock(); - private final WriteLock writerLock = new WriteLock(); - - @Override - public Lock readLock() { - return readerLock; - } - - @Override - public Lock writeLock() { - return writerLock; - } - - /** - * return true when globalMutex hold the reference of writerLock. - */ - private boolean doesWriterOwnThisLock() { - return globalMutex.contains(writerLock); - } - - /** - * Nobody get the lock when globalMutex contains nothing. - */ - private boolean isLockFree() { - return globalMutex.isEmpty(); - } - - /** - * Reader Lock, can be access for more than one reader concurrently if no writer get the lock. - */ - private class ReadLock implements Lock { - - @Override - public void lock() { - synchronized (readerMutex) { - currentReaderCount++; - if (currentReaderCount == 1) { - acquireForReaders(); - } - } - } - - /** - * Acquire the globalMutex lock on behalf of current and future concurrent readers. Make sure no - * writers currently owns the lock. - */ - private void acquireForReaders() { - // Try to get the globalMutex lock for the first reader - synchronized (globalMutex) { - // If the no one get the lock or the lock is locked by reader, just set the reference - // to the globalMutex to indicate that the lock is locked by Reader. - while (doesWriterOwnThisLock()) { - try { - globalMutex.wait(); - } catch (InterruptedException e) { - var message = "InterruptedException while waiting for globalMutex in acquireForReaders"; - LOGGER.info(message, e); - Thread.currentThread().interrupt(); - } - } - globalMutex.add(this); - } - } - - @Override - public void unlock() { - synchronized (readerMutex) { - currentReaderCount--; - // Release the lock only when it is the last reader, it is ensure that the lock is released - // when all reader is completely. - if (currentReaderCount == 0) { - synchronized (globalMutex) { - // Notify the waiter, mostly the writer - globalMutex.remove(this); - globalMutex.notifyAll(); - } - } - } - - } - - @Override - public void lockInterruptibly() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock(long time, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - - @Override - public Condition newCondition() { - throw new UnsupportedOperationException(); - } - - } - - /** - * Writer Lock, can only be accessed by one writer concurrently. - */ - private class WriteLock implements Lock { - - @Override - public void lock() { - synchronized (globalMutex) { - - // Wait until the lock is free. - while (!isLockFree()) { - try { - globalMutex.wait(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException while waiting for globalMutex to begin writing", e); - Thread.currentThread().interrupt(); - } - } - // When the lock is free, acquire it by placing an entry in globalMutex - globalMutex.add(this); - } - } - - @Override - public void unlock() { - synchronized (globalMutex) { - globalMutex.remove(this); - // Notify the waiter, other writer or reader - globalMutex.notifyAll(); - } - } - - @Override - public void lockInterruptibly() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean tryLock(long time, TimeUnit unit) { - throw new UnsupportedOperationException(); - } - - @Override - public Condition newCondition() { - throw new UnsupportedOperationException(); - } - } - -} diff --git a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java b/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java deleted file mode 100644 index 762f8f281..000000000 --- a/reader-writer-lock/src/main/java/com/iluwatar/reader/writer/lock/Writer.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import java.util.concurrent.locks.Lock; -import lombok.extern.slf4j.Slf4j; - -/** - * Writer class, write when it acquired the write lock. - */ -@Slf4j -public class Writer implements Runnable { - - private final Lock writeLock; - - private final String name; - - private final long writingTime; - - /** - * Create new Writer who writes for 250ms. - * - * @param name - Name of the thread owning the writer - * @param writeLock - Lock for this writer - */ - public Writer(String name, Lock writeLock) { - this(name, writeLock, 250L); - } - - /** - * Create new Writer. - * - * @param name - Name of the thread owning the writer - * @param writeLock - Lock for this writer - * @param writingTime - amount of time (in milliseconds) for this reader to engage writing - */ - public Writer(String name, Lock writeLock, long writingTime) { - this.name = name; - this.writeLock = writeLock; - this.writingTime = writingTime; - } - - - @Override - public void run() { - writeLock.lock(); - try { - write(); - } catch (InterruptedException e) { - LOGGER.info("InterruptedException when writing", e); - Thread.currentThread().interrupt(); - } finally { - writeLock.unlock(); - } - } - - /** - * Simulate the write operation. - */ - public void write() throws InterruptedException { - LOGGER.info("{} begin", name); - Thread.sleep(writingTime); - LOGGER.info("{} finished after writing {}ms", name, writingTime); - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java deleted file mode 100644 index 9dbaced75..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/AppTest.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - -/** - * Application test - */ -class AppTest { - - @Test - void shouldExecuteWithoutException() { - assertDoesNotThrow(() -> App.main(new String[]{})); - - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderAndWriterTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderAndWriterTest.java deleted file mode 100644 index bc1716146..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderAndWriterTest.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author hongshuwei@gmail.com - */ -class ReaderAndWriterTest { - - private InMemoryAppender appender; - - @BeforeEach - void setUp() { - appender = new InMemoryAppender(); - } - - @AfterEach - void tearDown() { - appender.stop(); - } - - private static final Logger LOGGER = LoggerFactory.getLogger(ReaderAndWriterTest.class); - - /** - * Verify reader and writer can only get the lock to read and write orderly - */ - @Test - void testReadAndWrite() throws Exception { - - var lock = new ReaderWriterLock(); - - var reader1 = new Reader("Reader 1", lock.readLock()); - var writer1 = new Writer("Writer 1", lock.writeLock()); - - var executeService = Executors.newFixedThreadPool(2); - executeService.submit(reader1); - // Let reader1 execute first - Thread.sleep(150); - executeService.submit(writer1); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - - assertTrue(appender.logContains("Reader 1 begin")); - assertTrue(appender.logContains("Reader 1 finish")); - assertTrue(appender.logContains("Writer 1 begin")); - assertTrue(appender.logContains("Writer 1 finish")); - } - - /** - * Verify reader and writer can only get the lock to read and write orderly - */ - @Test - void testWriteAndRead() throws Exception { - - var executeService = Executors.newFixedThreadPool(2); - var lock = new ReaderWriterLock(); - - var reader1 = new Reader("Reader 1", lock.readLock()); - var writer1 = new Writer("Writer 1", lock.writeLock()); - - executeService.submit(writer1); - // Let writer1 execute first - Thread.sleep(150); - executeService.submit(reader1); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - - assertTrue(appender.logContains("Writer 1 begin")); - assertTrue(appender.logContains("Writer 1 finish")); - assertTrue(appender.logContains("Reader 1 begin")); - assertTrue(appender.logContains("Reader 1 finish")); - } -} - diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderTest.java deleted file mode 100644 index 2fb31f36c..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/ReaderTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.spy; - -import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author hongshuwei@gmail.com - */ -class ReaderTest { - - private InMemoryAppender appender; - - @BeforeEach - void setUp() { - appender = new InMemoryAppender(Reader.class); - } - - @AfterEach - void tearDown() { - appender.stop(); - } - - private static final Logger LOGGER = LoggerFactory.getLogger(ReaderTest.class); - - /** - * Verify that multiple readers can get the read lock concurrently - */ - @Test - void testRead() throws Exception { - - var executeService = Executors.newFixedThreadPool(2); - var lock = new ReaderWriterLock(); - - var reader1 = spy(new Reader("Reader 1", lock.readLock())); - var reader2 = spy(new Reader("Reader 2", lock.readLock())); - - executeService.submit(reader1); - Thread.sleep(150); - executeService.submit(reader2); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - - // Read operation will hold the read lock 250 milliseconds, so here we prove that multiple reads - // can be performed in the same time. - assertTrue(appender.logContains("Reader 1 begin")); - assertTrue(appender.logContains("Reader 2 begin")); - assertTrue(appender.logContains("Reader 1 finish")); - assertTrue(appender.logContains("Reader 2 finish")); - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/WriterTest.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/WriterTest.java deleted file mode 100644 index 9c8422c0f..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/WriterTest.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.spy; - -import com.iluwatar.reader.writer.lock.utils.InMemoryAppender; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * @author hongshuwei@gmail.com - */ -class WriterTest { - - private InMemoryAppender appender; - - @BeforeEach - void setUp() { - appender = new InMemoryAppender(Writer.class); - } - - @AfterEach - void tearDown() { - appender.stop(); - } - - private static final Logger LOGGER = LoggerFactory.getLogger(WriterTest.class); - - /** - * Verify that multiple writers will get the lock in order. - */ - @Test - void testWrite() throws Exception { - - var executeService = Executors.newFixedThreadPool(2); - var lock = new ReaderWriterLock(); - - var writer1 = spy(new Writer("Writer 1", lock.writeLock())); - var writer2 = spy(new Writer("Writer 2", lock.writeLock())); - - executeService.submit(writer1); - // Let write1 execute first - Thread.sleep(150); - executeService.submit(writer2); - - executeService.shutdown(); - try { - executeService.awaitTermination(10, TimeUnit.SECONDS); - } catch (InterruptedException e) { - LOGGER.error("Error waiting for ExecutorService shutdown", e); - } - // Write operation will hold the write lock 250 milliseconds, so here we verify that when two - // writer execute concurrently, the second writer can only writes only when the first one is - // finished. - assertTrue(appender.logContains("Writer 1 begin")); - assertTrue(appender.logContains("Writer 1 finish")); - assertTrue(appender.logContains("Writer 2 begin")); - assertTrue(appender.logContains("Writer 2 finish")); - } -} diff --git a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java b/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java deleted file mode 100644 index f349ea382..000000000 --- a/reader-writer-lock/src/test/java/com/iluwatar/reader/writer/lock/utils/InMemoryAppender.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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. - */ -package com.iluwatar.reader.writer.lock.utils; - -import ch.qos.logback.classic.Logger; -import ch.qos.logback.classic.spi.ILoggingEvent; -import ch.qos.logback.core.AppenderBase; -import java.util.LinkedList; -import java.util.List; -import org.slf4j.LoggerFactory; - -/** - * InMemory Log Appender Util. - */ -public class InMemoryAppender extends AppenderBase { - private final List log = new LinkedList<>(); - - public InMemoryAppender(Class clazz) { - ((Logger) LoggerFactory.getLogger(clazz)).addAppender(this); - start(); - } - - public InMemoryAppender() { - ((Logger) LoggerFactory.getLogger("root")).addAppender(this); - start(); - } - - @Override - protected void append(ILoggingEvent eventObject) { - log.add(eventObject); - } - - public boolean logContains(String message) { - return log.stream().anyMatch(event -> event.getFormattedMessage().contains(message)); - } -} diff --git a/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java b/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java index 9432480d6..37ba92660 100644 --- a/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java +++ b/serialized-entity/src/test/java/com/iluwatar/serializedentity/CountryTest.java @@ -23,6 +23,8 @@ * THE SOFTWARE. */ package com.iluwatar.serializedentity; +import java.nio.file.Files; +import java.nio.file.Paths; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; @@ -101,5 +103,10 @@ public class CountryTest { } catch (Exception e) { LOGGER.error("Error occurred: ", e); } + try { + Files.deleteIfExists(Paths.get("output.txt")); + } catch (IOException e) { + LOGGER.error("Error occurred: ", e); + } } } diff --git a/type-object/etc/type-object.urm.puml b/type-object/etc/type-object.urm.puml new file mode 100644 index 000000000..42ac137e8 --- /dev/null +++ b/type-object/etc/type-object.urm.puml @@ -0,0 +1,77 @@ +@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) + ~ getName() : String + ~ getParent() : Candy + ~ getParentName() : String + ~ getPoints() : int + ~ getType() : Type + + setPoints(points : int) + } + ~enum Type { + + CRUSHABLE_CANDY {static} + + REWARD_FRUIT {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 { + + CANDY : String {static} + + FRUIT : String {static} + - LOGGER : Logger {static} + - RANDOM : SecureRandom {static} + ~ pointer : int + ~ pool : List + ~ randomCode : Candy[] + ~ CellPool(num : int) + ~ addNewCell(c : Cell) + ~ assignRandomCandytypes() : Candy[] + ~ getNewCell() : Cell + } + class JsonParser { + ~ candies : Hashtable + ~ JsonParser() + ~ parse() + ~ setParentAndPoints() + } +} +Candy --> "-type" Type +Cell --> "-candy" Candy +Candy --> "-parent" Candy +CandyGame --> "-pool" CellPool +CellPool --> "-pool" Cell +@enduml \ No newline at end of file