Module
The Module pattern is a structural design pattern that aims to reduce the complexity of a software system by dividing it into independent, interchangeable modules. Each module encapsulates a specific set of related functionalities, offering a well-defined interface to interact with other parts of the system. This promotes separation of concerns, making the system easier to understand, maintain, and test.
Essentially, a module acts as a building block. By composing a system out of modules, developers can minimize dependencies and coupling between different parts of the application. This allows for independent development, testing, and deployment of modules, and facilitates reuse across different projects. Modules can be dynamically loaded and unloaded, adding flexibility to the system.
Usage
The Module pattern is widely used in modern software development for several reasons:
- Large Applications: Breaking huge applications into smaller, manageable modules dramatically improves maintainability and understandability.
- Plugin Systems: It’s the cornerstone of plugin architectures, allowing external developers to extend functionality without modifying the core application.
- Microservices: Each microservice can be considered a module, loosely coupled and independently deployable.
- Code Organization: Used for organizing code into logical groups for improved readability and modularity even in smaller projects.
- Dynamic Loading: Systems that need to load and unload functionality based on runtime conditions benefit from this pattern.
Examples
-
Node.js Modules (CommonJS/ES Modules): Node.js leverages modules extensively. Each file in a Node.js project is treated as a separate module, and the
require()(CommonJS) orimport(ES Modules) statements are used to access and use the functionalities of other modules. This allows for creating reusable packages that can be installed via npm (Node Package Manager). The module system enables a significant ecosystem of third-party integrations. -
Java Modules (Java 9+): Java 9 introduced the module system to address issues with long-term maintainability and security of large Java applications. Modules explicitly declare their dependencies and which parts of their internal code are exposed to other modules. This provides stronger encapsulation and allows the Java runtime to optimize application loading and execution. The
module-info.javafile defines the module’s boundaries. -
Python Packages: Python utilizes packages (directories containing
__init__.pyfiles) as modules. You can import specific modules or subpackages within a package, providing a hierarchical way to organize code. This helps in creating structured and reusable Python libraries, like Django or Flask.
Specimens
15 implementationsThe Module pattern encapsulates related functionality into a self-contained unit, exposing only a public API while hiding implementation details. This promotes code organization, reduces global namespace pollution, and enhances maintainability. In Dart, this is naturally achieved using libraries and private members (prefixed with an underscore _). The example demonstrates a CalculatorModule with internal methods for performing calculations and a public calculate method to access them. This aligns with Dart’s library-centric approach, where libraries define modules and the underscore prefix enforces encapsulation, a core Dart principle.
// calculator_module.dart
library calculator_module;
// Internal helper function
double _add(double a, double b) {
return a + b;
}
// Internal helper function
double _subtract(double a, double b) {
return a - b;
}
// Public API - the module's exposed interface
class CalculatorModule {
double calculate(double a, double b, String operation) {
switch (operation) {
case 'add':
return _add(a, b);
case 'subtract':
return _subtract(a, b);
default:
throw ArgumentError('Invalid operation');
}
}
}
The Module Pattern in Scala is achieved through the use of objects. Objects are singleton instances of classes and act as namespaces for related functions and data. This provides a way to encapsulate state and behavior, preventing accidental modification from outside and promoting code organization.
In this example, the Calculator object encapsulates the addition and subtraction operations. The operations are defined as private methods, and only public methods are exposed to the user. This adheres to the principle of information hiding. Scala’s object-oriented nature makes this a natural and concise way to implement the Module Pattern, avoiding the need for explicit class instantiation and static members. The use of object is the idiomatic way to create modules in Scala.
object Calculator {
private def add(x: Int, y: Int): Int =
x + y
private def subtract(x: Int, y: Int): Int =
x - y
def calculateSum(x: Int, y: Int): Int =
add(x, y)
def calculateDifference(x: Int, y: Int): Int =
subtract(x, y)
}
// Example Usage:
object Main extends App {
val sum = Calculator.calculateSum(5, 3)
val difference = Calculator.calculateDifference(10, 4)
println(s"Sum: $sum")
println(s"Difference: $difference")
}
The Module pattern in PHP aims to encapsulate functionality and data within a single unit, exposing only a public interface while keeping internal details private. This promotes code organization, reduces global namespace pollution, and enhances maintainability. The implementation uses a closure to create a private scope. Variables and functions defined within the closure are only accessible through the returned public methods. This approach is idiomatic PHP as it leverages closures, a core language feature, to achieve encapsulation without requiring classes in simpler scenarios. It’s a lightweight alternative when full object-oriented structure isn’t necessary.
<?php
/**
* Module Pattern Example in PHP
*/
$module = function() {
// Private variables and functions
$privateVariable = 'Secret Value';
function privateFunction() {
return 'This is a private function.';
}
// Public interface
return [
'getPrivateVariable' => function() use ($privateVariable) {
return $privateVariable;
},
'publicFunction' => function() {
return 'This is a public function that calls a private one: ' . privateFunction();
},
];
};
// Usage
echo $module()['getPrivateVariable']() . "\n";
echo $module()['publicFunction']() . "\n";
// Attempting to access private parts directly will result in an error
// echo $module()['privateVariable']; // Fatal error: Uncaught Error: Call to undefined function
?>
The Module pattern in Ruby provides a way to encapsulate related methods and constants, creating namespaces and avoiding naming conflicts. It’s akin to static classes in other languages, but with more flexibility. This implementation defines a StringExtensions module containing a method to check if a string is a valid email address. The module is then mixed into the String class using include, effectively adding the valid_email? method to all string objects. This is a common Ruby idiom for extending built-in classes without modifying their core definition, promoting code organization and reusability.
# frozen_string_literal: true
module StringExtensions
refine do
def valid_email?(regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i)
match?(regex)
end
end
end
String.include StringExtensions
# Example Usage:
puts "test@example.com".valid_email? # Output: true
puts "invalid-email".valid_email? # Output: false
puts "another.test@sub.example.co.uk".valid_email? # Output: true
The Module Pattern is a way to encapsulate related functionality within a single object, exposing only a public API while hiding internal implementation details. This promotes code organization, prevents naming conflicts, and enhances maintainability. In Swift, this is naturally achieved using modules (files) and access control modifiers (public, private, internal, fileprivate). The code defines a Calculator module with public methods for basic operations and private helper functions for internal logic. This aligns with Swift’s emphasis on modularity and clear separation of concerns through access control, making the code readable and maintainable.
// Calculator.swift
public class Calculator {
// Public API - methods exposed to other parts of the application
public func add(_ a: Double, _ b: Double) -> Double {
return performOperation(a, b, operation: +)
}
public func subtract(_ a: Double, _ b: Double) -> Double {
return performOperation(a, b, operation: -)
}
public func multiply(_ a: Double, _ b: Double) -> Double {
return performOperation(a, b, operation: *)
}
public func divide(_ a: Double, _ b: Double) -> Double {
return performOperation(a, b, operation: /)
}
// Private helper function - internal implementation detail
private func performOperation(_ a: Double, _ b: Double, operation: (Double, Double) -> Double) -> Double {
// Add error handling or logging here if needed
return operation(a, b)
}
}
The Module pattern creates an isolated execution scope, encapsulating internal state and exposing a public API. This prevents global namespace pollution and allows for better organization and maintainability. In Kotlin, this is naturally achieved using object declarations, which are singletons with a defined interface. The code defines an OrderProcessor object that holds order-related data and provides methods for adding items, calculating totals, and processing the order. The internal MutableList<String> is hidden, and access is only granted through the public API. This approach aligns with Kotlin’s emphasis on immutability and concise syntax, leveraging objects for straightforward encapsulation.
// OrderProcessor.kt
object OrderProcessor {
private val items = mutableListOf<String>()
fun addItem(item: String) {
items.add(item)
}
fun getTotal(): Int {
return items.size // Simplified total calculation for demonstration
}
fun processOrder(): String {
if (items.isEmpty()) {
return "Order is empty."
}
return "Processing order with ${items.joinToString(", ")}."
}
fun getItems(): List<String> {
return items.toList() // Return a copy to prevent external modification
}
}
fun main() {
OrderProcessor.addItem("Shirt")
OrderProcessor.addItem("Pants")
println("Total items: ${OrderProcessor.getTotal()}")
println(OrderProcessor.processOrder())
println("Items in order: ${OrderProcessor.getItems()}")
}
The Module pattern organizes code into logical units, enhancing reusability, maintainability, and preventing naming conflicts. In Rust, modules are defined using the mod keyword. This example demonstrates a simple module structure with a public function and a private one. The pub keyword controls visibility, making items accessible outside the module. Rust’s module system is central to its package management (crates) and encourages a hierarchical organization of code. The use of mod and pub aligns with Rust’s explicit visibility control and emphasis on code organization.
// src/lib.rs
pub mod geometry {
// Publicly available types and functions
pub struct Rectangle {
pub width: u32,
pub height: u32,
}
impl Rectangle {
pub fn area(&self) -> u32 {
self.width * self.height
}
// Private function - only accessible within the geometry module
fn is_square(&self) -> bool {
self.width == self.height
}
pub fn new(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
}
}
#[cfg(test)]
mod tests {
use super::geometry::Rectangle;
#[test]
fn test_rectangle_area() {
let rect = Rectangle::new(5, 10);
assert_eq!(rect.area(), 50);
}
#[test]
fn test_is_square_access() {
let rect = Rectangle::new(5, 5);
// This would cause a compile error because is_square is private
// assert_eq!(rect.is_square(), true);
}
}
The Module pattern (also known as the Memento pattern) captures and externalizes an object’s internal state so that it can be restored later, providing a way to save and restore previous states without violating encapsulation. This implementation uses a State struct to hold the object’s data, and Save() and Restore() methods to manage the memento. Go’s struct composition and method receivers naturally lend themselves to this pattern. The Originator struct encapsulates the state and the logic for saving and restoring it, while the Memento struct is an immutable snapshot of the state.
package main
import "fmt"
// State holds the internal state of the Originator.
type State struct {
Value int
}
// Memento is an immutable snapshot of the Originator's state.
type Memento struct {
State State
}
// Originator creates and manages its own state.
type Originator struct {
currentState State
}
// NewOriginator creates a new Originator with an initial state.
func NewOriginator(initialValue int) *Originator {
return &Originator{State{Value: initialValue}}
}
// SetValue changes the Originator's state.
func (o *Originator) SetValue(newValue int) {
o.currentState.Value = newValue
}
// Value returns the current value of the originator.
func (o *Originator) Value() int {
return o.currentState.Value
}
// Save creates a memento containing the current state.
func (o *Originator) Save() *Memento {
return &Memento{State{Value: o.currentState.Value}}
}
// Restore sets the Originator's state to the one stored in the memento.
func (o *Originator) Restore(memento *Memento) {
o.currentState = memento.State
}
func main() {
originator := NewOriginator(10)
fmt.Println("Initial value:", originator.Value())
memento := originator.Save()
originator.SetValue(20)
fmt.Println("Value after change:", originator.Value())
originator.Restore(memento)
fmt.Println("Value after restore:", originator.Value())
}
The Module pattern encapsulates data and functionality within a single unit, exposing only a well-defined interface. This promotes code organization, reduces global namespace pollution, and enhances maintainability. In C, this is achieved through header files (.h) declaring the public interface and source files (.c) implementing the private details. The header file acts as the module’s public face, while the source file contains the implementation and static variables/functions, ensuring they are not directly accessible from outside the module. This example demonstrates a simple counter module.
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
// Public interface
typedef struct Counter Counter;
Counter* counter_create();
void counter_increment(Counter* counter);
int counter_get_value(const Counter* counter);
void counter_destroy(Counter* counter);
#endif // COUNTER_H
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value;
// Private data - not exposed in the header
};
Counter* counter_create() {
Counter* counter = (Counter*)malloc(sizeof(Counter));
if (counter != NULL) {
counter->value = 0;
}
return counter;
}
void counter_increment(Counter* counter) {
if (counter != NULL) {
counter->value++;
}
}
int counter_get_value(const Counter* counter) {
if (counter != NULL) {
return counter->value;
}
return -1; // Or some other error indicator
}
void counter_destroy(Counter* counter) {
if (counter != NULL) {
free(counter);
}
}
// main.c (Example Usage)
#include <stdio.h>
#include "counter.h"
int main() {
Counter* my_counter = counter_create();
if (my_counter == NULL) {
fprintf(stderr, "Failed to create counter\n");
return 1;
}
counter_increment(my_counter);
counter_increment(my_counter);
printf("Counter value: %d\n", counter_get_value(my_counter));
counter_destroy(my_counter);
return 0;
}
The Module Pattern aims to encapsulate functionality within a self-contained unit, controlling exposure to the outside world through a public API. This promotes code organization, avoids global namespace pollution, and enables reusability. In C++, this is best achieved using namespaces and carefully designed header files that define the public interface. Private implementation details are kept within .cpp files, inaccessible directly from outside the module. This example demonstrates a simple Math module with private helper functions and a public method for calculating the factorial.
// Math.h - Public Interface
#ifndef MATH_H
#define MATH_H
namespace Math {
/**
* @brief Calculates the factorial of a non-negative integer.
*
* @param n The input integer.
* @return The factorial of n. Returns 1 for n = 0.
* @throws std::invalid_argument if n is negative.
*/
int factorial(int n);
} // namespace Math
#endif // MATH_H
// Math.cpp - Private Implementation
#include "Math.h"
#include <stdexcept>
namespace Math {
// Private helper function for factorial calculation
static int factorialHelper(int n) {
if (n == 0) {
return 1;
}
return n * factorialHelper(n - 1);
}
int factorial(int n) {
if (n < 0) {
throw std::invalid_argument("Factorial is not defined for negative numbers.");
}
return factorialHelper(n);
}
} // namespace Math
// main.cpp - Usage Example
#include <iostream>
#include "Math.h"
int main() {
try {
std::cout << "Factorial of 5: " << Math::factorial(5) << std::endl;
std::cout << "Factorial of 0: " << Math::factorial(0) << std::endl;
// std::cout << Math::factorialHelper(5) << std::endl; // This would cause a compile error
std::cout << "Factorial of -1: ";
Math::factorial(-1);
} catch (const std::invalid_argument& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return 0;
}
The Module pattern, also known as the Minit pattern, aims to encapsulate functionality within a single type, exposing a minimal public interface. It’s particularly useful for grouping related functions and constants without creating a formal class with state. This promotes code organization and reduces namespace pollution.
The C# implementation uses a static class to hold all related functionality. All members are private except for the explicitly exposed public methods. This approach leverages C#’s static class capabilities to achieve the desired encapsulation and minimal interface. It’s idiomatic because C# readily supports static classes, making them a natural fit for this pattern, and avoids unnecessary object instantiation.
// Module.cs
public static class StringFormatter
{
private const string DefaultSeparator = "-";
public static string ToKebabCase(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}
var result = System.Text.RegularExpressions.Regex.Replace(input, "[^a-zA-Z0-9]", " ");
result = string.Join(DefaultSeparator, result.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)).ToLower();
return result;
}
public static string Truncate(string input, int maxLength)
{
if (string.IsNullOrEmpty(input) || input.Length <= maxLength)
{
return input;
}
return input.Substring(0, maxLength) + "...";
}
internal static string GetInternalConstant()
{
return DefaultSeparator;
}
}
The Module Pattern is a way to encapsulate state and expose only a necessary interface. It’s commonly used to create self-contained units of code, preventing global namespace pollution and improving maintainability. This TypeScript example uses a simple object literal to create a module. The counter variable is private to the module, and only the increment and getCount methods are exposed through the returned object. This aligns with TypeScript’s preference for clear interfaces and encapsulation, leveraging object literals for concise module creation when full class structures aren’t needed.
// counter.ts
const counterModule = (function() {
let counter = 0;
return {
increment: function() {
counter++;
},
getCount: function() {
return counter;
}
};
})();
export default counterModule;
The Module pattern encapsulates data and methods within a private scope, exposing only a public interface. This promotes data hiding, reduces global namespace pollution, and improves code organization. The JavaScript implementation uses an Immediately Invoked Function Expression (IIFE) to create a closure. Variables declared within the IIFE are private, while explicitly returned objects define the public API. This approach is idiomatic JavaScript as it leverages closures, a core language feature, to achieve encapsulation without relying on class-based inheritance (though modules can be used within classes). It’s a flexible pattern, applicable in both older and modern JavaScript environments.
// gist-module.js
const myModule = (function() {
// Private variables and functions
let privateCounter = 0;
function privateFunction() {
privateCounter++;
console.log("Private function called. Counter:", privateCounter);
}
// Public API (returned object)
return {
publicMethod: function(message) {
console.log("Public method says:", message);
privateFunction(); // Accessing private function
},
getCounter: function() {
return privateCounter;
},
initialValue: 42 // Public property
};
})();
// Usage
myModule.publicMethod("Hello from the outside!");
console.log("Counter value:", myModule.getCounter());
console.log("Initial value:", myModule.initialValue);
// Attempting to access privateCounter directly will result in undefined.
The Module pattern organizes code into reusable, self-contained units. It encapsulates related data and functionality, exposing only a necessary public interface while hiding implementation details. This promotes code maintainability, reduces naming conflicts, and enhances reusability.
The Python code demonstrates this by defining a module math_operations. It contains functions for addition and subtraction, but these are considered internal to the module. A calculate function serves as the public interface, choosing the appropriate operation based on input. This aligns with Python’s emphasis on modularity and the use of functions and classes to group related code. The use of a single module file is standard practice for simple modules in Python.
# math_operations.py
def _add(x, y):
"""Internal function for addition."""
return x + y
def _subtract(x, y):
"""Internal function for subtraction."""
return x - y
def calculate(operation, x, y):
"""Public interface for performing calculations."""
if operation == "add":
return _add(x, y)
elif operation == "subtract":
return _subtract(x, y)
else:
raise ValueError("Invalid operation")
if __name__ == '__main__':
# Example usage
result = calculate("add", 5, 3)
print(f"5 + 3 = {result}")
result = calculate("subtract", 10, 4)
print(f"10 - 4 = {result}")
try:
result = calculate("multiply", 2, 6)
except ValueError as e:
print(e)
The Module Pattern, in Java, leverages the principles of encapsulation and information hiding to create self-contained units of code with well-defined interfaces. Java 9 introduced the official java.base module system, but the pattern can be emulated even in older versions using careful class design. This example demonstrates a simple module with public and private components. The api package exposes the public interface, while the internal package contains implementation details hidden from external access. This promotes maintainability, reduces coupling, and allows for independent evolution of the module’s internals. The use of packages mirrors the modular structure, and access modifiers (public, private) enforce the module’s boundaries.
// api/MyModule.java
package com.example.mymodule.api;
public class MyModule {
private final com.example.mymodule.internal.Implementation impl;
public MyModule() {
this.impl = new com.example.mymodule.internal.Implementation();
}
public String doSomething(String input) {
return impl.internalLogic(input);
}
}
// internal/Implementation.java
package com.example.mymodule.internal;
class Implementation {
String internalLogic(String input) {
return "Module processed: " + input;
}
}
// Example Usage (in a separate file/module)
/*
package com.example.usermodule;
import com.example.mymodule.api.MyModule;
public class User {
public static void main(String[] args) {
MyModule module = new MyModule();
System.out.println(module.doSomething("Hello"));
// Cannot access Implementation directly
}
}
*/