diff --git a/clean-architecture/README.md b/clean-architecture/README.md new file mode 100644 index 000000000000..0e2e7f5da99e --- /dev/null +++ b/clean-architecture/README.md @@ -0,0 +1,278 @@ +--- +title: "Clean Architecture - A Software Maintainable Architectural style." +shortTitle: Clean Architecture +description: "Learn the Clean Architecture Style in Java with real-world examples, code snippets, and class diagrams. Enhance your coding skills with our detailed explanations." +category: Behavioral +language: en +tag: + - Decoupling + - Architectural Style +--- + +## Also known as + +* Hexagonal Architecture. + +## Intent of Clean Architecture. + +The clean architecture is a software design architectural style which ensures the software application is easy to understand, maintainable and can be extend easily as per business requirement. + +## Detailed Explanation of Clean Architecture Pattern with Real-World Examples + +Real World. + +A real world example of clean architecture is like teh shopping mall example. There some employee is assigned to work on the filling of the products in the counter, one person is responsible for the billing purpose, one person is taking care of the security, one person is taking care of the product they have in storage. The work of every individual is separate and they are focussed on the specific task. Clean architecture also suggests to make the component separate and each component should perform some task. Clean Architecture proposes a layered architecture with clear boundaries between different system components to achieve independence of frameworks, UI, databases, and delivery mechanisms and the possibility to test in isolation. + +In plain word + +It helps to make the system more maintainable and easy to extend. + +Wikipedia says + +> The clean architecture proposed by Robert C. Martin in 2012 combines the principles of the hexagonal architecture, the onion architecture and several other variants. It provides additional levels of detail of the component, which are presented as concentric rings. It isolates adapters and interfaces (user interface, databases, external systems, devices) in the outer rings of the architecture and leaves the inner rings for use cases and entities. +> +> The clean architecture uses the principle of dependency inversion with the strict rule that dependencies shall only exist between an outer ring to an inner ring and never the contrary. + + +## Clean architecture Class Diagram + +![Clean Architecture](./etc/cleanArchitectureUMLDiagram.png "Clean Architecture class diagram") + +## When to Use the Clean Architecture Pattern in Java + +In all application we can use the clean architecture style and make the component separate and business logic separate from the UI and database. + +## Real-World Applications of Chain of Responsibility Pattern in Java. + +In the application say Ecommerce application user gives teh order and the application is represented using teh clean architecture pattern. + +There are facility like the **product** where user can see the product details like the price and the features, **Cart** user can add the product they have selected and the **Order** where user can see the total order and calculate the price of the order. Learn how to implement this design pattern in Java with the following code snippet. + +## Programmatic Example of Clean Architecture Pattern + +First we have the entity class like the `Product`, `Order` and teh `Cart` +```java +public class Product { + private String id; + private String name; + private double price; + + public Product(String id, String name, double price) { + this.id = id; + this.name = name; + this.price = price; + } +} +``` + +```java +public class Cart { + private Product product; + private int quantity; + + public CartItem(Product product, int quantity) { + this.product = product; + this.quantity = quantity; + } + + public double getTotalPrice() { + return product.getPrice() * quantity; + } +} +``` + +```java +public class Order { + private String orderId; + private List items; + private double totalPrice; + + public Order(String orderId, List items) { + this.orderId = orderId; + this.items = items; + this.totalPrice = items.stream().mapToDouble(CartItem::getTotalPrice).sum(); + } +} +``` +The repository interfaces are created. +```java +public interface CartRepository { + void addItemToCart(String userId, Product product, int quantity); + void removeItemFromCart(String userId, String productId); + List getItemsInCart(String userId); + double calculateTotal(String userId); + void clearCart(String userId); +} +``` +```java +public interface ProductRepository { + Product getProductById(String productId); +} +``` +```java +public interface OrderRepository { + void saveOrder(Order order); +} +``` + + +The in memory data store in the cart and order. +```java +public class InMemoryCartRepository implements CartRepository { + private final Map> userCarts = new HashMap<>(); + + @Override + public void addItemToCart(String userId, Product product, int quantity) { + List cart = userCarts.getOrDefault(userId, new ArrayList<>()); + cart.add(new Cart(product, quantity)); + userCarts.put(userId, cart); + } + + @Override + public void removeItemFromCart(String userId, String productId) { + List cart = userCarts.get(userId); + if (cart != null) { + cart.removeIf(item -> item.getProduct().getId().equals(productId)); + } + } + + @Override + public List getItemsInCart(String userId) { + return userCarts.getOrDefault(userId, new ArrayList<>()); + } + + @Override + public double calculateTotal(String userId) { + return userCarts.getOrDefault(userId, new ArrayList<>()) + .stream() + .mapToDouble(Cart::getTotalPrice) + .sum(); + } + + @Override + public void clearCart(String userId) { + userCarts.remove(userId); + } +} +``` +```java +public class InMemoryOrderRepository implements OrderRepository { + private final List orders = new ArrayList<>(); + + @Override + public void saveOrder(Order order) { + orders.add(order); + } +} +``` + +```java +public class InMemoryProductRepository implements ProductRepository { + private final Map products = new HashMap<>(); + + public InMemoryProductRepository() { + products.put("1", new Product("1", "Laptop", 1000.0)); + products.put("2", new Product("2", "Smartphone", 500.0)); + } + + @Override + public Product getProductById(String productId) { + return products.get(productId); + } +} +``` + +The order controller. +```java +public class OrderController{ + private final ShoppingCartService shoppingCartUseCase; + + public OrderController(ShoppingCartService shoppingCartUseCase) { + this.shoppingCartUseCase = shoppingCartUseCase; + } + + public Order checkout(String userId) { + return shoppingCartUseCase.checkout(userId); + } +} +``` +The cart controller. +```java +public class CartController { + private final ShoppingCartService shoppingCartUseCase; + + public CartController(ShoppingCartService shoppingCartUseCase) { + this.shoppingCartUseCase = shoppingCartUseCase; + } + + public void addItemToCart(String userId, String productId, int quantity) { + shoppingCartUseCase.addItemToCart(userId, productId, quantity); + } + + public void removeItemFromCart(String userId, String productId) { + shoppingCartUseCase.removeItemFromCart(userId, productId); + } + + public double calculateTotal(String userId) { + return shoppingCartUseCase.calculateTotal(userId); + } +} +``` + +The clean architecture in action. +```java +public static void main(String[] args) { + + ProductRepository productRepository = new InMemoryProductRepository(); + CartRepository cartRepository = new InMemoryCartRepository(); + OrderRepository orderRepository = new InMemoryOrderRepository(); + + ShoppingCartService shoppingCartUseCase = + new ShoppingCartService(productRepository, cartRepository, orderRepository); + + CartController cartController = new CartController(shoppingCartUseCase); + OrderController orderController = new OrderController(shoppingCartUseCase); + + String userId = "user123"; + cartController.addItemToCart(userId, "1", 1); + cartController.addItemToCart(userId, "2", 2); + + System.out.println("Total: $" + cartController.calculateTotal(userId)); + + Order order = orderController.checkout(userId); + System.out.println( + "Order placed! Order ID: " + order.getOrderId() + ", Total: $" + order.getTotalPrice()); + } +``` + +The output of the code. +```md +Total: $2000.0 +Order placed! Order ID: ORDER-1743349969254, Total: $2000.0 +``` + +## Benefits and Trade-offs of Clean Architecture Pattern. + +Benefits: + +The main benefits of the Clean Architecture involves - +**Scalability** - It allows to add new features without any issue. +**Modularity** - It makes the code loosely coupled and making the change in any component becomes easier. +**Testability** - The architecture promotes unit testing, integration testing, and acceptance testing of different layers independently. + +Trade-Offs: + +Initially the design needs to be done with high precision and the UML diagram should cover all the architectural structure. It will in return help to make it more channelised and the code extensibility will increase. + +## Related Java Design Patterns + +* Dependency Injection - Dependency Injection (DI) is a key concept in Clean Architecture. It promotes loose coupling between classes by allowing dependencies to be injected rather than directly created by the class itself. +* Singleton Pattern - The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. This is often used for shared services or resources, such as a configuration manager, logging service, or database connection pool. + +## References and Credits + +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) +* [Head First Design Patterns: Building Extensible and Maintainable Object-Oriented Software](https://amzn.to/49NGldq) +* [Pattern-Oriented Software Architecture, Volume 1: A System of Patterns](https://amzn.to/3PAJUg5) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) +* [Pattern languages of program design 3](https://amzn.to/4a4NxTH) \ No newline at end of file diff --git a/clean-architecture/etc/cleanArchitectureUMLDiagram.PNG b/clean-architecture/etc/cleanArchitectureUMLDiagram.PNG new file mode 100644 index 000000000000..f107d34a14d8 Binary files /dev/null and b/clean-architecture/etc/cleanArchitectureUMLDiagram.PNG differ diff --git a/clean-architecture/pom.xml b/clean-architecture/pom.xml new file mode 100644 index 000000000000..e47a9df796e5 --- /dev/null +++ b/clean-architecture/pom.xml @@ -0,0 +1,62 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + clean-architecture + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.cleanarchitecture.App + + + + + + + + + diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/App.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/App.java new file mode 100644 index 000000000000..214388c33707 --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/App.java @@ -0,0 +1,52 @@ +package com.iluwatar.cleanarchitecture; + +import lombok.extern.slf4j.Slf4j; + +/** + * Clean Architecture ensures separation of concerns by organizing code, + * into layers and making it scalable and maintainable. + * + *

In the example there are Entities (Core Models) – Product, Cart, + * Order handle business logic. + * Use Cases (Application Logic) – ShoppingCartService manages + * operations like adding items and checkout. + * Interfaces & Adapters – Repositories (CartRepository, OrderRepository) + * abstract data handling, + * while controllers (CartController, OrderController) manage interactions. + */ +@Slf4j +public final class App { + + private App() { + throw new UnsupportedOperationException("Utility class"); + } + + /** + * Program entry point. + * + * @param args command line args + */ + public static void main(final String[] args) { + ProductRepository productRepository = new InMemoryProductRepository(); + CartRepository cartRepository = new InMemoryCartRepository(); + OrderRepository orderRepository = new InMemoryOrderRepository(); + + ShoppingCartService + shoppingCartUseCase = + new ShoppingCartService( + productRepository, cartRepository, orderRepository); + + CartController cartController = new CartController(shoppingCartUseCase); + OrderController orderController = new OrderController(shoppingCartUseCase); + + String userId = "user123"; + cartController.addItemToCart(userId, "1", 1); + cartController.addItemToCart(userId, "2", 2); + + Order order = orderController.checkout(userId); + LOGGER.info("Total: ${}" + cartController.calculateTotal(userId)); + + LOGGER.info("Order placed! Order ID: {}, Total: ${}", + order.getOrderId(), order.getTotalPrice()); + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Cart.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Cart.java new file mode 100644 index 000000000000..d31fc00b828b --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Cart.java @@ -0,0 +1,70 @@ +/* + * 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.cleanarchitecture; + +import lombok.Getter; + +/** + * Represents a shopping cart containing a product and its quantity. + * This class calculates the total price of the product based on its price and quantity. + */ +@Getter +public class Cart { + /** + * The product in the cart. + * It holds the product details such as name, price, and description. + */ + private final Product product; + + /** + * The quantity of the product in the cart. + * It represents how many units of the product are added to the cart. + */ + private final int quantity; + + /** + * Constructs a new Cart instance with a specified product and quantity. + * + * @param prod the product to be added to the cart. + * @param qty the quantity of the product in the cart. + */ + public Cart(final Product prod, final int qty) { + this.product = prod; + this.quantity = qty; + } + + /** + * Calculates the total price of the products in the cart. + * The total price is the product's price multiplied by the quantity. + * + * @return the total price of the products in the cart. + */ + public double getTotalPrice() { + return product.getPrice() * quantity; + } + +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/CartController.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/CartController.java new file mode 100644 index 000000000000..a586ea10c516 --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/CartController.java @@ -0,0 +1,82 @@ +/* + * 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.cleanarchitecture; + +/** + * Controller class for handling shopping cart operations. + * + *

This class provides methods to add, remove, and calculate the + * total price of items in a user's shopping cart.

+ */ +public class CartController { + + + /** Service layer responsible for cart operations. */ + private final ShoppingCartService shoppingCartUseCase; + + /** + * Constructs a CartController with the specified shopping cart service. + * + * @param shoppingCart The shopping cart service to handle cart operations. + */ + public CartController(final ShoppingCartService shoppingCart) { + this.shoppingCartUseCase = shoppingCart; + } + + /** + * Adds an item to the user's cart. + * + * @param userId The ID of the user. + * @param productId The ID of the product to be added. + * @param quantity The quantity of the product. + */ + public void addItemToCart( + final String userId, final String productId, final int quantity) { + shoppingCartUseCase.addItemToCart(userId, productId, quantity); + } + + /** + * Removes an item from the user's cart. + * + * @param userId The ID of the user. + * @param productId The ID of the product to be removed. + */ + public void removeItemFromCart(final String userId, final String productId) { + shoppingCartUseCase.removeItemFromCart(userId, productId); + } + + /** + * Calculates the total cost of items in the user's cart. + * + * @param userId The ID of the user. + * @return The total price of all items in the cart. + */ + public double calculateTotal(final String userId) { + return shoppingCartUseCase.calculateTotal(userId); + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/CartRepository.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/CartRepository.java new file mode 100644 index 000000000000..9e3c7dfe94ca --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/CartRepository.java @@ -0,0 +1,70 @@ +/* + * 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.cleanarchitecture; + +import java.util.List; + +/** + * CartRepository. + */ +public interface CartRepository { + /** + * Adds an item to the user's cart. + * + * @param userId The ID of the user. + * @param product The product to be added. + * @param quantity The quantity of the product. + */ + void addItemToCart(String userId, Product product, int quantity); + /** + * Removes an item from the user's cart. + * + * @param userId The ID of the user. + * @param productId The ID of the product to be removed. + */ + void removeItemFromCart(String userId, String productId); + /** + * Retrieves the list of items in the user's cart. + * + * @param userId The ID of the user. + * @return A list of items in the cart. + */ + List getItemsInCart(String userId); + /** + * Calculates the total price of the items in the user's cart. + * + * @param userId The ID of the user. + * @return The total price of all items in the cart. + */ + double calculateTotal(String userId); + /** + * Clears all items from the user's cart. + * + * @param userId The ID of the user. + */ + void clearCart(String userId); +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryCartRepository.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryCartRepository.java new file mode 100644 index 000000000000..b107a428517a --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryCartRepository.java @@ -0,0 +1,109 @@ +/* + * 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.cleanarchitecture; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implementation of {@link CartRepository} that stores cart items in memory. + * + *

This class maintains a map of user carts where each user has a + * list of cart items.

+ */ +public class InMemoryCartRepository implements CartRepository { + /** + * A map storing user carts with their respective cart items. + */ + private final Map> userCarts = new HashMap<>(); + + /** + * Adds an item to the user's cart. + * + * @param userId The ID of the user. + * @param product The product to be added. + * @param quantity The quantity of the product. + */ + @Override + public void addItemToCart( + final String userId, final Product product, final int quantity) { + List cart = userCarts.getOrDefault(userId, new ArrayList<>()); + cart.add(new Cart(product, quantity)); + userCarts.put(userId, cart); + } + + /** + * Removes an item from the user's cart. + * + * @param userId The ID of the user. + * @param productId The ID of the product to be removed. + */ + @Override + public void removeItemFromCart(final String userId, final String productId) { + List cart = userCarts.get(userId); + if (cart != null) { + cart.removeIf(item -> item.getProduct().getId().equals(productId)); + } + } + + /** + * Retrieves all items in the user's cart. + * + * @param userId The ID of the user. + * @return A list of {@link Cart} items in the user's cart. + */ + @Override + public List getItemsInCart(final String userId) { + return userCarts.getOrDefault(userId, new ArrayList<>()); + } + + /** + * Calculates the total price of items in the user's cart. + * + * @param userId The ID of the user. + * @return The total price of the cart. + */ + @Override + public double calculateTotal(final String userId) { + return userCarts.getOrDefault(userId, new ArrayList<>()) + .stream() + .mapToDouble(Cart::getTotalPrice) + .sum(); + } + + /** + * Clears all items from the user's cart. + * + * @param userId The ID of the user. + */ + @Override + public void clearCart(final String userId) { + userCarts.remove(userId); + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryOrderRepository.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryOrderRepository.java new file mode 100644 index 000000000000..2dab179a73f4 --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryOrderRepository.java @@ -0,0 +1,51 @@ +/* + * 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.cleanarchitecture; + +import java.util.ArrayList; +import java.util.List; + +/** + * An in-memory implementation of the {@link OrderRepository}. + * + *

This class stores orders in a list, allowing orders to be saved + * but not persisted beyond the application's runtime.

+ */ +public class InMemoryOrderRepository implements OrderRepository { + /** A list to store orders in memory. */ + private final List orders = new ArrayList<>(); + + /** + * Saves an order to the in-memory repository. + * + * @param order The order to be saved. + */ + @Override + public void saveOrder(final Order order) { + orders.add(order); + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryProductRepository.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryProductRepository.java new file mode 100644 index 000000000000..e7e0c88826af --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/InMemoryProductRepository.java @@ -0,0 +1,78 @@ +/* + * 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.cleanarchitecture; + +import java.util.HashMap; +import java.util.Map; + +/** + * In-memory implementation of the {@link ProductRepository} interface. + * + *

This repository stores products in memory + * allowing retrieval by product ID.

+ */ +public class InMemoryProductRepository implements ProductRepository { + /** + * A map to store products by their unique product ID. + */ + private final Map products = new HashMap<>(); + /** + * The price of the Laptop in USD. + *

Used in the in-memory product repository + * to define the cost of a Laptop.

+ */ + private static final double LAPTOP_PRICE = 1000.0; + + /** + * The price of the Smartphone in USD. + *

Used in the in-memory product repository + * to define the cost of a Smartphone.

+ */ + private static final double SMARTPHONE_PRICE = 500.0; + + + /** + * Constructs an {@code InMemoryProductRepository} and + * initializes it with some example products. + */ + public InMemoryProductRepository() { + products.put("1", new Product("1", "Laptop", LAPTOP_PRICE)); + products.put("2", new Product("2", "Smartphone", SMARTPHONE_PRICE)); + } + + /** + * Retrieves a product by its unique ID. + * + * @param productId The ID of the product to retrieve. + * @return The {@link Product} corresponding to the given ID + * {@code null} if not found. + */ + @Override + public Product getProductById(final String productId) { + return products.get(productId); + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Order.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Order.java new file mode 100644 index 000000000000..673d2108b93a --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Order.java @@ -0,0 +1,66 @@ +/* + * 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.cleanarchitecture; + +import java.util.List; +import lombok.Getter; + +/** + * Represents an order placed by a user containing + * the ordered items and total price. + * + *

An order includes a unique order ID, a list of cart items + * and the total price of the order.

+ */ +@Getter +public class Order { + /** + * The unique identifier for this order. + */ + private final String orderId; + /** + * The list of items included in this order. + */ + private final List items; + /** + * The list of items included in this order. + */ + private final double totalPrice; + + /** + * Constructs an {@code Order} with the given order ID and list of cart items. + * The total price is based on the individual item prices in the cart. + * + * @param id The unique identifier for the order. + * @param item The list of cart items included in the order. + */ + public Order(final String id, final List item) { + this.orderId = id; + this.items = item; + this.totalPrice = items.stream().mapToDouble(Cart::getTotalPrice).sum(); + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/OrderController.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/OrderController.java new file mode 100644 index 000000000000..f7c8e966bfaa --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/OrderController.java @@ -0,0 +1,60 @@ +/* + * 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.cleanarchitecture; + +/** + * Controller for handling order-related operations. + * + *

This class provides an endpoint for users to checkout their cart + * and place an order.

+ */ +public class OrderController { + /** + * Service for managing shopping cart operations. + */ + private final ShoppingCartService shoppingCartUseCase; + + + /** + * Constructs an {@code OrderController} with the given shopping cart service. + * + * @param shoppingCartUse The shopping cart service used to process orders. + */ + public OrderController(final ShoppingCartService shoppingCartUse) { + this.shoppingCartUseCase = shoppingCartUse; + } + + /** + * Processes the checkout for a given user and creates an order. + * + * @param userId The ID of the user checking out. + * @return The created {@link Order} after checkout. + */ + public Order checkout(final String userId) { + return shoppingCartUseCase.checkout(userId); + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/OrderRepository.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/OrderRepository.java new file mode 100644 index 000000000000..f722a6b43533 --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/OrderRepository.java @@ -0,0 +1,41 @@ +/* + * 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.cleanarchitecture; + +/** + * Repository interface for managing order persistence. + * + *

This interface defines the contract for storing orders in the system.

+ */ +public interface OrderRepository { + /** + * Saves an order to the repository. + * + * @param order The order to be saved. + */ + void saveOrder(Order order); +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Product.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Product.java new file mode 100644 index 000000000000..b6409341803d --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/Product.java @@ -0,0 +1,57 @@ +/* + * 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.cleanarchitecture; + +import lombok.Getter; + +/** + * Represents a product in the system. + */ +@Getter +public class Product { + /** The unique identifier for the product. */ + private final String id; + + /** The name of the product. */ + private final String name; + + /** The price of the product. */ + private final double price; + + /** + * Constructs a new Product with the given details. + * + * @param pdtId The unique identifier of the product. + * @param firstName The name of the product. + * @param p The price of the product. + */ + public Product(final String pdtId, final String firstName, final double p) { + this.id = pdtId; + this.name = firstName; + this.price = p; + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/ProductRepository.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/ProductRepository.java new file mode 100644 index 000000000000..1dde70005bf8 --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/ProductRepository.java @@ -0,0 +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.cleanarchitecture; + +/** + * Repository interface for handling product-related operations. + */ +public interface ProductRepository { + /** + * Retrieves a product by its unique identifier. + * + * @param productId The unique ID of the product. + * @return The product corresponding to the given ID. + */ + Product getProductById(String productId); +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/ShoppingCartService.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/ShoppingCartService.java new file mode 100644 index 000000000000..9f6225a8173e --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/ShoppingCartService.java @@ -0,0 +1,112 @@ +/* + * 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.cleanarchitecture; + +import java.util.List; + +/** + * Service class for managing shopping cart operations. + * + *

This class provides functionalities to add and remove items from the cart, + * calculate the total price, and handle checkout operations.

+ */ +public class ShoppingCartService { + /** Repository for managing product data. */ + private final ProductRepository productRepository; + /** Repository for managing cart data. */ + private final CartRepository cartRepository; + /** Repository for managing order data. */ + private final OrderRepository orderRepository; + + + /** + * Constructs a ShoppingCartService with the required repositories. + * + * @param pdtRepository The repository to fetch product details. + * @param repository The repository to manage cart operations. + * @param ordRepository The repository to handle order persistence. + */ + public ShoppingCartService(final ProductRepository pdtRepository, + final CartRepository repository, + final OrderRepository ordRepository) { + this.productRepository = pdtRepository; + this.cartRepository = repository; + this.orderRepository = ordRepository; + } + + /** + * Adds an item to the user's shopping cart. + * + * @param userId The ID of the user. + * @param productId The ID of the product to be added. + * @param quantity The quantity of the product. + */ + public void addItemToCart( + final String userId, final String productId, final int quantity) { + Product product = productRepository.getProductById(productId); + if (product != null) { + cartRepository.addItemToCart(userId, product, quantity); + } + } + /** + * Removes an item from the user's shopping cart. + * + * @param userId The ID of the user. + * @param productId The ID of the product to be removed. + */ + public void removeItemFromCart(final String userId, final String productId) { + cartRepository.removeItemFromCart(userId, productId); + } + + /** + * Calculates the total cost of items in the user's shopping cart. + * + * @param userId The ID of the user. + * @return The total price of all items in the cart. + */ + public double calculateTotal(final String userId) { + return cartRepository.calculateTotal(userId); + } + + /** + * Checks out the user's cart and creates an order. + * + *

This method retrieves the cart items, generates an order ID, + * creates a new order, saves it, and clears the cart.

+ * + * @param userId The ID of the user. + * @return The created order containing purchased items. + */ + public Order checkout(final String userId) { + List items = cartRepository.getItemsInCart(userId); + String orderId = "ORDER-" + System.currentTimeMillis(); + Order order = new Order(orderId, items); + orderRepository.saveOrder(order); + cartRepository.clearCart(userId); + return order; + } +} diff --git a/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/package-info.java b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/package-info.java new file mode 100644 index 000000000000..59bf905a428a --- /dev/null +++ b/clean-architecture/src/main/java/com/iluwatar/cleanarchitecture/package-info.java @@ -0,0 +1,10 @@ +/** + * Provides classes and interfaces for the clean architecture + * pattern implementation. + * + *

This package includes classes for managing products, carts, + * orders, repositories, + * and services for a shopping cart system, following the + * clean architecture principles.

+ */ +package com.iluwatar.cleanarchitecture; diff --git a/clean-architecture/src/test/java/com/iluwatar/cleanarchitecture/AppTest.java b/clean-architecture/src/test/java/com/iluwatar/cleanarchitecture/AppTest.java new file mode 100644 index 000000000000..d78baf3510d2 --- /dev/null +++ b/clean-architecture/src/test/java/com/iluwatar/cleanarchitecture/AppTest.java @@ -0,0 +1,20 @@ +package com.iluwatar.cleanarchitecture; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class AppTest { + /** + * Issue: Add at least one assertion to this test case. + * + * Solution: Inserted assertion to check whether the execution of the main method in {@link App} + * throws an exception. + */ + + @Test + void shouldExecuteApplicationWithoutException() { + + assertDoesNotThrow(() -> App.main(new String[]{})); + } +} \ No newline at end of file diff --git a/clean-architecture/src/test/java/com/iluwatar/cleanarchitecture/CartControllerTest.java b/clean-architecture/src/test/java/com/iluwatar/cleanarchitecture/CartControllerTest.java new file mode 100644 index 000000000000..ec1d1bb29119 --- /dev/null +++ b/clean-architecture/src/test/java/com/iluwatar/cleanarchitecture/CartControllerTest.java @@ -0,0 +1,41 @@ +package com.iluwatar.cleanarchitecture; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.assertEquals; + + +public class CartControllerTest { + + private ShoppingCartService shoppingCartUseCase; + private CartController cartController; + + @BeforeEach + public void setUp() { + ProductRepository productRepository = new InMemoryProductRepository(); + CartRepository cartRepository = new InMemoryCartRepository(); + OrderRepository orderRepository = new InMemoryOrderRepository(); + shoppingCartUseCase = new ShoppingCartService(productRepository, cartRepository, orderRepository); + cartController = new CartController(shoppingCartUseCase); + } + + @Test + void testRemoveItemFromCart() { + cartController.addItemToCart("user123", "1", 1); + cartController.addItemToCart("user123", "2", 2); + + assertEquals(2000.0, cartController.calculateTotal("user123")); + + cartController.removeItemFromCart("user123", "1"); + + assertEquals(1000.0, cartController.calculateTotal("user123")); + } + + @Test + void testRemoveNonExistentItem() { + cartController.addItemToCart("user123", "2", 2); + cartController.removeItemFromCart("user123", "999"); + + assertEquals(1000.0, cartController.calculateTotal("user123")); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 618cb175cc8a..2baf0fcd75ee 100644 --- a/pom.xml +++ b/pom.xml @@ -83,6 +83,7 @@ callback chain-of-responsibility circuit-breaker + clean-architecture client-session collecting-parameter collection-pipeline @@ -149,8 +150,8 @@ map-reduce marker-interface master-worker - mediator - memento + mediator + memento metadata-mapping microservices-aggregrator microservices-api-gateway @@ -164,7 +165,7 @@ model-view-viewmodel monad money - monitor + monitor monolithic-architecture monostate multiton