Module pattern

Last updated

In software engineering, the module pattern is a design pattern used to implement the concept of software modules, defined by modular programming, in a programming language with incomplete direct support for the concept.

Contents

This pattern can be implemented in several ways depending on the host programming language, such as the singleton design pattern, object-oriented static members in a class and procedural global functions. In Python, the pattern is built into the language, and each .py file is automatically a module. The same applies to Ada, where the package can be considered a module (similar to a static class).

Definition & Structure

The module software design pattern provides the features and syntactic structure defined by the modular programming paradigm to programming languages that have incomplete support for the concept.

The object module pattern expressed in UML. Module-software-design-pattern.png
The object module pattern expressed in UML.

Concept

In software development, source code can be organized into components that accomplish a particular function or contain everything necessary to accomplish a particular task. Modular programming is one of those approaches.

The concept of a "module" is not fully supported in many common programming languages.

Features

In order to consider that a Singleton or any group of related code implements this pattern, the following features must be supplied:

Implementations

The semantics and syntax of each programming language may affect the implementation of this pattern.

Object-oriented programming languages

Java

Although Java supports the notion of a namespace, a reduced version of a module, some scenarios benefit from employing the design pattern instead of using namespaces.

The following example uses the singleton pattern.

Definition
packageconsoles;importjava.io.InputStream;importjava.io.PrintStream;publicfinalclassMainModule{privatestaticMainModulesingleton=null;publicInputStreaminput=null;publicPrintStreamoutput=null;publicPrintStreamerror=null;privateMainModule(){// does nothing on purpose !!!}// ...publicstaticMainModulegetSingleton(){if(MainModule.singleton==null){MainModule.singleton=newMainModule();}returnMainModule.singleton;}// ...publicvoidprepare(){//System.out.println("consoles::prepare();");this.input=newInputStream();this.output=newPrintStream();this.error=newPrintStream();}publicvoidunprepare(){this.output=null;this.input=null;this.error=null;//System.out.println("consoles::unprepare();");}// ...publicvoidprintNewLine(){System.out.println();}publicvoidprintString(Stringvalue){System.out.print(value);}publicvoidprintInteger(intvalue){System.out.print(value);}publicvoidprintBoolean(booleanvalue){System.out.print(value);}publicvoidscanNewLine(){// to-do: ...}publicvoidscanString(Stringvalue){// to-do: ...}publicvoidscanInteger(intvalue){// to-do: ...}publicvoidscanBoolean(booleanvalue){// to-do: ...}// ...}
Implementation
importconsoles.*;classConsoleDemo{publicstaticMainModuleconsole=null;publicstaticvoidprepare(){console=MainModule.getSingleton();console.prepare();}publicstaticvoidunprepare(){console.unprepare();}publicstaticvoidexecute(String[]args){console.printString("Hello World");console.printNewLine();console.scanNewLine();}publicstaticvoidmain(String[]args){prepare();execute(args);unprepare();}}

C# (C Sharp .NET)

C#, like Java, supports namespaces although the pattern remains useful in specific cases.

The following example uses the singleton pattern.

Definition
usingSystem;usingSystem.IO;usingSystem.Text;namespaceConsoles;publicsealedclassMainModule{privatestaticMainModuleSingleton=null;publicInputStreaminput=null;publicOutputStreamoutput=null;publicErrorStreamerror=null;// ...publicMainModule(){// does nothing on purpose !!!}// ...publicstaticMainModuleGetSingleton(){if(MainModule.Singleton==null){MainModule.Singleton=newMainModule();}returnMainModule.Singleton;}// ...publicvoidPrepare(){//System.WriteLine("console::prepare();");this.input=newInputStream();this.output=newOutputStream();this.error=newErrorStream();}publicvoidUnprepare(){this.output=null;this.input=null;this.error=null;//System.WriteLine("console::unprepare();");}// ...publicvoidPrintNewLine(){System.Console.WriteLine("");}publicvoidPrintString(StringValue){System.Console.Write(Value);}publicvoidPrintInteger(IntegerValue){System.Console.Write(Value);}publicvoidPrintBoolean(BooleanValue){System.Console.Write(Value);}publicvoidScanNewLine(){// to-do: ...}publicvoidScanString(StringValue){// to-do: ...}publicvoidScanInteger(IntegerValue){// to-do: ...}publicvoidScanBoolean(BooleanValue){// to-do: ...}// ...}
Implementation
classConsoleDemo{publicstaticConsoles.MainModuleConsole=null;publicstaticvoidPrepare(){Console=Consoles.MainModule.GetSingleton();Console.Prepare();}publicstaticvoidUnprepare(){Console.Unprepare();}publicstaticvoidExecute(){Console.PrintString("Hello World");Console.PrintNewLine();Console.ScanNewLine();}publicstaticvoidMain(){Prepare();Execute(args);Unprepare();}}

Prototype-based programming languages

JavaScript

JavaScript is commonly used to automate web pages.

Definition
functionConsoleClass(){varInput=null;varOutput=null;varError=null;// ...this.prepare=function(){this.Input=newInputStream();this.Output=newOutputStream();this.Error=newErrorStream();}this.unprepare=function(){this.Input=null;this.Output=null;this.Error=null;}// ...varprintNewLine=function(){// code that prints a new line}varprintString=function(params){// code that prints parameters}varprintInteger=function(params){// code that prints parameters}varprintBoolean=function(params){// code that prints parameters}varScanNewLine=function(){// code that looks for a newline}varScanString=function(params){// code that inputs data into parameters}varScanInteger=function(params){// code that inputs data into parameters}varScanBoolean=function(params){// code that inputs data into parameters}// ...}
Implementation
functionConsoleDemo(){varConsole=null;varprepare=function(){Console=newConsoleClass();Console.prepare();}varunprepare=function(){Console.unprepare();}varrun=function(){Console.printString("Hello World");Console.printNewLine();}varmain=function(){this.prepare();this.run();this.unprepare();}}

Procedural programming languages

This pattern may be seen as a procedural extension to object-oriented languages.

Although the procedural and modular programming paradigms are often used together, there are cases where a procedural programming language may not fully support modules, hence requiring a design pattern implementation.

PHP (procedural)

This example applies to procedural PHP before namespaces (introduced in version 5.3.0). It is recommended that each member of a module is given a prefix related to the filename or module name in order to avoid identifier collisions.

Definition
<?php// filename: console.phpfunctionconsole_prepare(){// code that prepares a "console"}functionconsole_unprepare(){// code that unprepares a "console"}// ...functionconsole_printNewLine(){// code that outputs a new line}functionconsole_printString(/* String */Value){// code that prints parameters}functionconsole_printInteger(/* Integer */Value){// code that prints parameters}functionconsole_printBoolean(/* Boolean */Value){// code that prints parameters}functionconsole_scanNewLine(){// code that looks for a new line}functionconsole_scanString(/* String */Value){// code that stores data into parameters}functionconsole_scanInteger(/* Integer */Value){// code that stores data into parameters}functionconsole_scanBoolean(/* Boolean */Value){// code that stores data into parameters}
Implementation
// filename: consoledemo.phprequire_once("console.php");functionconsoledemo_prepare(){console_prepare();}functionconsoledemo_unprepare(){console_unprepare();}functionconsoledemo_execute(){console_printString("Hello World");console_printNewLine();console_scanNewLine();}functionconsoledemo_main(){consoledemo_prepare();consoledemo_execute();consoledemo_unprepare();}

C

Note that this example applies to procedural C without namespaces. It is recommended that each member of a module is given a prefix related to the filename or module name in order to avoid identifier collisions.

Definition header module
// filename: "consoles.h"#include<stdio.h>#include<string.h>#include<ctype.h>voidconsoles_prepare();voidconsoles_unprepare();// ...voidconsoles_printNewLine();voidconsoles_printString(char*Value);voidconsoles_printInteger(intValue);voidconsoles_printBoolean(boolValue);voidconsoles_scanNewLine();voidconsoles_scanString(char*Value);voidconsoles_scanInteger(int*Value);voidconsoles_scanBoolean(bool*Value);
Definition body module
// filename: "consoles.c"#include<stdio.h>#include<string.h>#include<ctype.h>#include<consoles.h>voidconsoles_prepare(){// code that prepares console}voidconsoles_unprepare(){// code that unprepares console}// ...voidconsoles_printNewLine(){printf("\n");}voidconsoles_printString(char*Value){printf("%s",Value);}voidconsoles_printInteger(intValue){printf("%d",&Value);}voidconsoles_printBoolean(boolValue){printf((Value)?("true"):("false"));}voidconsoles_scanNewLine(){getch();}voidconsoles_scanString(char*Value){scanf("%s",Value);}voidconsoles_scanInteger(int*Value){scanf("%d",Value);}voidconsoles_scanBoolean(bool*Value){chartemp[512];scanf("%s",temp);*Value=(strcmp(Temp,"true")==0);}
Implementation
// filename: "consoledemo.c"#include<stdio.h>#include<string.h>#include<ctype.h>#include<consoles.h>voidconsoledemo_prepare(){consoles_prepare();}voidconsoledemo_unprepare(){consoles_unprepare();}intconsoledemo_execute(){consoles_printString("Hello World");consoles_printNewLine();consoles_scanNewLine();return0;}intmain(){ErrorCodeResult=0;consoledemo_prepare();ErrorCode=consoledemo_execute();consoledemo_unprepare();returnErrorCode;}

Procedural Pascal

Note that this example applies to procedural non-modular Pascal. Many Pascal dialects have namespace support, called "unit (s)". Some dialects also support initialization and finalization.

If namespaces are not supported, it is recommended to give all member names a prefix related to the filename or module name in order to prevent identifier collisions.

Definition
unitconsoles;(* filename: "consoles.pas" *)usescrt;procedureprepare();begin(* code that prepares console *)end;procedureunprepare();begin(* code that unprepares console *)end;// ...procedureprintNewLine();beginWriteLn();end;procedureprintString(Value:string);beginWrite(Value);end;procedureprintInteger(Value:integer);beginWrite(Value);end;procedureprintBoolean(Value:boolean);beginif(Value)thenbeginWrite('true');endelsebeginWrite('false');end;end;procedurescanNewLine();beginSeekEoLn();end;procedurescanString(Value:string);beginReadLn(Value);end;procedurescanInteger(Value:Integer);beginReadLn(Value);end;procedurescanBoolean(Value:Boolean);vartemp:string;beginReadLn(temp);if(Temp='true')thenbeginValue:=true;endelsebeginValue:=false;end;end;
Implementation
programconsoledemo;// filename: "consoles.pas"usesconsoles;procedureprepare();beginconsoles.prepare();end;procedureunprepare();beginconsoles.unprepare();end;functionexecute():Integer;beginconsoles.printString('Hello World');consoles.printNewLine();consoles.scanNewLine();execute:=0;end;beginprepare();execute();unprepare();end.

Comparisons to other concepts

Namespaces

Both namespaces and modules allow to group several related entities by a single identifier, and in some situations, used interchangeably. Those entities can be globally accessed. The main purpose of both concepts is the same.

In some scenarios a namespace requires that the global elements that compose it are initialized and finalized by a function or method call.

In many programming languages, namespaces are not directly intended to support an initialization process nor a finalization process, and are therefore not equivalent to modules. That limitation can be worked around in two ways. In namespaces that support global functions, a function for initialization and a function for finalization are coded directly, and called directly in the main program code.

Classes and namespaces

Classes are used sometimes used as or with namespaces. In programming languages that don't support namespaces (e.g., JavaScript) but do support classes and objects, classes are often used to substitute for namespaces. These classes are usually not instantiated and consist exclusively of static members.

Singleton classes and namespaces

In object-oriented programming languages where namespaces are incompletely supported, the singleton pattern may be used instead of static members within a non-instantiable class.

Relationship with other design patterns

The module pattern can be implemented using a specialization of the singleton pattern. However, other design patterns may be applied and combined, in the same class.

This pattern can be used as a decorator , a flyweight , or an adapter .

Module as a design pattern

The Module pattern can be considered a creational pattern and a structural pattern. It manages the creation and organization of other elements, and groups them as the structural pattern does.

An object that applies this pattern can provide the equivalent of a namespace, providing the initialization and finalization process of a static class or a class with static members with cleaner, more concise syntax and semantics.

It supports specific cases where a class or object can be considered structured, procedural data. And, vice versa, migrate structured, procedural data, and considered as object-oriented.

See also

Related Research Articles

In object-oriented programming and software engineering, the visitor design pattern is a way of separating an algorithm from an object structure on which it operates. A practical result of this separation is the ability to add new operations to existing object structures without modifying the structures. It is one way to follow the open/closed principle.

Singleton pattern

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one "single" instance. This is useful when exactly one object is needed to coordinate actions across the system.

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. It is a kind of lazy evaluation that refers specifically to the instantiation of objects or other resources.

In computer programming, the proxy pattern is a software design pattern. A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate. In short, a proxy is a wrapper or agent object that is being called by the client to access the real serving object behind the scenes. Use of the proxy can simply be forwarding to the real object, or can provide additional logic. In the proxy, extra functionality can be provided, for example caching when operations on the real object are resource intensive, or checking preconditions before operations on the real object are invoked. For the client, usage of a proxy object is similar to using the real object, because both implement the same interface.

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.

In computer programming, the interpreter pattern is a design pattern that specifies how to evaluate sentences in a language. The basic idea is to have a class for each symbol in a specialized computer language. The syntax tree of a sentence in the language is an instance of the composite pattern and is used to evaluate (interpret) the sentence for a client. See also Composite pattern.

The observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

Visual Basic .NET Object-oriented computer programming language

Visual Basic, originally called Visual Basic .NET (VB.NET), is a multi-paradigm, object-oriented programming language, implemented on .NET, Mono, and the .NET Framework. Microsoft launched VB.NET in 2002 as the successor to its original Visual Basic language, the last version of which was Visual Basic 6.0. Although the ".NET" portion of the name was dropped in 2005, this article uses "Visual Basic [.NET]" to refer to all Visual Basic languages released since 2002, in order to distinguish between them and the classic Visual Basic. Along with C# and F#, it is one of the three main languages targeting the .NET ecosystem. As of March 11, 2020, Microsoft announced that evolution of the VB.NET language has concluded.

In mathematics and computer science, a higher-order function is a function that does at least one of the following:

Java syntax

The syntax of Java refers to the set of rules defining how a Java program is written and interpreted.

In software engineering, dependency injection is a technique in which an object receives other objects that it depends on, called dependencies. Typically, the receiving object is called a client and the passed-in ('injected') object is called a service. The code that passes the service to the client is called the injector. Instead of the client specifying which service it will use, the injector tells the client what service to use. The 'injection' refers to the passing of a dependency into the client that uses it.

In computer programming, an entry point is a point in a program where the execution of a program begins, and where the program has access to command line arguments.

In mathematics and in computer programming, a variadic function is a function of indefinite arity, i.e., one which accepts a variable number of arguments. Support for variadic functions differs widely among programming languages.

C Sharp (programming language) Multi-paradigm (object-oriented) programming language

C# is a general-purpose, multi-paradigm programming language. C# encompasses static typing, strong typing, lexically scoped, imperative, declarative, functional, generic, object-oriented (class-based), and component-oriented programming disciplines.

Multiton pattern Software engineering design pattern

In software engineering, the multiton pattern is a design pattern which generalizes the singleton pattern. Whereas the singleton allows only one instance of a class to be created, the multiton pattern allows for the controlled creation of multiple instances, which it manages through the use of a map.

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

Oxygene (programming language) Object Pascal-based programming language

Oxygene is a programming language developed by RemObjects Software for Microsoft's Common Language Infrastructure, the Java Platform and Cocoa. Oxygene is based on Delphi's Object Pascal, but also has influences from C#, Eiffel, Java, F# and other languages.

In object-oriented computer programming, a null object is an object with no referenced value or with defined neutral (null) behavior. The null object design pattern, which describes the uses of such objects and their behavior, was first published in the Pattern Languages of Program Design book series.

This article describes the syntax of the C# programming language. The features described are compatible with .NET Framework and Mono.

Ceylon (programming language)

Ceylon is an object-oriented, strongly statically typed programming language with an emphasis on immutability, created by Red Hat. Ceylon programs run on the Java virtual machine (JVM), and could be compiled to JavaScript. The language design focuses on source code readability, predictability, toolability, modularity, and metaprogrammability.