Model de modul - Module pattern

În ingineria software , modelul modulului este un model de proiectare utilizat pentru a implementa conceptul de module software , definit prin programare modulară , într-un limbaj de programare cu suport direct incomplet pentru concept.

Acest model poate fi implementat în mai multe moduri, în funcție de limbajul de programare gazdă, cum ar fi modelul de proiectare singleton , membrii statici orientați obiect într-o clasă și funcțiile globale procedurale. În Python, modelul este încorporat în limbă și fiecare fișier .py este automat un modul.

Definiție și structură

Modelul de proiectare a software-ului modulului oferă caracteristicile și structura sintactică definite de paradigma de programare modulară limbajelor de programare care au suport incomplet pentru concept.

Modelul modulului obiect exprimat în UML.
Modelul modulului obiect exprimat în UML .

Concept

În dezvoltarea de software, codul sursă poate fi organizat în componente care îndeplinesc o anumită funcție sau conțin tot ceea ce este necesar pentru a îndeplini o anumită sarcină. Programarea modulară este una dintre aceste abordări.

Conceptul de „modul” nu este pe deplin acceptat în multe limbaje de programare comune.

Caracteristici

Pentru a considera că un Singleton sau orice grup de coduri conexe implementează acest model, trebuie furnizate următoarele caracteristici:

  • O parte din cod trebuie să aibă acces global sau public și să fie concepută pentru a fi utilizată ca cod global / public. Codul privat sau protejat suplimentar poate fi executat de codul public principal.
  • Un modul trebuie să aibă o funcție de inițializare care să fie echivalentă sau complementară cu o metodă de constructor de obiecte . Această caracteristică nu este acceptată de spații de nume obișnuite .
  • Un modul trebuie să aibă o funcție de finalizare care este echivalentă sau complementară cu o metodă de distrugere a obiectelor. Această caracteristică nu este acceptată de spații de nume obișnuite.
  • Membrii de sprijin pot necesita cod de inițializare / finalizare care este executat de funcția de inițializare / finalizare a modulului.
  • Majoritatea membrilor sunt funcții care efectuează operațiuni pe elemente externe clasei, furnizate ca argumente prin apelarea funcțiilor. Astfel de funcții sunt „utilitare”, „instrumente” sau „biblioteci”.

Implementări

Semantica și sintaxa fiecărui limbaj de programare pot afecta implementarea acestui model.

Limbaje de programare orientate obiect

Java

Deși Java acceptă noțiunea de spațiu de nume , o versiune redusă a unui modul, unele scenarii beneficiază de utilizarea modelului de proiectare în loc de utilizarea spațiilor de nume.

Următorul exemplu folosește modelul singleton.

Definiție
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: ...
  }
  
  // ...
  
}
Implementare
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 # , la fel ca Java, acceptă spații de nume, deși modelul rămâne util în cazuri specifice.

Următorul exemplu folosește modelul singleton.

Definiție
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: ...
        }
        
        // ...
    
    }
}
Implementare
    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();
        }
    }

Limbaje de programare bazate pe prototip

JavaScript

JavaScript este utilizat în mod obișnuit pentru automatizarea paginilor web.

Definiție
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
  }
  
  // ...
  
}
Implementare
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();
  }  
}

Limbaje de programare procedurale

Acest model poate fi văzut ca o extensie procedurală la limbaje orientate obiect.

Deși paradigmele de programare procedurală și modulară sunt adesea utilizate împreună, există cazuri în care un limbaj de programare procedurală poate să nu accepte complet modulele, necesitând astfel o implementare a modelului de proiectare.

PHP (procedural)

Acest exemplu se aplică PHP procedural înainte de spații de nume (introdus în versiunea 5.3.0). Se recomandă ca fiecărui membru al unui modul să i se dea un prefix legat de numele fișierului sau numele modulului pentru a evita coliziunile identificatorului.

Definiție
<?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
}
Implementare
// 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

Rețineți că acest exemplu se aplică procedurii C fără spații de nume. Se recomandă ca fiecărui membru al unui modul să i se dea un prefix legat de numele fișierului sau numele modulului pentru a evita coliziunile identificatorului.

Modul antet de definiție
  // 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);
Definiție corp modul
  // 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);
  }
Implementare
  // 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 procedural

Rețineți că acest exemplu se aplică procedurilor Pascal nemodulare. Multe dialecte Pascal au suport pentru spațiul de nume, numit „unitate (e)”. Unele dialecte acceptă, de asemenea, inițializarea și finalizarea.

Dacă spațiile de nume nu sunt acceptate, este recomandat să le dați tuturor numele membrilor un prefix legat de numele fișierului sau numele modulului pentru a preveni coliziunile identificatorilor.

Definiție
  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;
Implementare
  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.

Comparații cu alte concepte

Spații de nume

Atât spațiile de nume, cât și modulele permit gruparea mai multor entități înrudite printr-un singur identificator și, în unele situații, utilizate în mod interschimbabil. Aceste entități pot fi accesate la nivel global. Scopul principal al ambelor concepte este același.

În unele scenarii, un spațiu de nume necesită ca elementele globale care îl compun să fie inițializate și finalizate printr-un apel de funcție sau metodă.

În multe limbaje de programare, spațiile de nume nu sunt destinate direct să susțină un proces de inițializare și nici un proces de finalizare și, prin urmare, nu sunt echivalente cu modulele. Această limitare poate fi rezolvată în două moduri. În spațiile de nume care acceptă funcții globale, o funcție pentru inițializare și o funcție pentru finalizare sunt codate direct și apelate direct în codul principal al programului.

Clase și spații de nume

Clasele sunt folosite uneori folosite ca sau cu spații de nume . În limbajele de programare care nu acceptă spații de nume (de exemplu, JavaScript), dar acceptă clase și obiecte, clasele sunt adesea folosite pentru a înlocui spațiile de nume. Aceste clase nu sunt de obicei instanțiate și constau exclusiv din membri statici.

Cursuri și spații de nume Singleton

În limbajele de programare orientate pe obiecte în care spațiile de nume sunt incomplet acceptate, modelul singleton poate fi utilizat în locul membrilor statici dintr-o clasă neinstanțabilă.

Relația cu alte modele de proiectare

Modelul modulului poate fi implementat utilizând o specializare a modelului single. Cu toate acestea, alte modele de proiectare pot fi aplicate și combinate, în aceeași clasă.

Acest model poate fi folosit ca decorator , greutate pentru muște sau ca adaptor .

Modulul ca model de proiectare

Modelul modulului poate fi considerat un model creațional și un model structural . Gestionează crearea și organizarea altor elemente și le grupează așa cum o face modelul structural.

Un obiect care aplică acest model poate oferi echivalentul unui spațiu de nume , oferind procesul de inițializare și finalizare a unei clase statice sau a unei clase cu membri statici cu sintaxă și semantică mai curate, mai concise .

Acceptă cazuri specifice în care o clasă sau un obiect pot fi considerate date procedurale structurate. Și, invers, migrează date structurate, procedurale și considerate orientate spre obiecte.

Vezi si