From 59d3e52434401f58ebe2b619ba947b3c63baf95b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Wed, 17 Apr 2024 21:21:37 +0300 Subject: [PATCH] docs: improve execute around --- execute-around/README.md | 78 +++++++++++++------ .../java/com/iluwatar/execute/around/App.java | 6 +- .../com/iluwatar/execute/around/AppTest.java | 5 +- 3 files changed, 57 insertions(+), 32 deletions(-) diff --git a/execute-around/README.md b/execute-around/README.md index 613f45ed4..1587a1da5 100644 --- a/execute-around/README.md +++ b/execute-around/README.md @@ -1,44 +1,47 @@ --- title: Execute Around -category: Idiom +category: Behavioral language: en tag: - - Extensibility + - Closure + - Code simplification + - Encapsulation + - Functional decomposition + - Resource management --- +## Also known as + +* Around Method Pattern +* Resource Block Management + ## Intent -Execute Around idiom frees the user from certain actions that should always be executed before and -after the business method. A good example of this is resource allocation and deallocation leaving -the user to specify only what to do with the resource. +Execute Around idiom frees the user from certain actions that should always be executed before and after the business method. A good example of this is resource allocation and deallocation leaving the user to specify only what to do with the resource. ## Explanation Real-world example -> A class needs to be provided for writing text strings to files. To make it easy for -> the user, the service class opens and closes the file automatically. The user only has to -> specify what is written into which file. +> A class needs to be provided for writing text strings to files. To make it easy for the user, the service class opens and closes the file automatically. The user only has to specify what is written into which file. In plain words -> Execute Around idiom handles boilerplate code before and after business method. +> Execute Around idiom handles boilerplate code before and after business method. [Stack Overflow](https://stackoverflow.com/questions/341971/what-is-the-execute-around-idiom) says -> Basically it's the pattern where you write a method to do things which are always required, e.g. -> resource allocation and clean-up, and make the caller pass in "what we want to do with the -> resource". +> Basically it's the pattern where you write a method to do things which are always required, e.g. resource allocation and clean-up, and make the caller pass in "what we want to do with the resource". **Programmatic Example** -`SimpleFileWriter` class implements the Execute Around idiom. It takes `FileWriterAction` as a -constructor argument allowing the user to specify what gets written into the file. +`SimpleFileWriter` class implements the Execute Around idiom. It takes `FileWriterAction` as a constructor argument allowing the user to specify what gets written into the file. ```java + @FunctionalInterface public interface FileWriterAction { - void writeFile(FileWriter writer) throws IOException; + void writeFile(FileWriter writer) throws IOException; } @Slf4j @@ -54,18 +57,18 @@ public class SimpleFileWriter { } ``` -The following code demonstrates how `SimpleFileWriter` is used. `Scanner` is used to print the file -contents after the writing finishes. +The following code demonstrates how `SimpleFileWriter` is used. `Scanner` is used to print the file contents after the writing finishes. ```java -FileWriterAction writeHello = writer -> { - writer.write("Gandalf was here"); -}; +// create the file writer and execute the custom action +FileWriterAction writeHello = writer -> writer.write("Gandalf was here"); new SimpleFileWriter("testfile.txt", writeHello); -var scanner = new Scanner(new File("testfile.txt")); -while (scanner.hasNextLine()) { -LOGGER.info(scanner.nextLine()); +// print the file contents +try (var scanner = new Scanner(new File("testfile.txt"))) { + while (scanner.hasNextLine()) { + LOGGER.info(scanner.nextLine()); + } } ``` @@ -84,10 +87,35 @@ Here's the console output. ## Applicability -Use the Execute Around idiom when +* Useful in scenarios requiring repetitive setup and cleanup activities, particularly in resource management (e.g., files, network connections, database sessions). +* Ideal for ensuring proper resource handling and cleanup in the face of exceptions, ensuring resources do not leak. +* Suitable in any Java application where the same preparation and finalization steps are executed around varying core functionalities. -* An API requires methods to be called in pairs such as open/close or allocate/deallocate. +## Known Uses + +* Java's try-with-resources statement, which ensures that resources are closed after execution regardless of whether an exception was thrown. +* Frameworks like Spring for managing database transactions, where predefined cleanup or rollback operations are performed depending on the execution outcome. + +## Consequences + +Benefits: + +* Reduces boilerplate code by abstracting routine setup and cleanup tasks. +* Increases code clarity and maintainability by separating business logic from resource management. +* Ensures robustness by automatically handling resource cleanup, even in error situations. + +Trade-offs: + +* Introduces additional abstraction layers, which might increase complexity and obscure control flow for some developers. +* May require more sophisticated understanding of closures and functional interfaces in Java. + +## Related Patterns + +* [Template Method](https://java-design-patterns.com/patterns/template-method/): Similar in concept but differs in that it uses inheritance and abstract classes, while Execute Around typically uses interfaces and lambdas. +* [Decorator](https://java-design-patterns.com/patterns/decorator/): Shares the concept of adding functionality around a core component; can be extended to wrap additional behaviors dynamically. ## Credits +* [Effective Java](https://amzn.to/4aDdWbs) +* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3vUGApm) * [Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions](https://www.amazon.com/gp/product/1937785467/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1937785467&linkCode=as2&tag=javadesignpat-20&linkId=7e4e2fb7a141631491534255252fd08b) diff --git a/execute-around/src/main/java/com/iluwatar/execute/around/App.java b/execute-around/src/main/java/com/iluwatar/execute/around/App.java index a956dd57a..9291fd0ea 100644 --- a/execute-around/src/main/java/com/iluwatar/execute/around/App.java +++ b/execute-around/src/main/java/com/iluwatar/execute/around/App.java @@ -30,7 +30,7 @@ import java.util.Scanner; import lombok.extern.slf4j.Slf4j; /** - * The Execute Around idiom specifies executable code before and after a method. Typically + * The Execute Around idiom specifies executable code before and after a method. Typically, * the idiom is used when the API has methods to be executed in pairs, such as resource * allocation/deallocation or lock acquisition/release. * @@ -47,9 +47,7 @@ public class App { public static void main(String[] args) throws IOException { // create the file writer and execute the custom action - FileWriterAction writeHello = writer -> { - writer.write("Gandalf was here"); - }; + FileWriterAction writeHello = writer -> writer.write("Gandalf was here"); new SimpleFileWriter("testfile.txt", writeHello); // print the file contents diff --git a/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java index 5e54732fd..8df0c9939 100644 --- a/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java +++ b/execute-around/src/test/java/com/iluwatar/execute/around/AppTest.java @@ -24,14 +24,13 @@ */ package com.iluwatar.execute.around; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + import java.io.File; -import java.io.IOException; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - /** * Tests execute-around example. */