docs: update module

This commit is contained in:
Ilkka Seppälä
2024-05-09 11:04:01 +03:00
parent b6a1f18acf
commit 0810b5531c
+56 -56
View File
@@ -3,20 +3,21 @@ title: Module
category: Structural
language: en
tag:
- Decoupling
- Decoupling
- Encapsulation
- Layered architecture
- Object composition
---
## Intent
Module pattern is used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept.
The Module pattern aims to encapsulate a group of related elements, such as classes, functions, and variables, into a single unit or module, enhancing cohesion and reducing dependencies between different parts of an application.
## Explanation
Real-world example
> In a bustling software city, different software components such as Database, UI, and API often need to collaborate. Instead of each component directly talking with every other, they rely on the module manager. This module manager acts like a central marketplace, where each component registers its services and requests for others. This ensures that components remain decoupled, and changes to one don't ripple throughout the system.
> Imagine a modern smartphone. It has different apps like messaging, camera, and music player. While each app functions independently, they sometimes need shared resources like access to contacts or storage. Instead of every app having its unique way to access these resources, they use the phone's built-in modules, like the Contacts module or the Storage module. This ensures a consistent experience for the user and avoids potential clashes between apps.
> Consider the organization of a modern kitchen as a real-world analogy to the Module pattern. In a kitchen, different sections are dedicated to specific functions: there's a cooking module with stoves and ovens, a cleaning module with sinks and dishwashers, and a storage module with refrigerators and cabinets. Each module encapsulates all the tools and equipment needed for its specific function, ensuring they are not intermingled with those of other modules. This organization enhances efficiency, as each section has everything necessary for its tasks, and reduces confusion by keeping unrelated items separate. This modular approach mirrors the Module pattern in software, where different functionalities are grouped into distinct, self-contained units that manage their own resources and dependencies.
In plain words
@@ -25,24 +26,18 @@ In plain words
Wikipedia says
> In software engineering, the module pattern is a design pattern used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept.
>
> This pattern can be implemented in several ways depending on the host programming language, such as the singleton design pattern, object-oriented static members in a class and procedural global functions. In Python, the pattern is built into the language, and each .py file is automatically a module. The same applies to Ada, where the package can be considered a module (similar to a static class).
**Programmatic Example**
The Module design pattern is a design pattern that provides a way to wrap a set of related functionalities into a single unit, which can be an object or a function. This pattern is particularly useful in large systems where it's necessary to group related functionality and data to improve code organization and readability.
In the provided code, we have a great example of the Module pattern. The pattern is implemented using two modules: `FileLoggerModule` and `ConsoleLoggerModule`. Both of these modules are singletons, meaning that only one instance of each module can exist at a time.
Here's a simplified version of the `FileLoggerModule`:
```java
//Define Logger abstract class
abstract class Logger {
protected String output;
protected String error;
public abstract void prepare();
public abstract void unprepare();
public abstract void printString(String message);
public abstract void printErrorString(String errorMessage);
}
//File log module
class FileLoggerModule extends Logger {
private static final String OUTPUT_FILE = "output.log";
private static final String ERROR_FILE = "error.log";
@@ -61,18 +56,6 @@ class FileLoggerModule extends Logger {
return instance;
}
@Override
public void prepare() {
// For example, open file operation
// add the action you want
}
@Override
public void unprepare() {
// For example, close file operation
// add the action you want
}
@Override
public void printString(String message) {
System.out.println("Writing to " + output + ": " + message);
@@ -83,8 +66,13 @@ class FileLoggerModule extends Logger {
System.out.println("Writing to " + error + ": " + errorMessage);
}
}
```
//Console log module
In this module, we have a `getSingleton` method that ensures only one instance of `FileLoggerModule` is created. The `printString` and `printErrorString` methods are used to print messages and errors to the console, simulating writing to a file.
Similarly, the `ConsoleLoggerModule` is another module that logs messages and errors to the console:
```java
class ConsoleLoggerModule extends Logger {
private static ConsoleLoggerModule instance;
@@ -97,16 +85,6 @@ class ConsoleLoggerModule extends Logger {
return instance;
}
@Override
public void prepare() {
//Initialize console operation
}
@Override
public void unprepare() {
//End console operation
}
@Override
public void printString(String message) {
System.out.println("Console Output: " + message);
@@ -117,19 +95,17 @@ class ConsoleLoggerModule extends Logger {
System.err.println("Console Error: " + errorMessage);
}
}
```
In the `App` class, these modules are used to log messages:
```java
public class App {
public void prepare() {
FileLoggerModule.getSingleton().prepare();
ConsoleLoggerModule.getSingleton().prepare();
}
public void unprepare() {
FileLoggerModule.getSingleton().unprepare();
ConsoleLoggerModule.getSingleton().unprepare();
}
public void execute(String message) {
FileLoggerModule.getSingleton().printString(message);
ConsoleLoggerModule.getSingleton().printString(message);
@@ -144,20 +120,44 @@ public class App {
}
```
Programme outputs:
```
Writing to output.log: Hello, Module Pattern!
Console Output: Hello, Module Pattern!
```
In the `prepare` method, the `prepare` method of each module is called. In the `execute` method, the `printString` method of each module is used to log a message. This demonstrates how the Module pattern can be used to encapsulate related functionality into a single unit, improving code organization and readability.
## Class diagram
![alt text](./etc/module.png "Module")
![Module](./etc/module.png "Module")
## Applicability
The Module pattern can be considered a creational pattern and a structural pattern. It manages the creation and organization of other elements, and groups them as the structural pattern does.
An object that applies this pattern can provide the equivalent of a namespace, providing the initialization and finalization process of a static class or a class with static members with cleaner, more concise syntax and semantics.
* When you need to group related functionality and data to improve code organization and readability.
* To encapsulate internal details of a part of a program, exposing only what is necessary through a well-defined interface.
* Useful in large systems for dividing the codebase into manageable sections.
## Known Uses
* Java Platform Module System introduced in Java 9.
* Organizing libraries or frameworks into coherent units.
* Web applications that segment logic into various modules for maintainability.
## Consequences
Benefits:
* Enhances code clarity and maintainability by grouping related features.
* Reduces global scope pollution and namespace clashes.
* Facilitates better testing and debugging by isolating functionalities.
Trade-offs:
* Initial complexity in setting up modules and their interactions.
* Over-modularization can lead to unnecessary complexity and overhead.
## Related Patterns
* [Facade](https://java-design-patterns.com/patterns/facade/): Simplifies the module's interface for clients. Both aim to simplify usage by hiding complexity.
* [Singleton](https://java-design-patterns.com/patterns/singleton/): Often used within a module to ensure a single instance of a component is used across the system.
## Credits
* [Module](https://en.wikipedia.org/wiki/Module_pattern)
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
* [Effective Java](https://amzn.to/4cGk2Jz)
* [Java 9 Modularity: Patterns and Practices for Developing Maintainable Applications](https://amzn.to/4b4CWIK)