From a3fcc631672a3e418523af0c61c403caf5c137bf Mon Sep 17 00:00:00 2001 From: e5LA <208197507+e5LA@users.noreply.github.com> Date: Sun, 8 Feb 2026 20:44:17 +0100 Subject: [PATCH] feat: Implement View Helper pattern (#3278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * #1263 - creating new module for view-helper * #1263 - creating Product and ProductViewModel * #1263 - creating interfaces for View and ViewHelper * #1263 - creating ProductViewHelper and its test * #1263 - creating Console View for Product * #1263 - creating ProductController * #1263 - creating main App and its test * #1263 - adding license header * #1263 - keeping module in alphabetical order * #1263 - creating README and diagrams * #1263 apply spotless --------- Co-authored-by: Ilkka Seppälä --- pom.xml | 3 +- view-helper/README.md | 98 ++++++++++++++++++ .../etc/view-helper-sequence-diagram.png | Bin 0 -> 27969 bytes .../etc/view-helper-sequence-diagram.puml | 15 +++ view-helper/etc/view-helper.png | Bin 0 -> 56099 bytes view-helper/etc/view-helper.puml | 45 ++++++++ view-helper/pom.xml | 70 +++++++++++++ .../java/com/iluwatar/viewhelper/App.java | 52 ++++++++++ .../viewhelper/ConsoleProductView.java | 36 +++++++ .../java/com/iluwatar/viewhelper/Product.java | 31 ++++++ .../viewhelper/ProductController.java | 49 +++++++++ .../viewhelper/ProductViewHelper.java | 45 ++++++++ .../iluwatar/viewhelper/ProductViewModel.java | 28 +++++ .../java/com/iluwatar/viewhelper/View.java | 30 ++++++ .../com/iluwatar/viewhelper/ViewHelper.java | 29 ++++++ .../java/com/iluwatar/viewhelper/AppTest.java | 39 +++++++ .../viewhelper/ProductViewHelperTest.java | 60 +++++++++++ 17 files changed, 628 insertions(+), 2 deletions(-) create mode 100644 view-helper/README.md create mode 100644 view-helper/etc/view-helper-sequence-diagram.png create mode 100644 view-helper/etc/view-helper-sequence-diagram.puml create mode 100644 view-helper/etc/view-helper.png create mode 100644 view-helper/etc/view-helper.puml create mode 100644 view-helper/pom.xml create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/App.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/Product.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/View.java create mode 100644 view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.java create mode 100644 view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.java create mode 100644 view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.java diff --git a/pom.xml b/pom.xml index 2816ef0ca..5926820b7 100644 --- a/pom.xml +++ b/pom.xml @@ -71,7 +71,6 @@ Java Design Patterns - abstract-document abstract-factory active-object @@ -244,11 +243,11 @@ update-method value-object version-number + view-helper virtual-proxy visitor backpressure actor-model - diff --git a/view-helper/README.md b/view-helper/README.md new file mode 100644 index 000000000..fbc93acba --- /dev/null +++ b/view-helper/README.md @@ -0,0 +1,98 @@ +--- +title: "View Helper Pattern in Java: Simplifying Presentation Logic in MVC Applications" +shortTitle: View Helper +description: "Discover the View Helper Design Pattern in Java, a powerful technique for separating view-related logic from business logic in MVC-based web applications. This pattern enhances maintainability, reusability, and testability by delegating complex UI operations to reusable helper components. Ideal for developers aiming to keep views clean and focused on presentation." +category: Architectural +language: en +tag: + - Architecture + - Presentation + - Decoupling + - Code reuse +--- + +## Intent of View Helper Design Pattern +The View Helper Design Pattern separates presentation logic from the view by delegating complex UI tasks — like formatting or conditional display — to reusable helper components. This keeps views clean, promotes reuse, and aligns with the MVC principle of separating concerns between the view and the business logic. + +## Detailed Explanation with Real‑World Analogy +Real‑world example +> Imagine you're putting together a slideshow for a business presentation. You focus on arranging the slides, choosing the layout, and telling the story. But for tasks like resizing images, formatting charts, or converting data into visual form, you use tools or templates that automate those parts. +> +> In this analogy, you are the view, and the tools/templates are the helpers. They handle the heavy lifting behind the scenes so you can concentrate on the presentation. Similarly, in the View Helper pattern, the view delegates logic-heavy tasks—such as formatting or conditionally displaying data—to helper classes, keeping the view layer clean and presentation-focused. + +### In plain words +> The View Helper pattern is about keeping your UI code clean by moving any logic—like formatting, calculations, or decision-making—into separate helper classes. Instead of stuffing all the logic into the HTML or template files, you delegate it to helpers, so the view just focuses on showing the final result. + +### Sequence diagram +![Sequence diagram for View Helper](etc/view-helper-sequence-diagram.png) + +## Programmatic Example of View Helper Pattern in Java +Raw domain object +```java +public record Product(String name, BigDecimal price, LocalDate releaseDate, boolean discounted) {} +``` + +View model object for display +```java +public record ProductViewModel(String name, String price, String releasedDate) {} +``` + +View Helper formats data for display +```java +class ProductViewHelper implements ViewHelper { + + private static final String DISCOUNT_TAG = " (ON SALE)"; + + public ProductViewModel prepare(Product product) { + var displayName = product.name() + (product.discounted() ? DISCOUNT_TAG : ""); + var priceWithCurrency = NumberFormat.getCurrencyInstance(US).format(product.price()); + var formattedDate = product.releaseDate().format(ISO_DATE); + + return new ProductViewModel(displayName, priceWithCurrency, formattedDate); + } +} +``` + +View renders the formatted data +```java +public class ConsoleProductView implements View { + + @Override + public void render(ProductViewModel productViewModel) { + LOGGER.info(productViewModel.toString()); + } +} +``` +The `App.java` class simulates how the View Helper pattern works in a real application. It starts with a raw `Product` object containing unformatted data. +Then it: +1. Initializes a helper (`ProductViewHelper`) to format the product data for display. +1. Creates a view (`ConsoleProductView`) to render the formatted data. +1. Uses a controller (`ProductController`) to coordinate the flow between raw data, helper logic, and view rendering. + +Finally, it simulates a user request by passing the product to the controller, which prepares the view model using the helper and displays it using the view. This demonstrates a clean separation between data, presentation logic, and rendering. + +## When to Use the View Helper Pattern in Java +Use the View Helper pattern when your view layer starts containing logic such as formatting data, applying conditional styles, or transforming domain objects for display. It's especially useful in MVC architectures where you want to keep views clean and focused on rendering, while delegating non-trivial presentation logic to reusable helper classes. This pattern helps improve maintainability, testability, and separation of concerns in your application's UI layer. + +## Real‑World Uses of View Helper Pattern in Java +The View Helper pattern is widely used in web frameworks that follow the MVC architecture. In Java-based web applications (e.g., JSP, Spring MVC), it's common to use helper classes or utility methods to format dates, currencies, or apply conditional logic before rendering views. Technologies like Thymeleaf or JSF often rely on custom tags or expression helpers to achieve the same effect. + +## Benefits and Trade‑offs +Benefits: +* Separation of concerns: Keeps view templates clean by moving logic into dedicated helpers. +* Reusability: Common formatting and display logic can be reused across multiple views. +* Improved maintainability: Easier to update presentation logic without touching the view. +* Testability: Helpers can be unit tested independently from the UI layer. + +Trade‑offs: +* Added complexity: Introduces extra classes, which may feel unnecessary for very simple views. +* Overuse risk: Excessive use of helpers can spread logic thinly across many files, making it harder to trace behavior. +* Tight coupling risk: If not designed carefully, helpers can become tightly coupled to specific views or data formats. + +## Related Java Design Patterns +* [Model-View-Controller (MVC)](https://java-design-patterns.com/patterns/model-view-controller/): View Helper supports the View layer in MVC by offloading logic from the view to helper classes. +* [Template Method](https://java-design-patterns.com/patterns/template-method/): Can structure the steps of rendering or data transformation, with helpers handling specific formatting tasks. +* [Data Transfer Object (DTO)](https://java-design-patterns.com/patterns/data-transfer-object/): Often used alongside View Helper when transferring raw data that needs formatting before being displayed. + +## References & Credits +* [Core J2EE Patterns: View Helper.](https://www.oracle.com/java/technologies/viewhelper.html) diff --git a/view-helper/etc/view-helper-sequence-diagram.png b/view-helper/etc/view-helper-sequence-diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..22e53c6b8afe625ae8604ca8f37659e69e6ef8e2 GIT binary patch literal 27969 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 literal 0 HcmV?d00001 diff --git a/view-helper/etc/view-helper-sequence-diagram.puml b/view-helper/etc/view-helper-sequence-diagram.puml new file mode 100644 index 000000000..d5be27e51 --- /dev/null +++ b/view-helper/etc/view-helper-sequence-diagram.puml @@ -0,0 +1,15 @@ +@startuml +actor Client +participant Controller +participant ViewHelper +participant View +participant Product +participant ProductViewModel + +Client -> Controller : handle(product) +Controller -> ViewHelper : prepare(product) +ViewHelper -> Product : access data +ViewHelper -> ProductViewModel : return formatted view model +Controller -> View : render(viewModel) +View -> Console : display output +@enduml \ No newline at end of file diff --git a/view-helper/etc/view-helper.png b/view-helper/etc/view-helper.png new file mode 100644 index 0000000000000000000000000000000000000000..9550b80d7acb2496f8ededf8ad9a85237203b28b GIT binary patch literal 56099 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 { + +render(T model) + } + + interface ViewHelper { + +prepare(S source): T + } + + class Product { + -name: String + -price: BigDecimal + -releaseDate: LocalDate + -discounted: boolean + } + + class ProductViewModel { + -name: String + -price: String + -releasedDate: String + } + + class ProductViewHelper { + +prepare(Product): ProductViewModel + } + + class ConsoleProductView { + +render(ProductViewModel) + } + + class ProductController { + -helper: ViewHelper + -view: View + +handle(Product) + } +} +Product --> ProductViewHelper +ProductViewHelper ..|> ViewHelper +ConsoleProductView ..|> View +ProductViewHelper --> ProductViewModel +ProductController --> ProductViewHelper +ProductController --> ConsoleProductView + +@enduml \ No newline at end of file diff --git a/view-helper/pom.xml b/view-helper/pom.xml new file mode 100644 index 000000000..e2f3afca3 --- /dev/null +++ b/view-helper/pom.xml @@ -0,0 +1,70 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + view-helper + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.value.object.App + + + + + + + + + diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/App.java b/view-helper/src/main/java/com/iluwatar/viewhelper/App.java new file mode 100644 index 000000000..e427bc8f5 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/App.java @@ -0,0 +1,52 @@ +/* + * 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.viewhelper; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** The main application class that sets up and runs the View Helper pattern demo. */ +public class App { + /** + * The entry point of the application. + * + * @param args the command line arguments + */ + public static void main(String[] args) { + // Raw Product data (no formatting, no UI tags) + var product = + new Product( + "Design patterns book", new BigDecimal("18.90"), LocalDate.of(2025, 4, 19), true); + + // Create view, viewHelper and viewHelper + var helper = new ProductViewHelper(); + var view = new ConsoleProductView(); + var controller = new ProductController(helper, view); + + // Handle “request” + controller.handle(product); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.java new file mode 100644 index 000000000..7f215a751 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ConsoleProductView.java @@ -0,0 +1,36 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.viewhelper; + +import lombok.extern.slf4j.Slf4j; + +/** Renders {@link ProductViewModel} to the console. */ +@Slf4j +public class ConsoleProductView implements View { + @Override + public void render(ProductViewModel productViewModel) { + LOGGER.info(productViewModel.toString()); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/Product.java b/view-helper/src/main/java/com/iluwatar/viewhelper/Product.java new file mode 100644 index 000000000..a0a75cf24 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/Product.java @@ -0,0 +1,31 @@ +/* + * 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.viewhelper; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** Definition of product. */ +public record Product(String name, BigDecimal price, LocalDate releaseDate, boolean discounted) {} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java new file mode 100644 index 000000000..836f34a33 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductController.java @@ -0,0 +1,49 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package com.iluwatar.viewhelper; + +/** + * Controller delegates a {@link Product} to {@link ProductViewHelper} and then to {@link + * ConsoleProductView}. + */ +public class ProductController { + + private final ViewHelper viewHelper; + private final View view; + + public ProductController( + ViewHelper viewHelper, View view) { + this.viewHelper = viewHelper; + this.view = view; + } + + /** + * Passes the product to the helper for formatting and then forwards formatted product to the + * view. + */ + public void handle(Product product) { + view.render(viewHelper.prepare(product)); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.java new file mode 100644 index 000000000..4c739e9f1 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewHelper.java @@ -0,0 +1,45 @@ +/* + * 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.viewhelper; + +import static java.time.format.DateTimeFormatter.ISO_DATE; +import static java.util.Locale.US; + +import java.text.NumberFormat; + +/** Formats a {@link Product} into a {@link ProductViewModel}. */ +public class ProductViewHelper implements ViewHelper { + + private static final String DISCOUNT_TAG = " ON SALE"; + + @Override + public ProductViewModel prepare(Product product) { + var displayName = product.name() + (product.discounted() ? DISCOUNT_TAG : ""); + var priceWithCurrency = NumberFormat.getCurrencyInstance(US).format(product.price()); + var formattedDate = product.releaseDate().format(ISO_DATE); + + return new ProductViewModel(displayName, priceWithCurrency, formattedDate); + } +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.java new file mode 100644 index 000000000..b133fc071 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ProductViewModel.java @@ -0,0 +1,28 @@ +/* + * 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.viewhelper; + +/** Class defining formatted display data of a {@link Product}. */ +public record ProductViewModel(String name, String price, String releasedDate) {} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/View.java b/view-helper/src/main/java/com/iluwatar/viewhelper/View.java new file mode 100644 index 000000000..7bc822166 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/View.java @@ -0,0 +1,30 @@ +/* + * 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.viewhelper; + +public interface View { + + void render(V data); +} diff --git a/view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.java b/view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.java new file mode 100644 index 000000000..68756f465 --- /dev/null +++ b/view-helper/src/main/java/com/iluwatar/viewhelper/ViewHelper.java @@ -0,0 +1,29 @@ +/* + * 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.viewhelper; + +public interface ViewHelper { + V prepare(M source); +} diff --git a/view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.java b/view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.java new file mode 100644 index 000000000..bc4a31cc4 --- /dev/null +++ b/view-helper/src/test/java/com/iluwatar/viewhelper/AppTest.java @@ -0,0 +1,39 @@ +/* + * 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.viewhelper; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + +import org.junit.jupiter.api.Test; + +/** Application test */ +class AppTest { + + @Test + void shouldExecuteApplicationWithoutException() { + assertDoesNotThrow(() -> App.main(new String[] {})); + } +} diff --git a/view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.java b/view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.java new file mode 100644 index 000000000..49cc48556 --- /dev/null +++ b/view-helper/src/test/java/com/iluwatar/viewhelper/ProductViewHelperTest.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.viewhelper; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import java.time.LocalDate; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class ProductViewHelperTest { + + private ProductViewHelper helper; + + @BeforeEach + void setUp() { + helper = new ProductViewHelper(); + } + + @Test + void shouldFormatProductWithoutDiscount() { + var product = new Product("X", new BigDecimal("10.00"), LocalDate.of(2025, 1, 1), false); + ProductViewModel viewModel = helper.prepare(product); + + assertEquals("X", viewModel.name()); + assertEquals("$10.00", viewModel.price()); + assertEquals("2025-01-01", viewModel.releasedDate()); + } + + @Test + void shouldFormatProductWithDiscount() { + var product = new Product("X", new BigDecimal("10.00"), LocalDate.of(2025, 1, 1), true); + ProductViewModel viewModel = helper.prepare(product); + + assertEquals("X ON SALE", viewModel.name()); // locale follows JVM default + } +}