Patrón de módulo - Module pattern
En ingeniería de software , el patrón de módulo es un patrón de diseño utilizado para implementar el concepto de módulos de software , definido por programación modular , en un lenguaje de programación con soporte directo incompleto para el concepto.
Este patrón se puede implementar de varias formas dependiendo del lenguaje de programación del host, como el patrón de diseño singleton , miembros estáticos orientados a objetos en una clase y funciones globales de procedimiento. En Python, el patrón está integrado en el lenguaje y cada archivo .py es automáticamente un módulo.
Definición y estructura
El patrón de diseño del software del módulo proporciona las características y la estructura sintáctica definidas por el paradigma de programación modular a los lenguajes de programación que tienen un soporte incompleto para el concepto.
Concepto
En el desarrollo de software, el código fuente se puede organizar en componentes que cumplen una función en particular o contienen todo lo necesario para realizar una tarea en particular. La programación modular es uno de esos enfoques.
El concepto de "módulo" no es totalmente compatible con muchos lenguajes de programación comunes.
Características
Para considerar que un Singleton o cualquier grupo de código relacionado implementa este patrón, se deben proporcionar las siguientes características:
- Una parte del código debe tener acceso público o global y estar diseñada para usarse como código público o global. El código público principal puede ejecutar código privado o protegido adicional.
- Un módulo debe tener una función inicializadora que sea equivalente o complementaria a un método constructor de objetos . Esta función no es compatible con los espacios de nombres habituales .
- Un módulo debe tener una función de finalizador que sea equivalente o complementaria a un método destructor de objetos. Esta función no es compatible con los espacios de nombres habituales.
- Los miembros de apoyo pueden requerir un código de inicialización / finalización que se ejecuta mediante la función de inicialización / finalización del módulo.
- La mayoría de los miembros son funciones que realizan operaciones en elementos externos a la clase, proporcionados como argumentos mediante funciones de llamada. Estas funciones son "utilidades", "herramientas" o "bibliotecas".
Implementaciones
La semántica y la sintaxis de cada lenguaje de programación pueden afectar la implementación de este patrón.
Lenguajes de programación orientados a objetos
Java
Aunque Java admite la noción de un espacio de nombres , una versión reducida de un módulo, algunos escenarios se benefician de emplear el patrón de diseño en lugar de usar espacios de nombres.
El siguiente ejemplo usa el patrón singleton.
Definición
package consoles;
import java.io.InputStream;
import java.io.PrintStream;
public final class MainModule {
private static MainModule singleton = null;
public InputStream input = null;
public PrintStream output = null;
public PrintStream error = null;
private MainModule() {
// does nothing on purpose !!!
}
// ...
public static MainModule getSingleton() {
if (MainModule.singleton == null) {
MainModule.singleton = new MainModule();
}
return MainModule.singleton;
}
// ...
public void prepare() {
//System.out.println("consoles::prepare();");
this.input = new InputStream();
this.output = new PrintStream();
this.error = new PrintStream();
}
public void unprepare() {
this.output = null;
this.input = null;
this.error = null;
//System.out.println("consoles::unprepare();");
}
// ...
public void printNewLine() {
System.out.println();
}
public void printString(String value) {
System.out.print(value);
}
public void printInteger(int value) {
System.out.print(value);
}
public void printBoolean(boolean value) {
System.out.print(value);
}
public void scanNewLine() {
// to-do: ...
}
public void scanString(String value) {
// to-do: ...
}
public void scanInteger(int value) {
// to-do: ...
}
public void scanBoolean(boolean value) {
// to-do: ...
}
// ...
}
Implementación
import consoles.*;
class ConsoleDemo {
public static MainModule console = null;
public static void prepare() {
console = MainModule.getSingleton();
console.prepare();
}
public static void unprepare() {
console.unprepare();
}
public static void execute(String[] args) {
console.printString("Hello World");
console.printNewLine();
console.scanNewLine();
}
public static void main(String[] args) {
prepare();
execute(args);
unprepare();
}
}
C # (C Sharp .NET)
C # , como Java, admite espacios de nombres, aunque el patrón sigue siendo útil en casos específicos.
El siguiente ejemplo usa el patrón singleton.
Definición
using System;
using System.IO;
using System.Text;
namespace Consoles {
public sealed class MainModule {
private static MainModule Singleton = null;
public InputStream input = null;
public OutputStream output = null;
public ErrorStream error = null;
// ...
public MainModule () {
// does nothing on purpose !!!
}
// ...
public static MainModule GetSingleton() {
if (MainModule.Singleton == null)
{
MainModule.Singleton = new MainModule();
}
return MainModule.Singleton;
}
// ...
public void Prepare() {
//System.WriteLine("console::prepare();");
this.input = new InputStream();
this.output = new OutputStream();
this.error = new ErrorStream();
}
public void Unprepare() {
this.output = null;
this.input = null;
this.error = null;
//System.WriteLine("console::unprepare();");
}
// ...
public void PrintNewLine() {
System.Console.WriteLine("");
}
public void PrintString(String Value) {
System.Console.Write(Value);
}
public void PrintInteger(Integer Value) {
System.Console.Write(Value);
}
public void PrintBoolean(Boolean Value) {
System.Console.Write(Value);
}
public void ScanNewLine() {
// to-do: ...
}
public void ScanString(String Value) {
// to-do: ...
}
public void ScanInteger(Integer Value) {
// to-do: ...
}
public void ScanBoolean(Boolean Value) {
// to-do: ...
}
// ...
}
}
Implementación
class ConsoleDemo {
public static Consoles.MainModule Console = null;
public static void Prepare()
{
Console = Consoles.MainModule.GetSingleton();
Console.Prepare();
}
public static void Unprepare()
{
Console.Unprepare();
}
public static void Execute()
{
Console.PrintString("Hello World");
Console.PrintNewLine();
Console.ScanNewLine();
}
public static void Main()
{
Prepare();
Execute(args);
Unprepare();
}
}
Lenguajes de programación basados en prototipos
JavaScript
JavaScript se usa comúnmente para automatizar páginas web.
Definición
function ConsoleClass() {
var Input = null;
var Output = null;
var Error = null;
// ...
this.prepare = function() {
this.Input = new InputStream();
this.Output = new OutputStream();
this.Error = new ErrorStream();
}
this.unprepare = function() {
this.Input = null;
this.Output = null;
this.Error = null;
}
// ...
var printNewLine = function() {
// code that prints a new line
}
var printString = function(params) {
// code that prints parameters
}
var printInteger = function(params) {
// code that prints parameters
}
var printBoolean = function(params) {
// code that prints parameters
}
var ScanNewLine = function() {
// code that looks for a newline
}
var ScanString = function(params) {
// code that inputs data into parameters
}
var ScanInteger = function(params) {
// code that inputs data into parameters
}
var ScanBoolean = function(params) {
// code that inputs data into parameters
}
// ...
}
Implementación
function ConsoleDemo() {
var Console = null;
var prepare = function() {
Console = new ConsoleClass();
Console.prepare();
}
var unprepare = function() {
Console.unprepare();
}
var run = function() {
Console.printString("Hello World");
Console.printNewLine();
}
var main = function() {
this.prepare();
this.run();
this.unprepare();
}
}
Lenguajes de programación procedimental
Este patrón puede verse como una extensión de procedimiento a los lenguajes orientados a objetos.
Aunque los paradigmas de programación procedimental y modular a menudo se usan juntos, hay casos en los que un lenguaje de programación procedimental puede no admitir completamente los módulos, por lo que se requiere una implementación de patrón de diseño.
PHP (de procedimiento)
Este ejemplo se aplica a PHP procedimental antes de los espacios de nombres (introducido en la versión 5.3.0). Se recomienda que a cada miembro de un módulo se le asigne un prefijo relacionado con el nombre del archivo o el nombre del módulo para evitar colisiones de identificadores.
Definición
<?php
// filename: console.php
function console_prepare()
{
// code that prepares a "console"
}
function console_unprepare()
{
// code that unprepares a "console"
}
// ...
function console_printNewLine()
{
// code that outputs a new line
}
function console_printString(/* String */ Value)
{
// code that prints parameters
}
function console_printInteger(/* Integer */ Value)
{
// code that prints parameters
}
function console_printBoolean(/* Boolean */ Value)
{
// code that prints parameters
}
function console_scanNewLine()
{
// code that looks for a new line
}
function console_scanString(/* String */ Value)
{
// code that stores data into parameters
}
function console_scanInteger(/* Integer */ Value)
{
// code that stores data into parameters
}
function console_scanBoolean(/* Boolean */ Value)
{
// code that stores data into parameters
}
Implementación
// filename: consoledemo.php
require_once("console.php");
function consoledemo_prepare()
{
console_prepare();
}
function consoledemo_unprepare()
{
console_unprepare();
}
function consoledemo_execute()
{
console_printString("Hello World");
console_printNewLine();
console_scanNewLine();
}
function consoledemo_main()
{
consoledemo_prepare();
consoledemo_execute();
consoledemo_unprepare();
}
C
Tenga en cuenta que este ejemplo se aplica al procedimiento C sin espacios de nombres. Se recomienda que a cada miembro de un módulo se le asigne un prefijo relacionado con el nombre del archivo o el nombre del módulo para evitar colisiones de identificadores.
Módulo de encabezado de definición
// filename: "consoles.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void consoles_prepare();
void consoles_unprepare();
// ...
void consoles_printNewLine();
void consoles_printString(char* Value);
void consoles_printInteger(int Value);
void consoles_printBoolean(bool Value);
void consoles_scanNewLine();
void consoles_scanString(char* Value);
void consoles_scanInteger(int* Value);
void consoles_scanBoolean(bool* Value);
Módulo de cuerpo de definición
// filename: "consoles.c"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <consoles.h>
void consoles_prepare() {
// code that prepares console
}
void consoles_unprepare() {
// code that unprepares console
}
// ...
void consoles_printNewLine() {
printf("\n");
}
void consoles_printString(char* Value) {
printf("%s", Value);
}
void consoles_printInteger(int Value) {
printf("%d", &Value);
}
void consoles_printBoolean(bool Value) {
if (Value)
{
printf("true");
}
else
{
printf("false");
}
}
void consoles_scanNewLine() {
getch();
}
void consoles_scanString(char* Value) {
scanf("%s", Value);
}
void consoles_scanInteger(int* Value) {
scanf("%d", Value);
}
void consoles_scanBoolean(bool* Value) {
char temp[512];
scanf("%s", temp);
*Value = (strcmp(Temp, "true") == 0);
}
Implementación
// filename: "consoledemo.c"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <consoles.h>
void consoledemo_prepare()
{
consoles_prepare();
}
void consoledemo_unprepare()
{
consoles_unprepare();
}
int consoledemo_execute()
{
consoles_printString("Hello World");
consoles_printNewLine();
consoles_scanNewLine();
return 0;
}
int main()
{
ErrorCode Result = 0;
consoledemo_prepare();
ErrorCode = consoledemo_execute();
consoledemo_unprepare();
return ErrorCode;
}
Pascal procesal
Tenga en cuenta que este ejemplo se aplica a Pascal procedimental no modular. Muchos dialectos de Pascal tienen soporte de espacio de nombres, llamado "unidad (es)". Algunos dialectos también admiten la inicialización y finalización.
Si los espacios de nombres no son compatibles, se recomienda dar a todos los nombres de miembros un prefijo relacionado con el nombre del archivo o del módulo para evitar colisiones de identificadores.
Definición
unit consoles;
(* filename: "consoles.pas" *)
uses crt;
procedure prepare();
begin
(* code that prepares console *)
end;
procedure unprepare();
begin
(* code that unprepares console *)
end;
// ...
procedure printNewLine();
begin
WriteLn();
end;
procedure printString(Value: string);
begin
Write(Value);
end;
procedure printInteger(Value: integer);
begin
Write(Value);
end;
procedure printBoolean(Value: boolean);
begin
if (Value) then
begin
Write('true');
end else
begin
Write('false');
end;
end;
procedure scanNewLine();
begin
SeekEoLn();
end;
procedure scanString(Value: string);
begin
ReadLn(Value);
end;
procedure scanInteger(Value: Integer);
begin
ReadLn(Value);
end;
procedure scanBoolean(Value: Boolean);
var temp: string;
begin
ReadLn(temp);
if (Temp = 'true') then
begin
Value := true;
end else
begin
Value := false;
end;
end;
Implementación
program consoledemo;
// filename: "consoles.pas"
uses consoles;
procedure prepare();
begin
consoles.prepare();
end;
procedure unprepare();
begin
consoles.unprepare();
end;
function execute(): Integer;
begin
consoles.printString('Hello World');
consoles.printNewLine();
consoles.scanNewLine();
execute := 0;
end;
begin
prepare();
execute();
unprepare();
end.
Comparaciones con otros conceptos
Espacios de nombres
Tanto los espacios de nombres como los módulos permiten agrupar varias entidades relacionadas mediante un solo identificador y, en algunas situaciones, se utilizan indistintamente. Se puede acceder a esas entidades de forma global. El propósito principal de ambos conceptos es el mismo.
En algunos escenarios, un espacio de nombres requiere que los elementos globales que lo componen se inicialicen y finalicen mediante una llamada a una función o método.
En muchos lenguajes de programación, los espacios de nombres no están destinados directamente a admitir un proceso de inicialización ni un proceso de finalización y, por lo tanto, no son equivalentes a módulos. Esa limitación se puede solucionar de dos maneras. En los espacios de nombres que admiten funciones globales, una función para la inicialización y una función para la finalización se codifican directamente y se llaman directamente en el código del programa principal.
Clases y espacios de nombres
Las clases se utilizan a veces como espacios de nombres o con ellos . En los lenguajes de programación que no admiten espacios de nombres (por ejemplo, JavaScript) pero sí admiten clases y objetos, las clases se utilizan a menudo para sustituir espacios de nombres. Por lo general, estas clases no se instancian y consisten exclusivamente en miembros estáticos.
Espacios de nombres y clases de singleton
En los lenguajes de programación orientados a objetos donde los espacios de nombres no son completamente compatibles, el patrón singleton puede usarse en lugar de miembros estáticos dentro de una clase no instanciable.
Relación con otros patrones de diseño
El patrón del módulo se puede implementar mediante una especialización del patrón singleton. Sin embargo, se pueden aplicar y combinar otros patrones de diseño en la misma clase.
Este patrón se puede utilizar como decorador , peso mosca o adaptador .
Módulo como patrón de diseño
El patrón del módulo se puede considerar un patrón de creación y un patrón estructural . Gestiona la creación y organización de otros elementos y los agrupa como lo hace el patrón estructural.
Un objeto que aplica este patrón puede proporcionar el equivalente de un espacio de nombres , proporcionando el proceso de inicialización y finalización de una clase estática o una clase con miembros estáticos con una sintaxis y una semántica más limpias y concisas .
Admite casos específicos en los que una clase u objeto pueden considerarse datos de procedimiento estructurados. Y viceversa, migrar datos estructurados, procedimentales y considerados como orientados a objetos.
Ver también
- Patrón de diseño
- Patrones de diseño (E. Gamma et al.)
- Patrón singleton
- Patrón de adaptador