diff --git a/.all-contributorsrc b/.all-contributorsrc index 806d0f4d91e1..8ae01fac1c43 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -2641,7 +2641,89 @@ "contributions": [ "doc", "code" - ] + ] + }, + { + "login": "Upendra-Allagadda", + "name": "Allagadda Sai Upendranath", + "avatar_url": "https://avatars.githubusercontent.com/u/25962010?v=4", + "profile": "https://github.com/Upendra-Allagadda", + "contributions": [ + "doc" + ] + }, + { + "login": "mathbraga", + "name": "Matheus Braga", + "avatar_url": "https://avatars.githubusercontent.com/u/31048764?v=4", + "profile": "https://www.linkedin.com/in/mobraga/", + "contributions": [ + "translation", + "doc" + ] + }, + { + "login": "satyabarghav", + "name": "Appari Satya Barghav", + "avatar_url": "https://avatars.githubusercontent.com/u/36763910?v=4", + "profile": "https://github.com/satyabarghav", + "contributions": [ + "doc" + ] + }, + { + "login": "mribeirodantas", + "name": "Marcel Ribeiro-Dantas", + "avatar_url": "https://avatars.githubusercontent.com/u/1023197?v=4", + "profile": "http://mribeirodantas.me", + "contributions": [ + "doc" + ] + }, + { + "login": "hamexhanif", + "name": "Muhammad Hanif Amrullah", + "avatar_url": "https://avatars.githubusercontent.com/u/74542852?v=4", + "profile": "https://github.com/hamexhanif", + "contributions": [ + "translation" + ] + }, + { + "login": "JackH408", + "name": "JackH408", + "avatar_url": "https://avatars.githubusercontent.com/u/141727294?v=4", + "profile": "https://github.com/JackH408", + "contributions": [ + "doc" + ] + }, + { + "login": "versus2004", + "name": "Shubham", + "avatar_url": "https://avatars.githubusercontent.com/u/132815243?v=4", + "profile": "https://github.com/versus2004", + "contributions": [ + "translation" + ] + }, + { + "login": "inishantjain", + "name": "Nishant Jain", + "avatar_url": "https://avatars.githubusercontent.com/u/121454072?v=4", + "profile": "https://github.com/inishantjain", + "contributions": [ + "doc" + ] + }, + { + "login": "hallowshaw", + "name": "Rhitam Chaudhury", + "avatar_url": "https://avatars.githubusercontent.com/u/90751158?v=4", + "profile": "https://github.com/hallowshaw", + "contributions": [ + "doc" + ] } ], "contributorsPerLine": 7, diff --git a/README.md b/README.md index d64f84195251..32b3bacc1073 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - @@ -10,7 +10,7 @@ [![Coverage](https://sonarcloud.io/api/project_badges/measure?project=iluwatar_java-design-patterns&metric=coverage)](https://sonarcloud.io/dashboard?id=iluwatar_java-design-patterns) [![Join the chat at https://gitter.im/iluwatar/java-design-patterns](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/iluwatar/java-design-patterns?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![All Contributors](https://img.shields.io/badge/all_contributors-289-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-299-orange.svg?style=flat-square)](#contributors-)
@@ -448,6 +448,17 @@ This project is licensed under the terms of the MIT license. Sanchit Bansal
Sanchit Bansal

📖 Md Saiful Islam
Md Saiful Islam

📖 Antonio Addeo
Antonio Addeo

📖 💻 + Allagadda Sai Upendranath
Allagadda Sai Upendranath

📖 + Matheus Braga
Matheus Braga

🌍 📖 + Appari Satya Barghav
Appari Satya Barghav

📖 + Marcel Ribeiro-Dantas
Marcel Ribeiro-Dantas

📖 + + + Muhammad Hanif Amrullah
Muhammad Hanif Amrullah

🌍 + JackH408
JackH408

📖 + Shubham
Shubham

🌍 + Nishant Jain
Nishant Jain

📖 + Rhitam Chaudhury
Rhitam Chaudhury

📖 diff --git a/adapter/README.md b/adapter/README.md index 27d440438d61..553471816785 100644 --- a/adapter/README.md +++ b/adapter/README.md @@ -107,6 +107,8 @@ Use the Adapter pattern when * [Dzone](https://dzone.com/articles/adapter-design-pattern-in-java) * [Refactoring Guru](https://refactoring.guru/design-patterns/adapter/java/example) * [Baeldung](https://www.baeldung.com/java-adapter-pattern) +* [GeeksforGeeks](https://www.geeksforgeeks.org/adapter-pattern/) + ## Consequences Class and object adapters have different trade-offs. A class adapter diff --git a/adapter/pom.xml b/adapter/pom.xml index d54cbd048708..9307c255d09f 100644 --- a/adapter/pom.xml +++ b/adapter/pom.xml @@ -4,7 +4,7 @@ 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ä + Copyright © 2014-2023 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 diff --git a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java index 7a1706cac585..88d11e5f4703 100644 --- a/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java +++ b/aggregator-microservices/information-microservice/src/main/java/com/iluwatar/information/microservice/InformationController.java @@ -34,7 +34,7 @@ public class InformationController { /** - * Endpoint to retrieve a product's informations. + * Endpoint to retrieve a product's information. * * @return product inventory. */ diff --git a/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java b/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java index 85c2baead744..ee7a4a04b936 100644 --- a/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java +++ b/caching/src/main/java/com/iluwatar/caching/database/DbManagerFactory.java @@ -25,7 +25,7 @@ package com.iluwatar.caching.database; /** - * Creates the database connection accroding the input parameter. + * Creates the database connection according the input parameter. */ public final class DbManagerFactory { /** diff --git a/circuit-breaker/src/main/java/com/iluwatar/circuitbreaker/App.java b/circuit-breaker/src/main/java/com/iluwatar/circuitbreaker/App.java index dca32740668a..6db5ad93604d 100644 --- a/circuit-breaker/src/main/java/com/iluwatar/circuitbreaker/App.java +++ b/circuit-breaker/src/main/java/com/iluwatar/circuitbreaker/App.java @@ -29,7 +29,7 @@ /** *

* The intention of the Circuit Builder pattern is to handle remote failures robustly, which is to - * mean that if a service is dependant on n number of other services, and m of them fail, we should + * mean that if a service is dependent on n number of other services, and m of them fail, we should * be able to recover from that failure by ensuring that the user can still use the services that * are actually functional, and resources are not tied up by uselessly by the services which are not * working. However, we should also be able to detect when any of the m failing services become diff --git a/circuit-breaker/src/test/java/com/iluwatar/circuitbreaker/DefaultCircuitBreakerTest.java b/circuit-breaker/src/test/java/com/iluwatar/circuitbreaker/DefaultCircuitBreakerTest.java index 817a1e7d0bcf..465371a3aad3 100644 --- a/circuit-breaker/src/test/java/com/iluwatar/circuitbreaker/DefaultCircuitBreakerTest.java +++ b/circuit-breaker/src/test/java/com/iluwatar/circuitbreaker/DefaultCircuitBreakerTest.java @@ -74,7 +74,7 @@ public String call() throws RemoteServiceException { } }; var circuitBreaker = new DefaultCircuitBreaker(mockService, 1, 1, 100); - //Call with the paramater start_time set to huge amount of time in past so that service + //Call with the parameter start_time set to huge amount of time in past so that service //replies with "Ok". Also, state is CLOSED in start var serviceStartTime = System.nanoTime() - 60 * 1000 * 1000 * 1000; var response = circuitBreaker.attemptRequest(); diff --git a/commander/README.md b/commander/README.md index 334bc4463d09..472370f4bbe1 100644 --- a/commander/README.md +++ b/commander/README.md @@ -18,7 +18,7 @@ This pattern can be used when we need to make commits into 2 (or more) databases ## Explanation Handling distributed transactions can be tricky, but if we choose to not handle it carefully, there could be unwanted consequences. Say, we have an e-commerce website which has a Payment microservice and a Shipping microservice. If the shipping is available currently but payment service is not up, or vice versa, how would we deal with it after having already received the order from the user? -We need a mechanism in place which can handle these kinds of situations. We have to direct the order to either one of the services (in this example, shipping) and then add the order into the database of the other service (in this example, payment), since two databses cannot be updated atomically. If currently unable to do it, there should be a queue where this request can be queued, and there has to be a mechanism which allows for a failure in the queueing as well. All this needs to be done by constant retries while ensuring idempotence (even if the request is made several times, the change should only be applied once) by a commander class, to reach a state of eventual consistency. +We need a mechanism in place which can handle these kinds of situations. We have to direct the order to either one of the services (in this example, shipping) and then add the order into the database of the other service (in this example, payment), since two databases cannot be updated atomically. If currently unable to do it, there should be a queue where this request can be queued, and there has to be a mechanism which allows for a failure in the queueing as well. All this needs to be done by constant retries while ensuring idempotence (even if the request is made several times, the change should only be applied once) by a commander class, to reach a state of eventual consistency. ## Credits diff --git a/crtp/README.md b/crtp/README.md index 89f0720a8ebe..67627f44da7f 100644 --- a/crtp/README.md +++ b/crtp/README.md @@ -134,5 +134,5 @@ Use the Curiously Recurring Template Pattern when ## Credits -* [How do I decrypt "Enum>"?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106) +* [How do I decrypt "Enum>"?](http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeParameters.html#FAQ106) * Chapter 5 Generics, Item 30 in [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) diff --git a/currying/README.md b/currying/README.md index 044c5df03d1a..9f32c9066e06 100644 --- a/currying/README.md +++ b/currying/README.md @@ -183,7 +183,7 @@ Cons * As shown in the programmatic example above, curried functions with several parameters have a cumbersome type signature (in Java). ## Related patterns -* [Builder patter](https://java-design-patterns.com/patterns/builder/) +* [Builder pattern](https://java-design-patterns.com/patterns/builder/) ## Credits * [Currying in Java](https://www.baeldung.com/java-currying) diff --git a/data-mapper/src/main/java/com/iluwatar/datamapper/DataMapperException.java b/data-mapper/src/main/java/com/iluwatar/datamapper/DataMapperException.java index 0d96a9b3cb4e..3e5419286f70 100644 --- a/data-mapper/src/main/java/com/iluwatar/datamapper/DataMapperException.java +++ b/data-mapper/src/main/java/com/iluwatar/datamapper/DataMapperException.java @@ -25,7 +25,7 @@ package com.iluwatar.datamapper; /** - * Using Runtime Exception for avoiding dependancy on implementation exceptions. This helps in + * Using Runtime Exception for avoiding dependency on implementation exceptions. This helps in * decoupling. * * @author amit.dixit diff --git a/embedded-value/src/main/java/com/iluwatar/embedded/value/App.java b/embedded-value/src/main/java/com/iluwatar/embedded/value/App.java index 3a51629601fd..37ec26179c5c 100644 --- a/embedded-value/src/main/java/com/iluwatar/embedded/value/App.java +++ b/embedded-value/src/main/java/com/iluwatar/embedded/value/App.java @@ -62,7 +62,7 @@ public static void main(String[] args) throws Exception { // Create table for orders - Orders(id, name, orderedBy, city, state, pincode). // We can see that table is different from the Order object we have. - // We're mapping ShippingAddress into city, state, pincode colummns of the database and not creating a separate table. + // We're mapping ShippingAddress into city, state, pincode columns of the database and not creating a separate table. if (dataSource.createSchema()) { LOGGER.info("TABLE CREATED"); LOGGER.info("Table \"Orders\" schema:\n" + dataSource.getSchema()); @@ -95,7 +95,7 @@ public static void main(String[] args) throws Exception { dataSource.removeOrder(1); LOGGER.info("\nOrders Query: {}", dataSource.queryOrders().collect(Collectors.toList()) + "\n"); - //After successfull demonstration of the pattern, drop the table + //After successful demonstration of the pattern, drop the table if (dataSource.deleteSchema()) { LOGGER.info("TABLE DROPPED"); } else { diff --git a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java index f668b61c7055..242e6fbddd51 100644 --- a/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java +++ b/event-queue/src/main/java/com/iluwatar/event/queue/Audio.java @@ -144,7 +144,7 @@ private void update() { clip.open(audioStream); clip.start(); } catch (LineUnavailableException e) { - LOGGER.trace("Error occoured while loading the audio: The line is unavailable", e); + LOGGER.trace("Error occurred while loading the audio: The line is unavailable", e); } catch (IOException e) { LOGGER.trace("Input/Output error while loading the audio", e); } catch (IllegalArgumentException e) { diff --git a/facade/README.md b/facade/README.md index 4090f89b8fc5..4efa8f7b76c7 100644 --- a/facade/README.md +++ b/facade/README.md @@ -212,6 +212,15 @@ subsystem independence and portability. If subsystems are dependent, then you can simplify the dependencies between them by making them communicate with each other solely through their facades. +## Tutorials + +*[DigitalOcean](https://www.digitalocean.com/community/tutorials/facade-design-pattern-in-java) +* [Refactoring Guru](https://refactoring.guru/design-patterns/facade) +* [GeekforGeeks](https://www.geeksforgeeks.org/facade-design-pattern-introduction/) +* [Tutorialspoint](https://www.tutorialspoint.com/design_pattern/facade_pattern.htm) + + + ## Credits * [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) diff --git a/factory/README.md b/factory/README.md index f6fa1b5a033a..ed841bd0e2da 100644 --- a/factory/README.md +++ b/factory/README.md @@ -60,7 +60,7 @@ public class CopperCoin implements Coin { } ``` -Enumeration above represents types of coins that we support (`GoldCoin` and `CopperCoin`). +Enumeration below represents types of coins that we support (`GoldCoin` and `CopperCoin`). ```java @RequiredArgsConstructor @@ -110,7 +110,7 @@ This is a gold coin. ## Applicability -Use the factory pattern when you only care about the creation of a object, not how to create +Use the factory pattern when you only care about the creation of an object, not how to create and manage it. Pros diff --git a/fanout-fanin/README.md b/fanout-fanin/README.md index 9f48160f9483..5d519528c6fb 100644 --- a/fanout-fanin/README.md +++ b/fanout-fanin/README.md @@ -18,7 +18,7 @@ service has received the requests. Now the caller will not wait or expect the re Meanwhile, the pattern service will invoke the requests that have come. The requests might complete at different time. These requests will be processed in different instances of the same function in different machines or services. As the -requests get completed, a callback service everytime is called that transforms the result into a common single object format +requests get completed, a callback service every time is called that transforms the result into a common single object format that gets pushed to a consumer. The caller will be at the other end of the consumer receiving the result. **Programmatic Example** diff --git a/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/Consumer.java b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/Consumer.java index acb1f2a054da..90b7c63855e3 100644 --- a/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/Consumer.java +++ b/fanout-fanin/src/main/java/com/iluwatar/fanout/fanin/Consumer.java @@ -30,7 +30,7 @@ /** - * Consumer or callback class that will be called everytime a request is complete This will + * Consumer or callback class that will be called every time a request is complete This will * aggregate individual result to form a final result. */ @Getter diff --git a/feature-toggle/README.md b/feature-toggle/README.md index 915a255690da..982108bc7440 100644 --- a/feature-toggle/README.md +++ b/feature-toggle/README.md @@ -10,10 +10,53 @@ tag: Feature Flag ## Intent -Used to switch code execution paths based on properties or groupings. Allowing new features to be released, tested -and rolled out. Allowing switching back to the older feature quickly if needed. It should be noted that this pattern, -can easily introduce code complexity. There is also cause for concern that the old feature that the toggle is eventually -going to phase out is never removed, causing redundant code smells and increased maintainability. +A technique used in software development to control and manage the rollout of specific features or functionality in a +program without changing the code. It can act as an on/off switch for features depending on the status or properties of +other values in the program. This is similar to A/B testing, where features are rolled out based on properties such as +location or device. Implementing this design pattern can increase code complexity, and it is important to remember to +remove redundant code if this design pattern is being used to phase out a system or feature. + +## Explanation +Real-world Example +> This design pattern works really well in any sort of development, in particular mobile development. Say you want to +> introduce a feature such as dark mode, but you want to ensure that the feature works correctly and don't want to roll +> out the feature to everyone immediately. You write in the code, and have it switched off as default. From here, it is +> easy to turn on the code for specific users based on selection criteria, or randomly. This will also allow the feature +> to be turned off easily without any drastic changes to the code, or any need for redeployment or updates. + +In plain words +> Feature Toggle is a way to introduce new features gradually instead of deployment all at once. + +Wikipedia says +> A feature toggle in software development provides an alternative to maintaining multiple feature branches in source +> code. A condition within the code enables or disables a feature during runtime. In agile settings the toggle is +> used in production, to switch on the feature on demand, for some or all the users. + +## Programmatic Example +This example shows Java code that allows a feature to show when it is enabled by the developer, and when a user is a +Premium member of the application. This is useful for subscription locked features. +```java +public class FeatureToggleExample { + // Bool for feature enabled or disabled + private static boolean isNewFeatureEnabled = false; + + public static void main(String[] args) { + boolean userIsPremium = true; // Example: Check if the user is a premium user + + // Check if the new feature should be enabled for the user + if (userIsPremium && isNewFeatureEnabled) { + // User is premium and the new feature is enabled + showNewFeature(); + } + } + + private static void showNewFeature() { + // If user is allowed to see locked feature, this is where the code would go + } +} +``` +The code shows how simple it is to implement this design pattern, and the criteria can be further refined or broadened +should the developers choose to do so. ## Class diagram ![alt text](./etc/feature-toggle.png "Feature Toggle") @@ -24,7 +67,20 @@ Use the Feature Toggle pattern when * Giving different features to different users. * Rolling out a new feature incrementally. * Switching between development and production environments. +* Quickly disable problematic features +* External management of feature deployment +* Ability to maintain multiple version releases of a feature +* 'Hidden' deployment, releasing a feature in code for designated testing but not publicly making it available + +## Consequences +Consequences involved with using the Feature Toggle pattern + +* Code complexity is increased +* Testing of multiple states is harder and more time-consuming +* Confusion between friends on why features are missing +* Keeping documentation up to date with all features can be difficult ## Credits * [Martin Fowler 29 October 2010 (2010-10-29).](http://martinfowler.com/bliki/FeatureToggle.html) +* [Feature Toggle - Java Design Patterns](https://java-design-patterns.com/patterns/feature-toggle/) diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java index 1f5359e195ae..421f86e4c2eb 100644 --- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java +++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/App.java @@ -39,8 +39,8 @@ * version of the feature toggle, where the enhanced version of the welcome message which is * personalised is turned either on or off at instance creation. This method is not as dynamic as * the {@link User} driven version where the feature of the personalised welcome message is - * dependant on the {@link UserGroup} the {@link User} is in. So if the user is a memeber of the - * {@link UserGroup#isPaid(User)} then they get an ehanced version of the welcome message. + * dependent on the {@link UserGroup} the {@link User} is in. So if the user is a member of the + * {@link UserGroup#isPaid(User)} then they get an enhanced version of the welcome message. * *

Note that this pattern can easily introduce code complexity, and if not kept in check can * result in redundant unmaintained code within the codebase. diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java index e70a581a6c5e..ce7886a10039 100644 --- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java +++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/propertiesversion/PropertiesFeatureToggleVersion.java @@ -30,7 +30,7 @@ import lombok.Getter; /** - * This example of the Feature Toogle pattern is less dynamic version than {@link + * This example of the Feature Toggle pattern is less dynamic version than {@link * com.iluwatar.featuretoggle.pattern.tieredversion.TieredFeatureToggleVersion} where the feature is * turned on or off at the time of creation of the service. This example uses simple Java {@link * Properties} however it could as easily be done with an external configuration file loaded by diff --git a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java index f846f990c9d9..74eb44340940 100644 --- a/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java +++ b/feature-toggle/src/main/java/com/iluwatar/featuretoggle/pattern/tieredversion/TieredFeatureToggleVersion.java @@ -29,7 +29,7 @@ import com.iluwatar.featuretoggle.user.UserGroup; /** - * This example of the Feature Toogle pattern shows how it could be implemented based on a {@link + * This example of the Feature Toggle pattern shows how it could be implemented based on a {@link * User}. Therefore showing its use within a tiered application where the paying users get access to * different content or better versions of features. So in this instance a {@link User} is passed in * and if they are found to be on the {@link UserGroup#isPaid(User)} they are welcomed with a diff --git a/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java b/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java index 21a49f625e5c..995f917b3fd5 100644 --- a/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java +++ b/front-controller/src/main/java/com/iluwatar/front/controller/FrontController.java @@ -38,7 +38,7 @@ public void handleRequest(String request) { private Command getCommand(String request) { var commandClass = getCommandClass(request); try { - return (Command) commandClass.newInstance(); + return (Command) commandClass.getDeclaredConstructor().newInstance(); } catch (Exception e) { throw new ApplicationException(e); } diff --git a/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractMessageManager.java b/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractMessageManager.java index eab9787d80a2..82f89f89c8fa 100644 --- a/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractMessageManager.java +++ b/leader-election/src/main/java/com/iluwatar/leaderelection/AbstractMessageManager.java @@ -37,7 +37,7 @@ public abstract class AbstractMessageManager implements MessageManager { protected Map instanceMap; /** - * Construtor of AbstractMessageManager. + * Constructor of AbstractMessageManager. */ public AbstractMessageManager(Map instanceMap) { this.instanceMap = instanceMap; diff --git a/localization/hi/module/README.md b/localization/hi/module/README.md new file mode 100644 index 000000000000..8d8a78ae4aa3 --- /dev/null +++ b/localization/hi/module/README.md @@ -0,0 +1,27 @@ +--- +title: Module +category: Structural +language: hi +tag: + - Decoupling + - Cloud distributed +--- + +## हेतु + +मॉड्यूल पैटर्न का उपयोग सॉफ़्टवेयर मॉड्यूल की अवधारणा को लागू करने के लिए किया जाता है, जिसे मॉड्यूलर प्रोग्रामिंग द्वारा परिभाषित किया जाता है, एक प्रोग्रामिंग भाषा में जो अवधारणा के लिए अपूर्ण प्रत्यक्ष समर्थन प्रदान करती है। + +## क्लास डायग्राम + + +![alt text](../../../module/etc/module.png "Module class diagram") + +## प्रयोज्यता + +मॉड्यूल पैटर्न को एक क्रिएशनल पैटर्न और एक स्ट्रक्चरल पैटर्न माना जा सकता है। यह अन्य तत्वों के निर्माण और संगठन को प्रबंधित करता है, और उन्हें स्ट्रक्चरल पैटर्न की तरह समूहों में विभाजित करता है। + +इस पैटर्न को लागू करने वाली कोई वस्तु एक नामस्थान के समकक्ष प्रदान कर सकती है, जो एक स्थैतिक वर्ग या स्थैतिक सदस्यों वाले वर्ग के आरंभीकरण और अंतिमकरण प्रक्रिया को क्लीनर, अधिक संक्षिप्त वाक्यविन्यास और अर्थशास्त्र के साथ प्रदान करती है। + +## श्रेय + +* [Module](https://en.wikipedia.org/wiki/Module_pattern) diff --git a/localization/id/decorator/README.md b/localization/id/decorator/README.md new file mode 100644 index 000000000000..1fe3d89241ba --- /dev/null +++ b/localization/id/decorator/README.md @@ -0,0 +1,169 @@ +--- +title: Decorator +category: Structural +language: id +tag: + - Gang of Four + - Extensibility +--- + +## Juga dikenal sebagai + +Pembungkus + +## Tujuan + +Menyematkan tanggung jawab tambahan ke suatu objek secara dinamis. Dekorator memberikan alternatif yang fleksibel terhadap subkelas untuk memperluas fungsionalitas. + +## Penjelasan + +Contoh dunia nyata + +> Ada troll pemarah yang tinggal di perbukitan terdekat. Biasanya ia pergi dengan tangan kosong, tetapi terkadang ia +> punya senjata. Untuk mempersenjatai troll, Anda tidak perlu membuat troll baru, melainkan mendekorasinya +> secara dinamis dengan senjata yang sesuai. + +Dengan kata sederhana + +> Pola dekorator memungkinkan Anda mengubah perilaku objek secara dinamis saat run time dengan membungkus +> mereka dalam objek kelas dekorator. + +Wikipedia(en) mengatakan + +> Dalam pemrograman berorientasi objek, pola dekorator adalah pola desain yang memungkinkan perilaku +> ditambahkan ke objek individual, baik secara statis maupun dinamis, tanpa memengaruhi perilaku +> objek lain dari kelas yang sama. Pola dekorator sering kali berguna untuk mematuhi Prinsip Tanggung +> Jawab Tunggal, karena memungkinkan fungsionalitas dibagi antara kelas-kelas dengan area perhatian yang +> unik serta Prinsip Terbuka-Tertutup, dengan memungkinkan fungsionalitas suatu kelas diperluas tanpa diubah. + +**Contoh Program** + +Mari kita ambil contoh troll. Pertama-tama kita memiliki `SimpleTroll` yang mengimplementasikan antarmuka +`Troll`: + +```java +public interface Troll { + void attack(); + int getAttackPower(); + void fleeBattle(); +} + +@Slf4j +public class SimpleTroll implements Troll { + + @Override + public void attack() { + LOGGER.info("Troll itu mencoba menangkapmu!"); + } + + @Override + public int getAttackPower() { + return 10; + } + + @Override + public void fleeBattle() { + LOGGER.info("Troll itu menjerit ketakutan dan melarikan diri!"); + } +} +``` + +Kemudian kita ingin menambahkan gada untuk troll tersebut. Kita dapat melakukannya secara dinamis dengan menggunakan dekorator: + +```java +@Slf4j +public class ClubbedTroll implements Troll { + + private final Troll decorated; + + public ClubbedTroll(Troll decorated) { + this.decorated = decorated; + } + + @Override + public void attack() { + decorated.attack(); + LOGGER.info("Troll itu mengayunkan gada ke arahmu!"); + } + + @Override + public int getAttackPower() { + return decorated.getAttackPower() + 10; + } + + @Override + public void fleeBattle() { + decorated.fleeBattle(); + } +} +``` + +Berikut aksi troll tersebut: + +```java +// simple troll +LOGGER.info("Troll biasa mendekat."); +var troll = new SimpleTroll(); +troll.attack(); +troll.fleeBattle(); +LOGGER.info("Kekuatan troll sederhana: {}.\n", troll.getAttackPower()); + +// change the behavior of the simple troll by adding a decorator +LOGGER.info("Troll dengan gada besar mengejutkanmu."); +var clubbedTroll = new ClubbedTroll(troll); +clubbedTroll.attack(); +clubbedTroll.fleeBattle(); +LOGGER.info("Kekuatan troll dengan gada: {}.\n", clubbedTroll.getAttackPower()); +``` + +Output program: + +```java +Troll biasa mendekat. +Troll itu mencoba menangkapmu! +Troll itu menjerit ketakutan dan melarikan diri! +Kekuatan troll sederhana: 10. + +Troll dengan gada besar mengejutkanmu. +Troll itu mencoba menangkapmu! +Troll itu mengayunkan gada ke arahmu! +Troll itu menjerit ketakutan dan melarikan diri! +Kekuatan troll dengan gada: 20. +``` + +## Diagram kelas + +![alt text](./etc/decorator.urm.png "Diagram kelas pola dekorator") + +## Penerapan + +Dekorator digunakan untuk: + +* Tambahkan tanggung jawab ke objek individual secara dinamis dan transparan, tanpa +memengaruhi objek lain. +* Untuk tanggung jawab yang dapat ditarik/dihapus. +* Dimana ekstensi dengan subkelas tidak praktis; Ketika sejumlah besar ekstensi independen +mungkin dilakukan dan akan menghasilkan ledakan subkelas untuk mendukung setiap kombinasi, atau definisi +kelas mungkin tersembunyi dan/atau tidak tersedia untuk subkelas. + +## Tutorial + +* [Tutorial Pola Dekorator](https://www.journaldev.com/1540/decorator-design-pattern-in-java-example) + +## Kegunaan yang diketahui + + * [java.io.InputStream](http://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html), [java.io.OutputStream](http://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html), + [java.io.Reader](http://docs.oracle.com/javase/8/docs/api/java/io/Reader.html) dan [java.io.Writer](http://docs.oracle.com/javase/8/docs/api/java/io/Writer.html) + * [java.util.Collections#synchronizedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#synchronizedCollection-java.util.Collection-) + * [java.util.Collections#unmodifiableXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableCollection-java.util.Collection-) + * [java.util.Collections#checkedXXX()](http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#checkedCollection-java.util.Collection-java.lang.Class-) + + +## Kredit + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) +* [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31) +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) +* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) +* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=f27d2644fbe5026ea448791a8ad09c94) diff --git a/localization/id/decorator/etc/decorator.urm.png b/localization/id/decorator/etc/decorator.urm.png new file mode 100644 index 000000000000..141c0563f0c6 Binary files /dev/null and b/localization/id/decorator/etc/decorator.urm.png differ diff --git a/localization/pt/factory/README.md b/localization/pt/factory/README.md new file mode 100644 index 000000000000..296c1b758b0c --- /dev/null +++ b/localization/pt/factory/README.md @@ -0,0 +1,141 @@ +--- +title: Factory +category: Creational +language: pt +tag: + - Gang of Four +--- + +## Também conhecido como + +* Simple Factory +* Static Factory Method + +## Propósito + +Fornecer um método estático encapsulado em uma classe conhecida como factory, para ocultar a lógica +de implementação e fazer com que o código do cliente se preocupe apenas com sua utilização em vez de +inicializar novos objetos. + +## Explicação + +Exemplo de mundo real + +> Imagine um alquimista que está prestes a fabricar moedas. O alquimista deve ser capaz de produzir +> moedas de ouro e cobre, e a alternância entre a fabricação destas deve ser possível sem a necessidade +> de modificar o código fonte. O padrão factory torna isso possível fornecendo um método construtor estático +> que pode ser chamado com parâmetros relevantes. + +Wikipedia diz + +> Factory é um objeto para a criação de outros objetos - formalmente uma factory é uma função ou método +> que retorna objetos de protótipos ou classes variadas. + +**Exemplo de programação** + +Temos uma interface `Coin` e duas implementações `GoldCoin` e `CopperCoin`. + +```java +public interface Coin { + String getDescription(); +} + +public class GoldCoin implements Coin { + + static final String DESCRIPTION = "This is a gold coin."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} + +public class CopperCoin implements Coin { + + static final String DESCRIPTION = "This is a copper coin."; + + @Override + public String getDescription() { + return DESCRIPTION; + } +} +``` + +O enum abaixo representa os tipos de moedas que suportamos (`GoldCoin` e `CopperCoin`). + +```java +@RequiredArgsConstructor +@Getter +public enum CoinType { + + COPPER(CopperCoin::new), + GOLD(GoldCoin::new); + + private final Supplier constructor; +} +``` + +Então temos o método estático `getCoin` para criar objetos de moeda encapsulados na classe factory +`CoinFactory`. + +```java +public class CoinFactory { + + public static Coin getCoin(CoinType type) { + return type.getConstructor().get(); + } +} +``` + +Agora no código cliente podemos criar diferentes tipos de moedas usando a classe factory. + +```java +LOGGER.info("The alchemist begins his work."); +var coin1 = CoinFactory.getCoin(CoinType.COPPER); +var coin2 = CoinFactory.getCoin(CoinType.GOLD); +LOGGER.info(coin1.getDescription()); +LOGGER.info(coin2.getDescription()); +``` + +Saída do programa: + +```java +The alchemist begins his work. +This is a copper coin. +This is a gold coin. +``` + +## Diagrama de classes + +![alt text](./etc/factory.urm.png "Diagrama de classes do padrão Factory") + +## Aplicabilidade + +Utilize o padrão factory quando a preocupação é apenas em criar o objeto, e não como criar +e gerenciá-lo. + +Prós + +* Permite manter a criação de todos os objetos em um só lugar e evita espalhar a palavra-chave 'new' pela base de código. +* Permite escrever código desacoplado. Algumas de suas principais vantagens incluem uma melhor testabilidade, código fácil de entender, componentes substituíveis, escalabilidade e funcionalidades isoladas. + +Contras + +* O código se torna mais complicado do que deveria. + +## Usos conhecidos + +* [java.util.Calendar#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html#getInstance--) +* [java.util.ResourceBundle#getBundle()](https://docs.oracle.com/javase/8/docs/api/java/util/ResourceBundle.html#getBundle-java.lang.String-) +* [java.text.NumberFormat#getInstance()](https://docs.oracle.com/javase/8/docs/api/java/text/NumberFormat.html#getInstance--) +* [java.nio.charset.Charset#forName()](https://docs.oracle.com/javase/8/docs/api/java/nio/charset/Charset.html#forName-java.lang.String-) +* [java.net.URLStreamHandlerFactory#createURLStreamHandler(String)](https://docs.oracle.com/javase/8/docs/api/java/net/URLStreamHandlerFactory.html) (retorna objetos singleton diferentes, dependendo do protocolo) +* [java.util.EnumSet#of()](https://docs.oracle.com/javase/8/docs/api/java/util/EnumSet.html#of(E)) +* [javax.xml.bind.JAXBContext#createMarshaller()](https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/JAXBContext.html#createMarshaller--) e outros métodos parecidos. + +## Padrões relacionados + +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/) +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) +* [Abstract Factory](https://java-design-patterns.com/patterns/abstract-factory/) + diff --git a/localization/vi/aggregator-microservices/README.md b/localization/vi/aggregator-microservices/README.md new file mode 100644 index 000000000000..b36a388fc9cb --- /dev/null +++ b/localization/vi/aggregator-microservices/README.md @@ -0,0 +1,102 @@ +--- +title: Microservices Tổng Hợp +category: Architectural +language: vi +tag: +- Cloud distributed +- Decoupling +- Microservices +--- + +## Mục Đích +Người dùng chỉ cần thực hiện một lần gọi duy nhất đến dịch vụ tổng hợp, sau đó dịch vụ tổng hợp sẽ gọi dịch vụ con tương ứng. + +## Giải Thích + +Ví dụ thực tế + +> Trang web thị trường của chúng ta cần thông tin về sản phẩm và tồn kho hiện tại của chúng. Nó thực hiện gọi đến dịch vụ tổng hợp, sau đó dịch vụ tổng hợp gọi dịch vụ thông tin sản phẩm và dịch vụ tồn kho sản phẩm, cuối cùng trả lại thông tin kết hợp. + +## Nói đơn giản hơn + +> Microservices Tổng Hợp thu thập các phần dữ liệu từ các dịch vụ con khác nhau và trả về một tổng hợp để xử lý. + +Theo Stack Overflow + +> Microservices Tổng Hợp gọi nhiều dịch vụ để đạt được chức năng được yêu cầu bởi ứng dụng. + +**Mã nguồn mẫu** + +Hãy bắt đầu từ mô hình dữ liệu. Đây là lớp `Product` của chúng ta. + +```java +public class Product { + private String title; + private int productInventories; + // getters and setters -> + ... +} +``` + +Tiếp theo, chúng ta có thể giới thiệu Microservices `Aggregator` của chúng ta. Nó chứa các khách hàng `ProductInformationClient` và +`ProductInventoryClient` để gọi các dịch vụ con tương ứng. + +```java +@RestController +public class Aggregator { + + @Resource + private ProductInformationClient informationClient; + + @Resource + private ProductInventoryClient inventoryClient; + + @RequestMapping(path = "/product", method = RequestMethod.GET) + public Product getProduct() { + + var product = new Product(); + var productTitle = informationClient.getProductTitle(); + var productInventory = inventoryClient.getProductInventories(); + + //Fallback to error message + product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed")); + + //Fallback to default error inventory + product.setProductInventories(requireNonNullElse(productInventory, -1)); + + return product; + } +} +``` + +Dưới đây là bản thể của việc triển khai dịch vụ thông tin sản phẩm. Dịch vụ tồn kho cũng tương tự như thế, nó chỉ trả về số lượng tồn kho. + +```java +@RestController +public class InformationController { + @RequestMapping(value = "/information", method = RequestMethod.GET) + public String getProductTitle() { + return "The Product Title."; + } +} +``` + +Bây giờ, việc gọi `Aggregator` API REST của chúng ta sẽ trả về thông tin sản phẩm. + +```bash +curl http://localhost:50004/product +{"title":"The Product Title.","productInventories":5} +``` + +## Sơ Đồ Lớp +![alt text](../../../aggregator-microservices/aggregator-service/etc/aggregator-service.png "Aggregator Microservice") + + +## Các Trường Hợp Sử Dụng +Sử dụng mẫu Microservices Tổng Hợp khi bạn cần một API chung cho các dịch vụ Microservices khác nhau, bất kể thiết bị của khách hàng. + +## Người Đóng Góp + +* [Microservice Design Patterns](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/) +* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60) +* [Architectural Patterns: Uncover essential patterns in the most indispensable realm of enterprise architecture](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4) diff --git a/model-view-viewmodel/README.md b/model-view-viewmodel/README.md index 859a14fa6f0a..ab8b20628934 100644 --- a/model-view-viewmodel/README.md +++ b/model-view-viewmodel/README.md @@ -114,7 +114,6 @@ To deploy the example, go to model-view-viewmodel folder and run: ## Tutorials * [Zkoss Demo](https://www.zkoss.org/zkdemo/getting_started/mvvm) -* [Learn MVVM](https://www.learnmvvm.com/) * [Data Binding in Android](https://developer.android.com/codelabs/android-databinding#0) ## Typical Use Case diff --git a/object-mother/README.md b/object-mother/README.md index 99d49af4b04d..4f2a6664cd48 100644 --- a/object-mother/README.md +++ b/object-mother/README.md @@ -7,7 +7,7 @@ tag: --- ## Object Mother -Define a factory of immutable content with separated builder and factory interfaces. +It is used to define a factory of immutable content with separated builder and factory interfaces. ## Class diagram ![alt text](./etc/object-mother.png "Object Mother") @@ -19,6 +19,69 @@ Use the Object Mother pattern when * You want to reduce code for creation of objects in tests * Every test should run with fresh data + +## Understanding the Object Mother Pattern + +### Real-World Scenario +Imagine you're developing a Java application for a travel agency. In your system, there are different types of travelers, such as tourists, business travelers, and travel agents, each with specific attributes and behaviors. To perform thorough testing, you need to create and manipulate these traveler objects in various contexts. The Object Mother Pattern can help you generate consistent and predefined traveler objects for testing purposes, ensuring that your tests are based on known, reliable data. + +### In Plain Terms +The Object Mother Pattern is a design pattern used in Java to simplify the creation of objects with specific configurations, especially for testing. Instead of manually constructing objects with varying properties for each test case, you create a dedicated "Object Mother" class or method that produces these objects with predefined settings. This ensures that you have consistent and predictable test data, making your tests more reliable and easier to manage. + +### Overview from a Testing Perspective +The Object Mother Pattern is a testing-related design pattern that assists in maintaining a consistent and reliable testing environment. It allows you to define and create objects with specific attributes, helping you ensure that your tests produce consistent and predictable results, making it easier to spot issues and maintain your test suite. + +### Practical Usage in Testing +In software testing, especially unit testing, the Object Mother Pattern is invaluable. It helps ensure that your tests are not influenced by unpredictable data, thus making your tests more robust and repeatable. By centralizing the creation of test objects in an Object Mother, you can easily adapt your test data to different scenarios. + +### Example in Java +Here's an illustrative Java example of the Object Mother Pattern within the context of a travel agency application: + +```java +class Traveler { + private String name; + private int age; + private boolean isBusinessTraveler; + + // Constructor and methods for the traveler + // ... + + // Getter and setter methods + // ... +} + +class TravelerMother { + public static Traveler createTourist(String name, int age) { + Traveler traveler = new Traveler(); + traveler.setName(name); + traveler.setAge(age); + traveler.setBusinessTraveler(false); + return traveler; + } + + public static Traveler createBusinessTraveler(String name, int age) { + Traveler traveler = new Traveler(); + traveler.setName(name); + traveler.setAge(age); + traveler.setBusinessTraveler(true); + return traveler; + } +} + +public class TravelAgency { + public static void main(String[] args) { + // Using the Object Mother to create traveler objects for testing + Traveler tourist = TravelerMother.createTourist("Alice", 28); + Traveler businessTraveler = TravelerMother.createBusinessTraveler("Bob", 35); + + // Now you have consistent traveler objects for testing. + } +} + +``` + +In this example, TravelerMother is the Object Mother class responsible for generating predefined Traveler objects with specific configurations. This approach ensures that you have consistent test data for various scenarios in a travel agency application, enhancing the reliability and effectiveness of your testing efforts. + ## Credits * [Answer by David Brown](http://stackoverflow.com/questions/923319/what-is-an-objectmother) to the stackoverflow question: [What is an ObjectMother?](http://stackoverflow.com/questions/923319/what-is-an-objectmother) diff --git a/page-object/README.md b/page-object/README.md index 87046a85d917..93777ad2e032 100644 --- a/page-object/README.md +++ b/page-object/README.md @@ -6,13 +6,69 @@ tag: - Decoupling --- +# Page Object Pattern in Java + +## Real World Example + +Consider a web automation scenario where you need to interact with a web page using a test framework like Selenium. The Page Object pattern can be applied to model each web page as a Java class. Each class encapsulates the structure and behavior of the corresponding web page, making it easier to manage and update the automation code. + ## Intent Page Object encapsulates the UI, hiding the underlying UI widgetry of an application (commonly a web application) and providing an application-specific API to allow the manipulation of UI components required for tests. In doing so, it allows the test class itself to focus on the test logic instead. -## Class diagram -![alt text](./etc/page-object.png "Page Object") +## In Plain Words + +The Page Object pattern in Java is a design pattern used in test automation to represent web pages as Java classes. Each class corresponds to a specific web page and contains methods to interact with the elements on that page. This pattern enhances code maintainability and readability in automated testing. + +## Wikipedia Says + +While there isn't a specific Wikipedia entry for the Page Object pattern, it is widely used in software testing, particularly in the context of UI automation. The Page Object pattern helps abstract the details of a web page, providing a cleaner and more maintainable way to interact with web elements in automated tests. + +## Programmatic Example + +Let's create a simple programmatic example of the Page Object pattern for a login page using Selenium in Java: + +```java +import org.openqa.selenium.By; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; + +public class LoginPage { + private final WebDriver driver; + // Web elements on the login page + private final By usernameInput = By.id("username"); + private final By passwordInput = By.id("password"); + private final By loginButton = By.id("login-button"); + + public LoginPage(WebDriver driver) { + this.driver = driver; + } + + // Methods to interact with the login page + + public void enterUsername(String username) { + WebElement usernameElement = driver.findElement(usernameInput); + usernameElement.sendKeys(username); + } + + public void enterPassword(String password) { + WebElement passwordElement = driver.findElement(passwordInput); + passwordElement.sendKeys(password); + } + + public void clickLoginButton() { + WebElement loginButtonElement = driver.findElement(loginButton); + loginButtonElement.click(); + } + + // Other methods specific to the login page if needed +} +``` + +In this example, the `LoginPage` class represents the login page of a web application. It encapsulates the web elements on the page and provides methods to interact with those elements. The actual Selenium WebDriver instance is passed to the constructor, allowing the methods to perform actions on the web page. + +This Page Object can be used in test scripts to interact with the login page without exposing the details of the page structure in the test code, promoting maintainability and reusability. ## Applicability @@ -21,6 +77,9 @@ Use the Page Object pattern when * You are writing automated tests for your web application and you want to separate the UI manipulation required for the tests from the actual test logic. * Make your tests less brittle, and more readable and robust +## Another example with Class diagram +![alt text](./etc/page-object.png "Page Object") + ## Credits * [Martin Fowler - PageObject](http://martinfowler.com/bliki/PageObject.html) diff --git a/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java b/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java index ef18ea41839f..0913af68e538 100644 --- a/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java +++ b/page-object/sample-application/src/main/java/com/iluwatar/pageobject/App.java @@ -83,7 +83,7 @@ public static void main(String[] args) { } } catch (IOException ex) { - LOGGER.error("An error occured.", ex); + LOGGER.error("An error occurred.", ex); } } diff --git a/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumListPage.java b/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumListPage.java index 7ea05d6c8c09..83917be917aa 100644 --- a/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumListPage.java +++ b/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumListPage.java @@ -59,7 +59,7 @@ public AlbumListPage navigateToPage() { try { page = this.webClient.getPage(PAGE_URL); } catch (IOException e) { - LOGGER.error("An error occured on navigateToPage.", e); + LOGGER.error("An error occurred on navigateToPage.", e); } return this; } @@ -87,7 +87,7 @@ public AlbumPage selectAlbum(String albumTitle) { ((HtmlAnchor) anchor).click(); return new AlbumPage(webClient); } catch (IOException e) { - LOGGER.error("An error occured on selectAlbum", e); + LOGGER.error("An error occurred on selectAlbum", e); } } } diff --git a/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumPage.java b/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumPage.java index 52af795996a5..625293a7a2cc 100644 --- a/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumPage.java +++ b/page-object/test-automation/src/main/java/com/iluwatar/pageobject/AlbumPage.java @@ -61,7 +61,7 @@ public AlbumPage navigateToPage() { try { page = this.webClient.getPage(PAGE_URL); } catch (IOException e) { - LOGGER.error("An error occured on navigateToPage.", e); + LOGGER.error("An error occurred on navigateToPage.", e); } return this; } @@ -151,7 +151,7 @@ public AlbumListPage cancelChanges() { try { cancelButton.click(); } catch (IOException e) { - LOGGER.error("An error occured on cancelChanges.", e); + LOGGER.error("An error occurred on cancelChanges.", e); } return new AlbumListPage(webClient); } @@ -167,7 +167,7 @@ public AlbumPage saveChanges() { try { saveButton.click(); } catch (IOException e) { - LOGGER.error("An error occured on saveChanges.", e); + LOGGER.error("An error occurred on saveChanges.", e); } return this; } diff --git a/page-object/test-automation/src/main/java/com/iluwatar/pageobject/LoginPage.java b/page-object/test-automation/src/main/java/com/iluwatar/pageobject/LoginPage.java index d2c963031298..f87b58e76867 100644 --- a/page-object/test-automation/src/main/java/com/iluwatar/pageobject/LoginPage.java +++ b/page-object/test-automation/src/main/java/com/iluwatar/pageobject/LoginPage.java @@ -60,7 +60,7 @@ public LoginPage navigateToPage() { try { page = this.webClient.getPage(PAGE_URL); } catch (IOException e) { - LOGGER.error("An error occured on navigateToPage.", e); + LOGGER.error("An error occurred on navigateToPage.", e); } return this; } @@ -111,7 +111,7 @@ public AlbumListPage login() { try { loginButton.click(); } catch (IOException e) { - LOGGER.error("An error occured on login.", e); + LOGGER.error("An error occurred on login.", e); } return new AlbumListPage(webClient); } diff --git a/partial-response/src/main/java/com/iluwatar/partialresponse/Video.java b/partial-response/src/main/java/com/iluwatar/partialresponse/Video.java index 5c71f9bb37d3..28604ca0acf9 100644 --- a/partial-response/src/main/java/com/iluwatar/partialresponse/Video.java +++ b/partial-response/src/main/java/com/iluwatar/partialresponse/Video.java @@ -33,7 +33,7 @@ public record Video(Integer id, String title, Integer length, String description /** * ToString. * - * @return json representaion of video + * @return json representation of video */ @Override public String toString() { diff --git a/pom.xml b/pom.xml index 736aa6ddb55d..4169976ff444 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,7 @@ 1.1.0 3.1.2 3.3.0 - 4.2 + 4.3 2.1.1 https://sonarcloud.io diff --git a/role-object/src/main/java/com/iluwatar/roleobject/Role.java b/role-object/src/main/java/com/iluwatar/roleobject/Role.java index ef808c15dd6b..de216b0d7a07 100644 --- a/role-object/src/main/java/com/iluwatar/roleobject/Role.java +++ b/role-object/src/main/java/com/iluwatar/roleobject/Role.java @@ -24,6 +24,7 @@ */ package com.iluwatar.roleobject; +import java.lang.reflect.InvocationTargetException; import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,8 +51,8 @@ public enum Role { public Optional instance() { var typeCst = this.typeCst; try { - return (Optional) Optional.of(typeCst.newInstance()); - } catch (InstantiationException | IllegalAccessException e) { + return (Optional) Optional.of(typeCst.getDeclaredConstructor().newInstance()); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { logger.error("error creating an object", e); } return Optional.empty(); diff --git a/serialized-entity/src/main/java/com/iluwatar/serializedentity/Country.java b/serialized-entity/src/main/java/com/iluwatar/serializedentity/Country.java index e1eb3c22a868..6ef08e83b8d6 100644 --- a/serialized-entity/src/main/java/com/iluwatar/serializedentity/Country.java +++ b/serialized-entity/src/main/java/com/iluwatar/serializedentity/Country.java @@ -31,7 +31,7 @@ import lombok.ToString; /** - * A Country POJO taht represents the data that will serialize and store in database. + * A Country POJO that represents the data that will serialize and store in database. */ @Getter @Setter diff --git a/service-to-worker/src/test/java/com/iluwatar/servicetoworker/GiantViewTest.java b/service-to-worker/src/test/java/com/iluwatar/servicetoworker/GiantViewTest.java index 579f991a93d1..8f5f3bb359e9 100644 --- a/service-to-worker/src/test/java/com/iluwatar/servicetoworker/GiantViewTest.java +++ b/service-to-worker/src/test/java/com/iluwatar/servicetoworker/GiantViewTest.java @@ -37,7 +37,7 @@ class GiantViewTest { /** - * Test dispaly giant. + * Test display giant. */ @Test void testDispalyGiant() { diff --git a/step-builder/README.md b/step-builder/README.md index 659da6e31968..a1e98b237611 100644 --- a/step-builder/README.md +++ b/step-builder/README.md @@ -6,16 +6,100 @@ tag: - Instantiation --- +# Step Builder Pattern + +## Explanation + +The Step Builder pattern is a creational design pattern used to construct a complex object step by step. It provides a fluent interface to create an object with a large number of possible configurations, making the code more readable and reducing the need for multiple constructors or setter methods. + ## Intent An extension of the Builder pattern that fully guides the user through the creation of the object with no chances of confusion. The user experience will be much more improved by the fact that he will only see the next step methods available, NO build method until is the right time to build the object. -## Class diagram -![alt text](./etc/step-builder.png "Step Builder") +## Real World Example + +Imagine you are building a configuration object for a database connection. The connection has various optional parameters such as host, port, username, password, and others. Using the Step Builder pattern, you can set these parameters in a clean and readable way: + +```java +DatabaseConnection connection = new DatabaseConnection.Builder() + .setHost("localhost") + .setPort(3306) + .setUsername("user") + .setPassword("password") + .setSSL(true) + .build(); +``` + +## In Plain Words + +The Step Builder pattern allows you to construct complex objects by breaking down the construction process into a series of steps. Each step corresponds to setting a particular attribute or configuration option of the object. This results in more readable and maintainable code, especially when dealing with objects that have numerous configuration options. + +## Wikipedia Says + +According to Wikipedia, the Step Builder pattern is a creational design pattern in which an object is constructed step by step. It involves a dedicated 'director' class, which orchestrates the construction process through a series of 'builder' classes, each responsible for a specific aspect of the object's configuration. This pattern is particularly useful when dealing with objects that have a large number of optional parameters. + +## Programmatic Example + +Assuming you have a class `Product` with several configurable attributes, a Step Builder for it might look like this: + +```java +public class Product { + private String name; + private double price; + private int quantity; + + // private constructor to force the use of the builder + private Product(String name, double price, int quantity) { + + this.name = name; + this.price = price; + this.quantity = quantity; + + } + + public static class Builder { + private String name; + private double price; + private int quantity; + + public Builder setName(String name) { + this.name = name; + return this; + } + + public Builder setPrice(double price) { + this.price = price; + return this; + } + + public Builder setQuantity(int quantity) { + this.quantity = quantity; + return this; + } + + public Product build() { + return new Product(name, price, quantity); + } + } +} + +// Usage +Product product = new Product.Builder() + .setName("Example Product") + .setPrice(29.99) + .setQuantity(100) + .build(); +``` + +This example demonstrates how you can use the Step Builder pattern to create a `Product` object with a customizable set of attributes. Each method in the builder corresponds to a step in the construction process. ## Applicability Use the Step Builder pattern when the algorithm for creating a complex object should be independent of the parts that make up the object and how they're assembled the construction process must allow different representations for the object that's constructed when in the process of constructing the order is important. +## Another example with class diagram +![alt text](./etc/step-builder.png "Step Builder") + + ## Credits * [Marco Castigliego - Step Builder](http://rdafbn.blogspot.co.uk/2012/07/step-builder-pattern_28.html) diff --git a/subclass-sandbox/README.md b/subclass-sandbox/README.md index d76c149eedc4..7a4587e3d4d5 100644 --- a/subclass-sandbox/README.md +++ b/subclass-sandbox/README.md @@ -32,8 +32,8 @@ public abstract class Superpower { logger.info("Move to ( " + x + ", " + y + ", " + z + " )"); } - protected void playSound(String soundName, int volumn) { - logger.info("Play " + soundName + " with volumn " + volumn); + protected void playSound(String soundName, int volume) { + logger.info("Play " + soundName + " with volume " + volume); } protected void spawnParticles(String particleType, int count) { @@ -88,11 +88,11 @@ Program output: ``` // Use superpower: sky launch // Move to ( 0.0, 0.0, 20.0 ) -// Play SKYLAUNCH_SOUND with volumn 1 +// Play SKYLAUNCH_SOUND with volume 1 // Spawn 100 particle with type SKYLAUNCH_PARTICLE // Use superpower: ground dive // Move to ( 0.0, 0.0, -20.0 ) -// Play GROUNDDIVE_SOUND with volumn 5 +// Play GROUNDDIVE_SOUND with volume 5 // Spawn 20 particle with type GROUNDDIVE_PARTICLE ``` ## Class diagram diff --git a/subclass-sandbox/etc/subclass-sandbox.urm.puml b/subclass-sandbox/etc/subclass-sandbox.urm.puml index a1f863b697c9..9c9fda5994a0 100644 --- a/subclass-sandbox/etc/subclass-sandbox.urm.puml +++ b/subclass-sandbox/etc/subclass-sandbox.urm.puml @@ -18,7 +18,7 @@ package com.iluwatar.subclasssandbox { + Superpower() # activate() {abstract} # move(x : double, y : double, z : double) - # playSound(soundName : String, volumn : int) + # playSound(soundName : String, volume : int) # spawnParticles(particleType : String, count : int) } } diff --git a/subclass-sandbox/src/main/java/com/iluwatar/subclasssandbox/Superpower.java b/subclass-sandbox/src/main/java/com/iluwatar/subclasssandbox/Superpower.java index d3472323e225..4e520f39754e 100644 --- a/subclass-sandbox/src/main/java/com/iluwatar/subclasssandbox/Superpower.java +++ b/subclass-sandbox/src/main/java/com/iluwatar/subclasssandbox/Superpower.java @@ -53,10 +53,10 @@ protected void move(double x, double y, double z) { /** * Play sound effect for the superpower. * @param soundName Sound name. - * @param volumn Value of volumn. + * @param volume Value of volume. */ - protected void playSound(String soundName, int volumn) { - logger.info("Play " + soundName + " with volumn " + volumn); + protected void playSound(String soundName, int volume) { + logger.info("Play " + soundName + " with volume " + volume); } /** diff --git a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java index 05104fa29f86..03c6b2e5c8ba 100644 --- a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java +++ b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/GroundDiveTest.java @@ -48,7 +48,7 @@ void testMove() throws Exception { void testPlaySound() throws Exception { var groundDive = new GroundDive(); var outputLog = getLogContent(() -> groundDive.playSound("SOUND_NAME", 1)); - var expectedLog = "Play SOUND_NAME with volumn 1"; + var expectedLog = "Play SOUND_NAME with volume 1"; assertEquals(outputLog, expectedLog); } @@ -70,7 +70,7 @@ void testActivate() throws Exception { final var log1 = logs[0].split("-")[1].trim() + " -" + logs[0].split("-")[2].trim(); final var expectedLog1 = "Move to ( 0.0, 0.0, -20.0 )"; final var log2 = getLogContent(logs[1]); - final var expectedLog2 = "Play GROUNDDIVE_SOUND with volumn 5"; + final var expectedLog2 = "Play GROUNDDIVE_SOUND with volume 5"; final var log3 = getLogContent(logs[2]); final var expectedLog3 = "Spawn 20 particle with type GROUNDDIVE_PARTICLE"; assertEquals(logs.length, expectedSize); diff --git a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java index 0a199c20e9b5..87cee4f3c697 100644 --- a/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java +++ b/subclass-sandbox/src/test/java/com/iluwatar/subclasssandbox/SkyLaunchTest.java @@ -47,7 +47,7 @@ void testMove() throws Exception { void testPlaySound() throws Exception { var skyLaunch = new SkyLaunch(); var outputLog = getLogContent(() -> skyLaunch.playSound("SOUND_NAME", 1)); - var expectedLog = "Play SOUND_NAME with volumn 1"; + var expectedLog = "Play SOUND_NAME with volume 1"; assertEquals(outputLog, expectedLog); } @@ -69,7 +69,7 @@ void testActivate() throws Exception { final var log1 = getLogContent(logs[0]); final var expectedLog1 = "Move to ( 0.0, 0.0, 20.0 )"; final var log2 = getLogContent(logs[1]); - final var expectedLog2 = "Play SKYLAUNCH_SOUND with volumn 1"; + final var expectedLog2 = "Play SKYLAUNCH_SOUND with volume 1"; final var log3 = getLogContent(logs[2]); final var expectedLog3 = "Spawn 100 particle with type SKYLAUNCH_PARTICLE"; assertEquals(logs.length, expectedSize); diff --git a/typeobjectpattern/README.md b/typeobjectpattern/README.md index d2ff8f295fb5..4942a9592192 100644 --- a/typeobjectpattern/README.md +++ b/typeobjectpattern/README.md @@ -7,6 +7,12 @@ tag: - Extensibility --- +# Type-Object Pattern in Java + +## Explanation + +In Java, the Type-Object pattern is a design pattern that encapsulates type information in an object. This pattern is particularly useful when dealing with multiple objects of the same kind, and there is a need to add new types without altering existing code. + ## Intent As explained in the book Game Programming Patterns by Robert Nystrom, type object pattern helps in @@ -149,8 +155,48 @@ public class JsonParser { } ``` -## Class diagram -![alt text](./etc/typeobjectpattern.urm.png "Type-Object pattern class diagram") +## In Plain Words + +The Type-Object pattern in Java is a method to encapsulate type-specific properties and behaviors within an object. This design pattern facilitates the addition of new types without necessitating changes to existing code, thereby enhancing codebase expansion and maintenance. + +## Wikipedia Says + +While there isn't a specific Wikipedia entry for the Type-Object pattern, it is a commonly used technique in object-oriented programming. This pattern assists in managing objects that share similar characteristics but have different values for those characteristics. It finds widespread use in game development, where numerous types of objects (like enemies) share common behavior but have different properties. + +## Programmatic Example + +Consider an example involving different types of enemies in a game. Each enemy type has distinct properties like speed, health, and damage. + +```java +public class EnemyType { + private String name; + private int speed; + private int health; + private int damage; + + public EnemyType(String name, int speed, int health, int damage) { + this.name = name; + this.speed = speed; + this.health = health; + this.damage = damage; + } + + // getters and setters +} + +public class Enemy { + private EnemyType type; + + // Encapsulating type information in an object + public Enemy(EnemyType type) { + this.type = type; + } + + // other methods +} +``` + +In the above example, `EnemyType` encapsulates type-specific properties (name, speed, health, damage), and `Enemy` uses an instance of `EnemyType` to define its type. This way, you can add as many enemy types as you want without modifying the `Enemy` class. ## Applicability This pattern can be used when: @@ -158,7 +204,10 @@ This pattern can be used when: * We don’t know what types we will need up front. * We want to be able to modify or add new types without having to recompile or change code. * Only difference between the different 'types' of objects is the data, not the behaviour. - + +## Another example with class diagram +![alt text](./etc/typeobjectpattern.urm.png "Type-Object pattern class diagram") + ## Credits * [Game Programming Patterns - Type Object](http://gameprogrammingpatterns.com/type-object.html) diff --git a/update-method/src/main/java/com/iluwatar/updatemethod/World.java b/update-method/src/main/java/com/iluwatar/updatemethod/World.java index f2da8b9f89b1..5335b23f12f0 100644 --- a/update-method/src/main/java/com/iluwatar/updatemethod/World.java +++ b/update-method/src/main/java/com/iluwatar/updatemethod/World.java @@ -74,7 +74,7 @@ private void processInput() { } /** - * Update internal status. The update method pattern invoke udpate method for + * Update internal status. The update method pattern invoke update method for * each entity in the game. */ private void update() {