docs: improve execute around

This commit is contained in:
Ilkka Seppälä
2024-04-17 21:21:37 +03:00
parent 9615fd9e72
commit 59d3e52434
3 changed files with 57 additions and 32 deletions
+53 -25
View File
@@ -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)
@@ -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
@@ -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.
*/