From f833ad326b4dc1a84c9bfa26b5fcb967b469ea71 Mon Sep 17 00:00:00 2001 From: Faris Sharara Date: Wed, 4 Dec 2024 00:15:17 +0200 Subject: [PATCH 1/3] Resolved issue #1323 Two-Step View pattern --- .../iluwatar/idempotentconsumer/AppTest.java | 24 ++++++ .../RequestStateMachineTests.java | 24 ++++++ pom.xml | 1 + two-step-view/README.md | 79 +++++++++++++++++++ two-step-view/pom.xml | 53 +++++++++++++ .../src/main/java/com/iluwatar/App.java | 47 +++++++++++ .../src/main/java/com/iluwatar/Book.java | 37 +++++++++ .../src/main/java/com/iluwatar/BookStore.java | 38 +++++++++ .../java/com/iluwatar/DataPreparation.java | 43 ++++++++++ .../main/java/com/iluwatar/Presentation.java | 47 +++++++++++ .../test/java/com/iluwatar/BookStoreTest.java | 43 ++++++++++ update-header.sh | 25 ++++++ 12 files changed, 461 insertions(+) create mode 100644 two-step-view/README.md create mode 100644 two-step-view/pom.xml create mode 100644 two-step-view/src/main/java/com/iluwatar/App.java create mode 100644 two-step-view/src/main/java/com/iluwatar/Book.java create mode 100644 two-step-view/src/main/java/com/iluwatar/BookStore.java create mode 100644 two-step-view/src/main/java/com/iluwatar/DataPreparation.java create mode 100644 two-step-view/src/main/java/com/iluwatar/Presentation.java create mode 100644 two-step-view/src/test/java/com/iluwatar/BookStoreTest.java diff --git a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java index e161b2edc30d..b72f5bffaac5 100644 --- a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java +++ b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/AppTest.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.idempotentconsumer; import org.junit.jupiter.api.Test; diff --git a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.java b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.java index af779648c8a3..083cff7ad05e 100644 --- a/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.java +++ b/microservices-idempotent-consumer/src/test/java/com/iluwatar/idempotentconsumer/RequestStateMachineTests.java @@ -1,3 +1,27 @@ +/* + * This project is licensed under the MIT license. Module model-view-viewmodel is using ZK framework licensed under LGPL (see lgpl-3.0.txt). + * + * The MIT License + * Copyright © 2014-2022 Ilkka Seppälä + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ package com.iluwatar.idempotentconsumer; import org.junit.jupiter.api.BeforeEach; diff --git a/pom.xml b/pom.xml index ef3a39265d53..c1cc996ab1d0 100644 --- a/pom.xml +++ b/pom.xml @@ -218,6 +218,7 @@ function-composition microservices-distributed-tracing microservices-idempotent-consumer + two-step-view diff --git a/two-step-view/README.md b/two-step-view/README.md new file mode 100644 index 000000000000..a8962999cc15 --- /dev/null +++ b/two-step-view/README.md @@ -0,0 +1,79 @@ +# Book Data Processing and Presentation + +This example demonstrates a simple pipeline for processing book data and rendering it as an HTML view. It involves three main steps: **data preparation**, **business logic processing**, and **presentation**. The structure of the program aligns with the principles of the **Presentation-Abstraction-Control (PAC)** design pattern. + +--- + +## Problem Addressed +This implementation solves the issue described in [Issue #1323](https://github.com/iluwatar/java-design-patterns/issues/1323) of the [java-design-patterns repository](https://github.com/iluwatar/java-design-patterns). The goal is to showcase how to split application logic into phases while keeping the layers loosely coupled. + +--- + +## Overview of the Solution +The program is divided into the following parts: + +1. **Data Layer** + - The `Book` class represents the raw data for a book. + - The `BookStore` class holds the processed book data for display. + +2. **Logic Layer** + - The `DataPreparation` class handles the business logic. It computes whether a discount is applied and checks stock availability. + +3. **Presentation Layer** + - The `Presentation` class generates an HTML view of the book data. + +--- + +## How to Run the Code + +1. Clone the repository: + ```bash + git clone https://github.com/iluwatar/java-design-patterns.git + cd java-design-patterns + ``` + +2. Compile and run the `App` class: + ```bash + javac com/iluwatar/*.java + java com.iluwatar.App + ``` + +3. Expected Output: + The program generates an HTML representation of the book data and prints it to the console: + ```html +
+

Batman Vol. 1: The Court of Owls

+

Price: $11.6

+

Discounted Price: $8.7

+

Status: In Stock

+
+ ``` + +--- + +## Code Structure + +- `Book`: Represents raw book data with fields like `name`, `price`, `discount`, and `stock`. +- `BookStore`: Represents processed data including `discountPrice` and `inStock` status. +- `DataPreparation`: Contains logic to calculate the discount price and determine stock status. +- `Presentation`: Generates the HTML view of the book data. +- `App`: Entry point that orchestrates the flow. + +--- + +## Key Features + +- **Layered Architecture**: The application is divided into layers for better separation of concerns. +- **Scalable Design**: The modular approach makes it easier to extend functionality, such as adding new data preparation rules or presentation formats. +- **Reusability**: Each layer operates independently, promoting code reuse. + +--- + +## Related Resources + +- **GitHub Issue**: [Issue #1323](https://github.com/iluwatar/java-design-patterns/issues/1323) +- **Repository**: [java-design-patterns](https://github.com/iluwatar/java-design-patterns) +- **Design Pattern**: [Two-Step-View-Pattern](https://martinfowler.com/eaaCatalog/twoStepView.html) + + + diff --git a/two-step-view/pom.xml b/two-step-view/pom.xml new file mode 100644 index 000000000000..182b3aedfba2 --- /dev/null +++ b/two-step-view/pom.xml @@ -0,0 +1,53 @@ + + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.26.0-SNAPSHOT + + + two-step-view + + + 17 + 17 + UTF-8 + + + + junit + junit + test + + + + \ No newline at end of file diff --git a/two-step-view/src/main/java/com/iluwatar/App.java b/two-step-view/src/main/java/com/iluwatar/App.java new file mode 100644 index 000000000000..0dbde81a211d --- /dev/null +++ b/two-step-view/src/main/java/com/iluwatar/App.java @@ -0,0 +1,47 @@ +/* + * 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; + +import java.util.logging.Logger; + +/** Main class. */ +public class App { + private static final Logger logger = Logger.getLogger(App.class.getName()); + + /** Main function. */ + public static void main(String[] args) { + // Create a Book instance with sample data + Book book = new Book("Batman Vol. 1: The Court of Owls", 11.60, true, 10); + + // Convert raw book data into a structured format + BookStore preparedData = DataPreparation.prepareBook(book); + + String htmlOutput = Presentation.presentBook(preparedData); + + // Output the rendered HTML + logger.info(htmlOutput); + } +} + diff --git a/two-step-view/src/main/java/com/iluwatar/Book.java b/two-step-view/src/main/java/com/iluwatar/Book.java new file mode 100644 index 000000000000..ebaeeca2ee19 --- /dev/null +++ b/two-step-view/src/main/java/com/iluwatar/Book.java @@ -0,0 +1,37 @@ +/* + * 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; +import lombok.AllArgsConstructor; +import lombok.Data; + +/** Represents a Book. */ +@AllArgsConstructor +@Data +public class Book { + String name; + double price; + boolean discount; + int stock; +} diff --git a/two-step-view/src/main/java/com/iluwatar/BookStore.java b/two-step-view/src/main/java/com/iluwatar/BookStore.java new file mode 100644 index 000000000000..7352ebff9095 --- /dev/null +++ b/two-step-view/src/main/java/com/iluwatar/BookStore.java @@ -0,0 +1,38 @@ +/* + * 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; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** Represents the processed book data used for display purposes. */ +@AllArgsConstructor +@Data +public class BookStore { + String name; + double price; + double discountPrice; // Calculates price if the book is discounted + boolean inStock; // Indicates if the book is in stock +} diff --git a/two-step-view/src/main/java/com/iluwatar/DataPreparation.java b/two-step-view/src/main/java/com/iluwatar/DataPreparation.java new file mode 100644 index 000000000000..3d25e92d9e93 --- /dev/null +++ b/two-step-view/src/main/java/com/iluwatar/DataPreparation.java @@ -0,0 +1,43 @@ +/* + * 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; + + + +/** class representing phase 1. */ +public class DataPreparation { + + private DataPreparation() {} + /** + * Prepares book data for the store. + * Calculates the discount price if applicable and checks stock availability. + */ + + public static BookStore prepareBook(Book book) { + double discountPrice = book.isDiscount() ? book.getPrice() * 0.75 : book.getPrice(); + boolean inStock = book.getStock() > 0; + return new BookStore(book.getName(), book.getPrice(), discountPrice, inStock); + } +} diff --git a/two-step-view/src/main/java/com/iluwatar/Presentation.java b/two-step-view/src/main/java/com/iluwatar/Presentation.java new file mode 100644 index 000000000000..49d6c71a8515 --- /dev/null +++ b/two-step-view/src/main/java/com/iluwatar/Presentation.java @@ -0,0 +1,47 @@ +/* + * 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; +/** Phase 2.*/ +public class Presentation { + private Presentation() {} + /** Generates an HTML representation of the book details.*/ + public static String presentBook(BookStore bookInStore) { + String newLine = System.lineSeparator(); + return "
" + + newLine + + "

" + bookInStore.getName() + "

" + + newLine + + "

Price: $" + bookInStore.getPrice() + "

" + + newLine + + "

Discounted Price: $" + bookInStore.getDiscountPrice() + "

" + + newLine + + "

Status: " + + (bookInStore.isInStock() ? "In Stock" : "Out of Stock") + + "

" + + newLine + + "
"; + } +} + diff --git a/two-step-view/src/test/java/com/iluwatar/BookStoreTest.java b/two-step-view/src/test/java/com/iluwatar/BookStoreTest.java new file mode 100644 index 000000000000..3ef115104fe7 --- /dev/null +++ b/two-step-view/src/test/java/com/iluwatar/BookStoreTest.java @@ -0,0 +1,43 @@ +package com.iluwatar; + +import org.junit.Test; + +import static org.junit.Assert.*; + + +public class BookStoreTest { + + @Test + public void testWithDiscount() { + Book bookWithDiscount = new Book("Superman Vol. 1", 20.00, true, 5); + BookStore bookStoreWithDiscount = DataPreparation.prepareBook(bookWithDiscount); + + assertNotNull(bookStoreWithDiscount); + assertTrue(bookStoreWithDiscount.getName().contains("Superman Vol. 1")); + assertEquals(15.00, bookStoreWithDiscount.getDiscountPrice(), 0.01); + assertTrue(bookStoreWithDiscount.isInStock()); + } + + @Test + public void testWithoutDiscount() { + Book bookWithoutDiscount = new Book("Superman Vol. 1", 20.00, false, 5); + BookStore bookStoreWithoutDiscount = DataPreparation.prepareBook(bookWithoutDiscount); + + assertNotNull(bookStoreWithoutDiscount); + assertTrue(bookStoreWithoutDiscount.getName().contains("Superman Vol. 1")); + assertEquals(20.00, bookStoreWithoutDiscount.getDiscountPrice(), 0.01); + assertTrue(bookStoreWithoutDiscount.isInStock()); + } + + @Test + public void testWithOutOfStock() { + Book bookOutOfStock = new Book("Superman Vol. 1", 20.00, true, 0); + BookStore bookStoreOutOfStock = DataPreparation.prepareBook(bookOutOfStock); + + assertNotNull(bookStoreOutOfStock); + assertTrue(bookStoreOutOfStock.getName().contains("Superman Vol. 1")); + assertEquals(15.00, bookStoreOutOfStock.getDiscountPrice(), 0.01); + assertFalse(bookStoreOutOfStock.isInStock()); + } + +} diff --git a/update-header.sh b/update-header.sh index 48da4dcd6125..568d00d52a03 100755 --- a/update-header.sh +++ b/update-header.sh @@ -1,4 +1,29 @@ #!/bin/bash +# +# 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. +# + # Find all README.md files in subdirectories one level deep # and replace "### " with "## " at the beginning of lines From 53afd1fe62cdd8de687a552fc5aba6aa510fff05 Mon Sep 17 00:00:00 2001 From: Faris Sharara Date: Thu, 5 Dec 2024 17:02:27 +0200 Subject: [PATCH 2/3] Fixed tet coverage and fixed some edge cases --- .../src/main/java/com/iluwatar/Book.java | 14 +++- .../src/main/java/com/iluwatar/BookStore.java | 1 + .../test/java/com/iluwatar/BookStoreTest.java | 70 +++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/two-step-view/src/main/java/com/iluwatar/Book.java b/two-step-view/src/main/java/com/iluwatar/Book.java index ebaeeca2ee19..add59c4db181 100644 --- a/two-step-view/src/main/java/com/iluwatar/Book.java +++ b/two-step-view/src/main/java/com/iluwatar/Book.java @@ -23,15 +23,25 @@ * THE SOFTWARE. */ package com.iluwatar; -import lombok.AllArgsConstructor; import lombok.Data; /** Represents a Book. */ -@AllArgsConstructor @Data public class Book { String name; double price; boolean discount; int stock; + Book(String name, double price, boolean discount, int stock) { + if (!name.isEmpty()) { // Make sure is not empty + this.name = name; + } + if (price > 0) { // Make sure price is set with a realistic value + this.price = price; + } + if (stock >= 0) { // Make sure stock is not negative + this.stock = stock; + } + this.discount = discount; + } } diff --git a/two-step-view/src/main/java/com/iluwatar/BookStore.java b/two-step-view/src/main/java/com/iluwatar/BookStore.java index 7352ebff9095..c3d14386883c 100644 --- a/two-step-view/src/main/java/com/iluwatar/BookStore.java +++ b/two-step-view/src/main/java/com/iluwatar/BookStore.java @@ -35,4 +35,5 @@ public class BookStore { double price; double discountPrice; // Calculates price if the book is discounted boolean inStock; // Indicates if the book is in stock + } diff --git a/two-step-view/src/test/java/com/iluwatar/BookStoreTest.java b/two-step-view/src/test/java/com/iluwatar/BookStoreTest.java index 3ef115104fe7..2e693c016043 100644 --- a/two-step-view/src/test/java/com/iluwatar/BookStoreTest.java +++ b/two-step-view/src/test/java/com/iluwatar/BookStoreTest.java @@ -5,6 +5,12 @@ import static org.junit.Assert.*; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; +import java.util.logging.Logger; + + public class BookStoreTest { @Test @@ -40,4 +46,68 @@ public void testWithOutOfStock() { assertFalse(bookStoreOutOfStock.isInStock()); } + @Test + public void testPrepareZeroPrice() { + Book book = new Book("Zero Price Book", 0.00, true, 5); + BookStore bookStore = DataPreparation.prepareBook(book); + + assertNotNull(bookStore); + assertEquals(0.00, bookStore.getDiscountPrice(), 0.01); + assertTrue(bookStore.isInStock()); + } + + @Test + public void testPrepareNegativeStock() { + Book book = new Book("Negative Stock Book", 10.00, false, -1); + BookStore bookStore = DataPreparation.prepareBook(book); + + assertNotNull(bookStore); + assertFalse(bookStore.isInStock()); + } + + @Test + public void testPresentInStock() { + BookStore bookInStock = new BookStore("Wonder Woman Vol. 1", 15.00, 12.00, true); + String htmlOutput = Presentation.presentBook(bookInStock); + + assertNotNull(htmlOutput); + assertTrue(htmlOutput.contains("

Wonder Woman Vol. 1

")); + assertTrue(htmlOutput.contains("

Price: $15.0

")); + assertTrue(htmlOutput.contains("

Discounted Price: $12.0

")); + assertTrue(htmlOutput.contains("

Status: In Stock

")); + } + + @Test + public void testPresentOutOfStock() { + BookStore bookOutOfStock = new BookStore("Wonder Woman Vol. 1", 15.00, 12.00, false); + String htmlOutput = Presentation.presentBook(bookOutOfStock); + + assertNotNull(htmlOutput); + assertTrue(htmlOutput.contains("

Wonder Woman Vol. 1

")); + assertTrue(htmlOutput.contains("

Price: $15.0

")); + assertTrue(htmlOutput.contains("

Discounted Price: $12.0

")); + assertTrue(htmlOutput.contains("

Status: Out of Stock

")); + } + + @Test + public void testMain() { + // Redirect System.out to capture logger output + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + PrintStream printStream = new PrintStream(outputStream); + Logger.getLogger("").addHandler(new java.util.logging.ConsoleHandler() { + { + setOutputStream(printStream); + } + }); + + // Run the main method + App.main(new String[]{}); + + // Check output contains expected HTML + String loggedOutput = outputStream.toString(); + assertTrue(loggedOutput.contains("

Batman Vol. 1: The Court of Owls

")); + assertTrue(loggedOutput.contains("

Price: $11.6

")); + assertTrue(loggedOutput.contains("

Discounted Price: $8.7

")); + assertTrue(loggedOutput.contains("

Status: In Stock

")); + } } From a3fe2745322d5a299d40e49fff66efeb16687f04 Mon Sep 17 00:00:00 2001 From: Faris Sharara Date: Wed, 22 Jan 2025 21:09:57 +0200 Subject: [PATCH 3/3] Resolved Reviews --- two-step-view/README.md | 179 +++++++++++++----- two-step-view/pom.xml | 26 ++- .../src/main/java/com/iluwatar/App.java | 13 ++ 3 files changed, 160 insertions(+), 58 deletions(-) diff --git a/two-step-view/README.md b/two-step-view/README.md index a8962999cc15..018df900c461 100644 --- a/two-step-view/README.md +++ b/two-step-view/README.md @@ -1,79 +1,156 @@ -# Book Data Processing and Presentation +# Two-Step View -This example demonstrates a simple pipeline for processing book data and rendering it as an HTML view. It involves three main steps: **data preparation**, **business logic processing**, and **presentation**. The structure of the program aligns with the principles of the **Presentation-Abstraction-Control (PAC)** design pattern. --- -## Problem Addressed -This implementation solves the issue described in [Issue #1323](https://github.com/iluwatar/java-design-patterns/issues/1323) of the [java-design-patterns repository](https://github.com/iluwatar/java-design-patterns). The goal is to showcase how to split application logic into phases while keeping the layers loosely coupled. +## Also known as +- Template View. +- Model-View Separation +- Separated Presentation +- View Helper Pattern --- -## Overview of the Solution -The program is divided into the following parts: +## Intent of Two-Step View Design Pattern +- **Decouple Data and Presentation**: Separate data preparation from rendering for better modularity. +- **Reusable Rendering**: Use templates to reduce duplication. +- **Flexibility**: Render the same data differently with various templates. +- **Maintainability**: Simplify testing and updates by isolating logic. +- **Multi-Format Support**: Prepare data once and render in formats like HTML or JSON. +--- + +## Detailed Explanation of the Two Step View Pattern with Real-World Examples + +**Real-World Example**: +Imagine a restaurant kitchen. + +**Step 1**: Preparation – The chef cooks and plates the food, ensuring it is ready to be served. -1. **Data Layer** - - The `Book` class represents the raw data for a book. - - The `BookStore` class holds the processed book data for display. +**Step 2**: Presentation – The waiter serves the plated food to the customer, adding any final touches, such as garnishes. -2. **Logic Layer** - - The `DataPreparation` class handles the business logic. It computes whether a discount is applied and checks stock availability. +**In Plain Words**: The Two-Step View Pattern separates the process of preparing data from how it is presented. -3. **Presentation Layer** - - The `Presentation` class generates an HTML view of the book data. +**Authoritative Source**: Martin Fowler describes the Two-Step View pattern as transforming domain data into HTML in two stages: first by creating a logical page, then rendering it into HTML.(https://martinfowler.com/eaaCatalog/twoStepView.html) --- -## How to Run the Code - -1. Clone the repository: - ```bash - git clone https://github.com/iluwatar/java-design-patterns.git - cd java-design-patterns - ``` - -2. Compile and run the `App` class: - ```bash - javac com/iluwatar/*.java - java com.iluwatar.App - ``` - -3. Expected Output: - The program generates an HTML representation of the book data and prints it to the console: - ```html -
-

Batman Vol. 1: The Court of Owls

-

Price: $11.6

-

Discounted Price: $8.7

-

Status: In Stock

-
- ``` +## Programmatic Example of Two-Step View Pattern in Java + + +#### **Phase 1: Data Preparation (`DataPreparation`)** +- **Responsibility:** Processes raw `Book` data by calculating the discount price and checking stock availability. +- **Method:** `prepareBook(Book book)` +- **Output:** Returns a `BookStore` object with processed details. +- **Example:** + ```java + BookStore bookStore = DataPreparation.prepareBook(book); + ``` + +#### **Phase 2: Presentation (`Presentation`)** +- **Responsibility:** Converts the prepared `BookStore` data into an HTML representation. +- **Method:** `presentBook(BookStore bookInStore)` +- **Output:** HTML formatted book details. +- **Example:** + ```java + String bookHtml = Presentation.presentBook(bookStore); + ``` + + +--- + +## When to Use the Two Step View Pattern in Java + +- **Separation of Logic:** When you need to separate data preparation from presentation for better modularity. +- **Multiple Formats:** When the same data needs to be rendered in multiple formats (e.g., HTML, JSON, XML). +- **Reusable Templates:** When you want to reuse rendering logic across different parts of the application. +- **Maintainability:** When frequent changes in the presentation layer shouldn't impact the business logic or data preparation. +- **Flexibility:** When different rendering methods are required for the same prepared data based on user preferences or contexts. +- **Scalability:** When adding new presentation formats without affecting existing preparation logic is needed. +- **MVC Architecture:** When implementing the Model-View-Controller (MVC) design pattern, where the model (data preparation) and view (presentation) are distinctly separate. +- **Testability:** When isolating and unit testing data preparation and rendering logic independently is a priority. --- +## Two-Step View Pattern Java Tutorials + + +- **Martin Fowler's Explanation**: Martin Fowler discusses the Two-Step View pattern, detailing its application in transforming domain data into HTML in two stages.(https://martinfowler.com/eaaCatalog/twoStepView) + +- **Stack Overflow Discussion**: A discussion on Stack Overflow explores the implementation of the Two Step View pattern in Spring MVC, highlighting its benefits and practical considerations.(https://stackoverflow.com/questions/58114790/spring-mvc-one-step-view-or-two-step-view) -## Code Structure +- **Java Design Patterns Tutorial**: This comprehensive tutorial covers various design patterns in Java, including structural patterns that may relate to the Two Step View pattern.(https://www.digitalocean.com/community/tutorials/java-design-patterns-example-tutorial) -- `Book`: Represents raw book data with fields like `name`, `price`, `discount`, and `stock`. -- `BookStore`: Represents processed data including `discountPrice` and `inStock` status. -- `DataPreparation`: Contains logic to calculate the discount price and determine stock status. -- `Presentation`: Generates the HTML view of the book data. -- `App`: Entry point that orchestrates the flow. + +--- +## Real-World Applications of Two-Step View Pattern in Java + +- **Spring MVC**: Separates the logic of data preparation from view rendering, using technologies like JSP, Thymeleaf, or FreeMarker. ([Stack Overflow discussion](https://stackoverflow.com/questions/58114790/spring-mvc-one-step-view-or-two-step-view)) +- **Composite View Pattern**: Similar to Two Step View, this pattern involves composing view components into tree structures, promoting separation of concerns. ([Java Design Patterns - Composite View](https://java-design-patterns.com/patterns/composite-view/?utm_source=chatgpt.com)) +- **Martin Fowler's Two Step View**: A foundational explanation of transforming domain data into HTML in two stages, applied in web applications. ([martinfowler.com](https://martinfowler.com/eaaCatalog/twoStepView.html?utm_source=chatgpt.com)) +--- +### **Benefits of the Two Step View Pattern** + +- **Separation of Concerns:** Separates data processing from presentation logic, making the system more modular and easier to maintain. +- **Reusability:** Data preparation and presentation can be reused independently across different views or formats. +- **Flexibility:** Easily switch or modify the presentation layer (e.g., HTML, XML, JSON) without changing the underlying data logic. +- **Maintainability:** Changes in the data model or presentation logic are isolated, reducing the risk of side effects. +- **Testability:** Each phase (data preparation and rendering) can be unit tested independently, improving code quality and reliability. +- **Scalability:** Adding new views or presentation formats becomes easier without altering the core business logic. +--- + +## **Trade-offs of the Two Step View Pattern** + +- **Increased Complexity:** Implementing two separate steps adds complexity, particularly in smaller applications where a simple approach may suffice. +- **Performance Overhead:** Dividing the logic into two phases may introduce unnecessary overhead, especially in performance-critical applications. +- **Over-engineering:** For simple applications, the pattern might be overkill, leading to unnecessary abstraction. +- **Tighter Coupling of Phases:** If not designed properly, the two phases (data preparation and presentation) might still become tightly coupled, reducing the pattern's effectiveness. +- **Development Time:** The initial implementation of two phases may require more time compared to simpler, more straightforward methods. --- +## **Related Java Design Patterns** -## Key Features +- **Model-View-Controller (MVC):** Separates data (Model), presentation (View), and user interaction (Controller), which is conceptually similar to the Two Step View pattern. + [Learn more](https://refactoring.guru/design-patterns/mvc) -- **Layered Architecture**: The application is divided into layers for better separation of concerns. -- **Scalable Design**: The modular approach makes it easier to extend functionality, such as adding new data preparation rules or presentation formats. -- **Reusability**: Each layer operates independently, promoting code reuse. +- **Composite View:** Builds complex views by combining multiple components into a tree structure, promoting modularity in rendering views. + [Learn more](https://java-design-patterns.com/patterns/composite-view/?utm_source=chatgpt.com) +- **Template Method:** Defines the structure of an algorithm but allows certain steps to be implemented by subclasses, similar to separating data preparation from presentation. + [Learn more](https://refactoring.guru/design-patterns/template-method) + +- **Strategy Pattern:** Allows the selection of algorithms (e.g., data preparation or presentation rendering) at runtime, offering flexibility in handling multiple views. + [Learn more](https://refactoring.guru/design-patterns/strategy) + +- **Decorator Pattern:** Adds behavior or functionality to an object dynamically, which can be useful for enhancing view rendering capabilities. + [Learn more](https://refactoring.guru/design-patterns/decorator) + +- **Abstract Factory Pattern:** Creates families of related objects without specifying their concrete classes, similar to abstracting view rendering across different formats. + [Learn more](https://refactoring.guru/design-patterns/abstract-factory) --- +## **References and Credits for the Two Step View Pattern** + +- **"Patterns of Enterprise Application Architecture"** by Martin Fowler + A key resource explaining the Two Step View pattern, among other enterprise application design patterns. + [Link to book](https://martinfowler.com/books/eaa.html) + +- **"Design Patterns: Elements of Reusable Object-Oriented Software"** by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides + This book outlines foundational design patterns that are conceptually related to the Two Step View pattern, like MVC and Composite View. + [Link to book](https://www.pearson.com/store/p/design-patterns-elements-of-reusable-object-oriented-software/P100000825256) + +- **"Refactoring: Improving the Design of Existing Code"** by Martin Fowler + Discusses how to refactor code in a way that aligns with the principles of modularity and separation of concerns, which are also key goals of the Two Step View pattern. + [Link to book](https://martinfowler.com/books/refactoring.html) + +- **"Head First Design Patterns"** by Eric Freeman and Elisabeth Robson + A beginner-friendly resource that explains various design patterns, including those related to view rendering, like MVC and Composite View. + [Link to book](https://www.oreilly.com/library/view/head-first-design/9780596007126/) -## Related Resources +- **"Java Design Patterns: A Hands-On Experience with Real-World Examples"** by Vaskaran Sarcar + Provides practical examples of design patterns in Java, with potential applications for the Two Step View pattern. + [Link to book](https://www.amazon.com/Java-Design-Patterns-Hands-Experience/dp/1788621754) -- **GitHub Issue**: [Issue #1323](https://github.com/iluwatar/java-design-patterns/issues/1323) -- **Repository**: [java-design-patterns](https://github.com/iluwatar/java-design-patterns) -- **Design Pattern**: [Two-Step-View-Pattern](https://martinfowler.com/eaaCatalog/twoStepView.html) +- **"Design Patterns in Java"** by Steven John Metsker + A book that covers Java-specific examples of design patterns and explores how they can be used effectively in enterprise applications. + [Link to book](https://www.amazon.com/Design-Patterns-Java-Steven-Metsker/dp/0321192958) diff --git a/two-step-view/pom.xml b/two-step-view/pom.xml index 182b3aedfba2..ac1046847e91 100644 --- a/two-step-view/pom.xml +++ b/two-step-view/pom.xml @@ -36,12 +36,6 @@ two-step-view - - - 17 - 17 - UTF-8 - junit @@ -49,5 +43,23 @@ test - + + + + org.apache.maven.plugins + maven-assembly-plugin + + + + + + com.iluwatar.model.view.presenter.App + + + + + + + + \ No newline at end of file diff --git a/two-step-view/src/main/java/com/iluwatar/App.java b/two-step-view/src/main/java/com/iluwatar/App.java index 0dbde81a211d..9a242efcbee5 100644 --- a/two-step-view/src/main/java/com/iluwatar/App.java +++ b/two-step-view/src/main/java/com/iluwatar/App.java @@ -26,6 +26,18 @@ import java.util.logging.Logger; +/* + * The Two Step View Pattern: + * Separates generating dynamic web content into: + * 1. Data Preparation: Raw data is structured for presentation. + * 2. Data Presentation: Prepared data is rendered into a display format (e.g., HTML). + * This enhances modularity, maintainability, and testability by decoupling preparation and presentation. + + * Implementation in this Example: + * 1. Data Preparation: `DataPreparation` transforms a `Book` into a `BookStore` object, calculating discount prices and stock status. + * 2. Data Presentation: `Presentation` generates an HTML view of the `BookStore` object, focusing only on rendering. + */ + /** Main class. */ public class App { private static final Logger logger = Logger.getLogger(App.class.getName()); @@ -38,6 +50,7 @@ public static void main(String[] args) { // Convert raw book data into a structured format BookStore preparedData = DataPreparation.prepareBook(book); + // Converts the prepared book data into an HTML string for display String htmlOutput = Presentation.presentBook(preparedData); // Output the rendered HTML