Modèle de module - Module pattern
En génie logiciel , le modèle de module est un modèle de conception utilisé pour implémenter le concept de modules logiciels , défini par la programmation modulaire , dans un langage de programmation avec une prise en charge directe incomplète du concept.
Ce modèle peut être implémenté de plusieurs manières en fonction du langage de programmation hôte, comme le modèle de conception singleton , les membres statiques orientés objet dans une classe et les fonctions globales procédurales. En Python, le modèle est intégré au langage et chaque fichier .py est automatiquement un module.
Définition et structure
Le modèle de conception de logiciel de module fournit les fonctionnalités et la structure syntaxique définies par le paradigme de programmation modulaire aux langages de programmation qui ont une prise en charge incomplète du concept.
Concept
Dans le développement logiciel, le code source peut être organisé en composants qui accomplissent une fonction particulière ou contiennent tout le nécessaire pour accomplir une tâche particulière. La programmation modulaire est l'une de ces approches.
Le concept de "module" n'est pas entièrement pris en charge dans de nombreux langages de programmation courants.
Caractéristiques
Afin de considérer qu'un Singleton ou tout groupe de code associé implémente ce modèle, les fonctionnalités suivantes doivent être fournies :
- Une partie du code doit avoir un accès global ou public et être conçue pour être utilisée en tant que code global/public. Un code privé ou protégé supplémentaire peut être exécuté par le code public principal.
- Un module doit avoir une fonction d'initialisation équivalente ou complémentaire à une méthode de constructeur d'objet . Cette fonctionnalité n'est pas prise en charge par les espaces de noms normaux .
- Un module doit avoir une fonction de finaliseur équivalente ou complémentaire à une méthode de destructeur d'objet. Cette fonctionnalité n'est pas prise en charge par les espaces de noms normaux.
- Les membres de support peuvent nécessiter un code d'initialisation/finalisation qui est exécuté par la fonction d'initialisation/finalisation du module.
- La plupart des membres sont des fonctions qui effectuent des opérations sur des éléments externes à la classe, fournis comme arguments en appelant des fonctions. Ces fonctions sont des « utilitaires », des « outils » ou des « bibliothèques ».
Implémentations
La sémantique et la syntaxe de chaque langage de programmation peuvent affecter la mise en œuvre de ce modèle.
Langages de programmation orientés objet
Java
Bien que Java prenne en charge la notion d' espace de noms , une version réduite d'un module, certains scénarios bénéficient de l'utilisation du modèle de conception au lieu d'utiliser des espaces de noms.
L'exemple suivant utilise le modèle singleton.
Définition
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: ...
}
// ...
}
Mise en œuvre
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# , comme Java, prend en charge les espaces de noms bien que le modèle reste utile dans des cas spécifiques.
L'exemple suivant utilise le modèle singleton.
Définition
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: ...
}
// ...
}
}
Mise en œuvre
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();
}
}
Langages de programmation basés sur des prototypes
JavaScript
JavaScript est couramment utilisé pour automatiser les pages Web.
Définition
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
}
// ...
}
Mise en œuvre
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();
}
}
Langages de programmation procédurale
Ce modèle peut être vu comme une extension procédurale aux langages orientés objet.
Bien que les paradigmes de programmation procédurale et modulaire soient souvent utilisés ensemble, il existe des cas où un langage de programmation procédurale peut ne pas prendre entièrement en charge les modules, nécessitant donc une implémentation de modèle de conception.
PHP (procédural)
Cet exemple s'applique au PHP procédural avant les espaces de noms (introduit dans la version 5.3.0). Il est recommandé de donner à chaque membre d'un module un préfixe lié au nom de fichier ou au nom du module afin d'éviter les collisions d'identifiants.
Définition
<?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
}
Mise en œuvre
// 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
Notez que cet exemple s'applique au C procédural sans espaces de noms. Il est recommandé de donner à chaque membre d'un module un préfixe lié au nom de fichier ou au nom du module afin d'éviter les collisions d'identifiants.
Module d'en-tête de définition
// 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);
Module de corps de définition
// 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);
}
Mise en œuvre
// 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 procédural
Notez que cet exemple s'applique au Pascal non modulaire procédural. De nombreux dialectes Pascal ont un support d'espace de noms, appelé "unité(s)". Certains dialectes prennent également en charge l'initialisation et la finalisation.
Si les espaces de noms ne sont pas pris en charge, il est recommandé de donner à tous les noms de membres un préfixe lié au nom de fichier ou au nom de module afin d'éviter les collisions d'identifiants.
Définition
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;
Mise en œuvre
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.
Comparaisons avec d'autres concepts
Espaces de noms
Les espaces de noms et les modules permettent de regrouper plusieurs entités liées par un seul identifiant, et dans certaines situations, utilisé de manière interchangeable. Ces entités sont accessibles dans le monde entier. Le but principal des deux concepts est le même.
Dans certains scénarios, un espace de noms nécessite que les éléments globaux qui le composent soient initialisés et finalisés par un appel de fonction ou de méthode.
Dans de nombreux langages de programmation, les espaces de noms ne sont pas directement destinés à prendre en charge un processus d'initialisation ni un processus de finalisation, et ne sont donc pas équivalents à des modules. Cette limitation peut être contournée de deux manières. Dans les espaces de noms qui prennent en charge les fonctions globales, une fonction d'initialisation et une fonction de finalisation sont codées directement et appelées directement dans le code principal du programme.
Classes et espaces de noms
Les classes sont parfois utilisées comme ou avec des espaces de noms . Dans les langages de programmation qui ne prennent pas en charge les espaces de noms (par exemple, JavaScript) mais prennent en charge les classes et les objets, les classes sont souvent utilisées pour remplacer les espaces de noms. Ces classes ne sont généralement pas instanciées et se composent exclusivement de membres statiques.
Classes singleton et espaces de noms
Dans les langages de programmation orientés objet où les espaces de noms ne sont pas complètement pris en charge, le modèle singleton peut être utilisé à la place des membres statiques au sein d'une classe non instanciable.
Relation avec d'autres modèles de conception
Le modèle de module peut être implémenté en utilisant une spécialisation du modèle singleton. Cependant, d'autres modèles de conception peuvent être appliqués et combinés, dans la même classe.
Ce modèle peut être utilisé comme décorateur , poids mouche ou adaptateur .
Module comme modèle de conception
Le modèle de module peut être considéré comme un modèle de création et un modèle structurel . Il gère la création et l'organisation d'autres éléments et les regroupe comme le fait le modèle structurel.
Un objet qui applique ce modèle peut fournir l'équivalent d'un espace de noms , fournissant le processus d'initialisation et de finalisation d'une classe statique ou d'une classe avec des membres statiques avec une syntaxe et une sémantique plus propres et plus concises .
Il prend en charge des cas spécifiques où une classe ou un objet peut être considéré comme des données procédurales structurées. Et, inversement, migrer des données structurées, procédurales, et considérées comme orientées objet.
Voir également
- Design pattern
- Modèles de conception (E. Gamma et al.)
- Modèle singleton
- Modèle d'adaptateur