Modul programtervezési minta
A szoftverfejlesztésben a modul minta egy olyan programtervezési minta, amit a moduláris programozásban definiált szoftver modulok létrehozására használnak egy olyan programozási nyelven, ami nem rendelkezik teljes (beépített) támogatással a modul koncepció megvalósítására.
A minta több különböző módon is implementálható, a konkrét programozási nyelvtől függően, mint például az egyke minta, az objektumorientált nyelvek osztályaiban a statikus tagok vagy a procedurális nyelvek globális függvényei. A Python nyelvben a modul minta egy beépített tulajdonság, minden .py kiterjesztésű fájl automatikusan egy-egy modul is.
Definíció és struktúra
A modul programtervezési minta a moduláris programozás paradigmája szerint definiált modul fogalmának megfelelő tulajdonságokat és szintaktikai struktúrát valósítja meg olyan programozási nyelveknél, amik nem rendelkeznek teljes (beépített) támogatással a modul koncepció megvalósítására.
Koncepció
A szoftverfejlesztésben, a forráskód komponensekbe szervezhető, amik egy adott funkcionalitást valósítanak meg, vagy tartalmaznak mindent ami egy adott (bővebb) feladat elvégzéséhez szükséges. A moduláris programozás ezen megközelítések egyike, ahol a modul egy ilyen forráskód komponensként fogható fel.
Sok elterjedt programozási nyelven, a „modul“ koncepciója nem teljes körűen támogatott beépített konstrukcióként.
Tulajdonságok
Ahhoz, hogy azt mondhassuk, hogy egy egyke osztály vagy bármilyen összetartozó kód-csoport implementálja ezt a mintát, a következő tulajdonságokkal kell rendelkeznie:
- A kód egy részének globális vagy publikus elérésűnek kell lennie, és ennek megfelelően külső (globális/publikus) használatra tervezettnek. A további saját (private) vagy védett (protected) kódot a „fő“ (nyilvános) kód hívja (hajtja végre).
- A modulnak kell hogy legyen egy inicializáló metódusa, amely megfeleltethető (hasonlít) egy osztály konstruktor metódusához. Ez a képesség általánosságban nincs meg a névtereknél (namespace).
- A modulnak kell hogy legyen egy lezáró metódusa (finalizer), amely megfeleltethető (hasonlít) egy osztály destruktor metódusához. Ez a képesség sincs meg általában a névtereknél.
- A modul egyes elemei is megkövetelhetnek további inicializációs/lezáró kódokat, amiket a modul inicializáló/lezáró metódusai hajtanak végre.
- A legtöbb modul-elem valamilyen függvény, amelyek modulon kívüli elemeken hajtanak végre műveleteket, amely külső elemek függvény-argumentumként kerülnek átadásra. Az ilyen függvények általában „segédkódok“ (utility), „kódeszközök“ (tool) vagy „könyvtárak“ (library).
Implementációk
Az egyes programozási nyelvek szintaxisa és a szemantikája befolyásolja a minta implementációját.
Objektumorientált programozási nyelvek
Java
Habár a Java támogatja a névterek (namespace) fogalmát (ami a modul egy egyszerűsített változataként is felfogható), bizonyos esetekben előnyét élvezhetjük annak, ha a modul mintát használjuk, az egyszerű névterek helyett.
A következő példa az egyke mintát használja a modul minta megvalósítására.
Modul definíció
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; public MainModule() { // Szándékosan nem csinál semmit !!! } // ... 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: ... } // ... }
Használat
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)
A C#, csakúgy mint a Java, támogatja a névterek használatát, de adott esetben a modul minta alkalmazása továbbra is hasznos lehet.
A következő példa az egyke mintát használja a modul minta megvalósítására.
Modul definíció
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 () { // Szándékosan nem csinál semmit !!! } // ... public 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: ... } // ... } }
Használat
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(); } }
Prototípus alapú programozási nyelvek
JavaScript
A JavaScript széleskörűen használt a WEB alapú technológiákban. Az objektumokat nem konstruktorok segítségével, hanem a prototípus klónozásával állítja elő.
Modul definíció
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 } // ... }
Használat
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(); } }
Procedurális programozási nyelvek
A modul minta, az objektumorientált nyelvek procedurális kiegészítéseként is tekinthető.
Habár a procedurális és moduláris programozási paradigmák gyakran használatosak együtt, vannak esetek, ahol egy procedurális programnyelv nem teljes mértékben támogatja a modulokat, ami miatt a modul minta implementálása szükséges.
PHP (procedurálisan)
Az alábbiakban egy a procedurális, névtér használat lehetősége előtti (5.3.0 verziót megelőző) PHP nyelvre alkalmazott példa. Ajánlott, hogy egy modul minden eleme (függvénye), el legyen látva egy a modul-fájl vagy a modul nevéhez kapcsolódó előtaggal, az esetleges azonosító ütközések elkerülése érdekében.
Modul definíció
<?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 ouputs 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 } ?>
Használat
<?php // 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
Az alábbi példa a procedurális, névterek nélküli C nyelvre vonatkozik. Ajánlott, hogy egy modul minden eleme (függvénye), el legyen látva egy a modul-fájl vagy a modul nevéhez kapcsolódó előtaggal, az esetleges azonosító ütközések elkerülése érdekében.
Modul definíció header
// 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);
Modul definíció törzs
// 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); }
Használat
// 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; }
Procedurális Pascal
Az alábbi példa a procedurális, nem moduláris Pascal nyelvre vonatkozik. Több Pascal dialektus támogatja a „unit“-oknak nevezett névterek használatát. Néhány dialektus a unitok inicializációs és lezáró (finalizer) kódjainak megadását is támogatja.
Ha a névterek használata nem támogatott, ajánlott, hogy egy modul minden eleme (függvénye), el legyen látva egy a modul-fájl vagy a modul nevéhez kapcsolódó előtaggal, az esetleges azonosító ütközések elkerülése érdekében.
Modul definíció
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;
Használat
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.
Összehasonlítás egyéb koncepciókkal
Néveterek (namespace)
Mind a névtér, mind a modul lehetővé teszi egymással összefüggő kód-entitások (pl. függvények) csoportosítását egyetlen azonosító „alá“ (modulnév / névtér), és bizonyos szituációkban felcserélhető módon használhatóak. A csoportosított entitások globálisan elérhetőek. Mindkét koncepció fő célja azonos.
Néhány esetben egy névtér megkövetelheti a részét képező globális elemek, egy metódus hívással történő inicializálását vagy lezárását.
Sok programozási nyelvben, a névterek közvetlenül nem támogatnak inicializációs vagy lezáró eljárásokat, és emiatt ezek nem tekinthetőek egyenlőnek a modul fogalmával. Ez a korlátozás oly módon oldható fel, hogy a globális függvényeket támogató névterekben, közvetlenül lekódolásra kerül egy inicializáló és egy lezáró (finalizer) függvény, amelyek direkt módon meghívásra kerülnek a főprogram kódjában.
Osztályok (classes) és a névterek
Az osztályok néha a névterekkel együtt, vagy azokat helyettesítve használatosak. Azokban a programozási nyelvekben (mint például a JavaScript) amik nem támogatják a névtereket, de támogatják az osztályokat és objektumokat, az osztálydefiníciók gyakran használatosak a névterek helyettesítésére. Az ilyen osztályokból rendszerint nem készülnek példányok és kizárólag statikus (osztályszintű) tag-metódusokból állnak, és az osztály neve használható névtérként (összefogva az osztály tag-metódusait).
Egyke (singleton) osztályok és a néveterek
Azokban az objektumorientált nyelvekben, ahol a névterek nem támogatottak, az egyke minta is használható a névterek helyettesítésére, a „nem példányosított osztály, statikus tag-metódusokkal“ megoldás helyett (lásd fentebb).
Kapcsolat más tervezési mintákkal
A modul minta implementálható az egyke minta specializált változataként. Más tervezési minták is alkalmazhatóak és kombinálhatóak, ugyanabban az osztályban. A modul minta használható, mint díszítő minta, vagy pehelysúlyú minta vagy akár illesztő mintaként.
A modul mint tervezési minta
A modul mintára tekinthetünk létrehozási mintaként és szerkezeti mintaként is. Egyrészt menedzseli más elemek létrehozását és szervezését, másrészt csoportba (struktúrába) foglalja az elemeket, ahogyan a szerkezeti minták teszik.
A minta alkalmazása támogatja azokat a specifikus eseteket, amikor egy osztályra, strukturált, procedurális kódként tekintünk, csakúgy, mint ennek a fordítottját, ahol strukturált, procedurális kódra tekintünk objektumorientáltan, egy osztály metódusaiként.
Fordítás
Ez a szócikk részben vagy egészben a Module pattern című angol Wikipédia-szócikk fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.