نمط الوحدة

في هندسة البرمجيات ، يُعد نمط الوحدة نمط تصميم يُستخدم لتطبيق مفهوم وحدات البرمجيات ، الذي يُعرّف بواسطة البرمجة المعيارية ، في لغة برمجة ذات دعم مباشر غير كامل لهذا المفهوم. [ 1 ]

يمكن تطبيق هذا النمط بعدة طرق حسب لغة البرمجة المستخدمة، مثل نمط التصميم Singleton ، والأعضاء الثابتة في الأصناف الموجهة للكائنات، والدوال العامة الإجرائية. في بايثون، يُعدّ هذا النمط جزءًا لا يتجزأ من اللغة، ويُمثّل كل ملف ‎.py وحدةً تلقائيًا. وينطبق الأمر نفسه على لغة آدا، حيث يمكن اعتبار الحزمة وحدةً (شبيهةً بالصنف الثابت).

التعريف والبنية

يوفر نمط تصميم البرمجيات المعيارية الميزات والبنية النحوية المحددة بواسطة نموذج البرمجة المعيارية للغات البرمجة التي لا تدعم هذا المفهوم بشكل كامل.

نمط وحدة الكائن المعبر عنه في لغة النمذجة الموحدة (UML).
نمط وحدة الكائن المعبر عنه في لغة النمذجة الموحدة (UML) .

مفهوم

في تطوير البرمجيات، يمكن تنظيم شفرة المصدر في مكونات تؤدي وظيفة معينة أو تحتوي على كل ما هو ضروري لإنجاز مهمة معينة. البرمجة المعيارية هي أحد هذه الأساليب.

لا يتم دعم مفهوم "الوحدة النمطية" بشكل كامل في العديد من لغات البرمجة الشائعة.

سمات

لكي يُعتبر نمط Singleton أو أي مجموعة من التعليمات البرمجية ذات الصلة مُطبقًا لهذا النمط، يجب توفير الميزات التالية:

  • يجب أن يكون جزء من الكود متاحًا للجميع أو بشكل عام، وأن يكون مصممًا للاستخدام ككود عام. ويمكن تنفيذ أكواد خاصة أو محمية إضافية بواسطة الكود العام الرئيسي.
  • يجب أن تحتوي الوحدة على دالة تهيئة مكافئة أو مكملة لدالة إنشاء الكائن . هذه الميزة غير مدعومة في مساحات الأسماء العادية .
  • يجب أن تحتوي الوحدة على دالة إنهاء مكافئة أو مكملة لدالة تدمير الكائن. هذه الميزة غير مدعومة في مساحات الأسماء العادية.
  • قد تتطلب الأعضاء الداعمة رمز تهيئة/إنهاء يتم تنفيذه بواسطة دالة التهيئة/الإنهاء الخاصة بالوحدة.
  • معظم الأعضاء عبارة عن دوال تُجري عمليات على عناصر خارجية للفئة، يتم توفيرها كوسائط بواسطة الدوال المستدعِية. هذه الدوال هي "أدوات مساعدة" أو "مكتبات".

التطبيقات

قد تؤثر دلالات وبنية كل لغة برمجة على تطبيق هذا النمط.

لغات البرمجة الكائنية التوجه

جافا

على الرغم من أن لغة جافا تدعم مفهوم مساحة الاسم ، وهي نسخة مصغرة من الوحدة النمطية، إلا أن بعض السيناريوهات تستفيد من استخدام نمط التصميم بدلاً من استخدام مساحات الأسماء.

يستخدم المثال التالي نمط المفرد.

تعريف
الحزمة org.wikipedia.consoles ؛استيراد java.io.InputStream ؛ استيراد 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 () { // لا يفعل شيئًا عن قصد !!! }// ...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: ... } // ... }
تطبيق
استيراد org.wikipedia.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# ، مثل لغة Java، مساحات الأسماء على الرغم من أن هذا النمط يظل مفيدًا في حالات محددة.

يستخدم المثال التالي نمط المفرد.

تعريف
باستخدام System ؛ باستخدام System.IO ؛ باستخدام System.Text ؛مساحة الاسم Consoles ;public sealed class MainModule { private static MainModule Singleton = null ; public InputStream input = null ; public OutputStream output = null ; public ErrorStream error = null ;// ...public MainModule () { // لا يفعل شيئًا عن قصد !!! }// ...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 ;// Console.WriteLine("console::unprepare();"); }// ...public void PrintNewLine () { Console . WriteLine ( "" ); }public void PrintString ( string Value ) { Console . Write ( Value ); }public void PrintInteger ( int Value ) { Console . Write ( Value ); }public void PrintBoolean ( bool Value ) { Console . Write ( Value ); }public void ScanNewLine () { // to-do: ... }public void ScanString ( string Value ) { // to-do: ... }public void ScanInteger ( int Value ) { // to-do: ... }public void ScanBoolean ( bool Value ) { // to-do: ... }// ... }
تطبيق
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 ( string [] args ) { Prepare (); Execute ( args ); Unprepare (); } }

لغات البرمجة القائمة على النماذج الأولية

جافا سكريبت

تُستخدم لغة جافا سكريبت بشكل شائع لأتمتة صفحات الويب.

تعريف
دالة ConsoleClass () { متغير الإدخال = لا شيء ؛ متغير الإخراج = لا شيء ؛ متغير الخطأ = لا شيء ؛// ... 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 ( ) { // كود لطباعة سطر جديد }var printString = function ( params ) { // الكود الذي يطبع المعاملات }var printInteger = function ( params ) { // الكود الذي يطبع المعاملات }var printBoolean = function ( params ) { // الكود الذي يطبع المعاملات }var ScanNewLine = function () { // الكود الذي يبحث عن سطر جديد }var ScanString = function ( params ) { // الكود الذي يُدخل البيانات في المعاملات } var ScanInteger = function ( params ) { // الكود الذي يُدخل البيانات في المعاملات }var ScanBoolean = function ( params ) { // الكود الذي يُدخل البيانات في المعاملات } // ... }
تطبيق
دالة 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 ( ) ; } }

لغات البرمجة الإجرائية

يمكن اعتبار هذا النمط امتدادًا إجرائيًا للغات البرمجة الكائنية التوجه.

على الرغم من أن نماذج البرمجة الإجرائية والنمطية تستخدم غالبًا معًا، إلا أن هناك حالات قد لا تدعم فيها لغة البرمجة الإجرائية الوحدات النمطية بشكل كامل، مما يتطلب تنفيذ نمط تصميم.

PHP (إجرائي)

ينطبق هذا المثال على لغة PHP الإجرائية قبل استخدام مساحات الأسماء (التي تم تقديمها في الإصدار 5.3.0). يُنصح بإعطاء كل عنصر من عناصر الوحدة بادئة مرتبطة باسم الملف أو اسم الوحدة لتجنب تضارب المعرفات.

تعريف
<?php // اسم الملف: console.phpfunction console_prepare () { // الكود الذي يُهيئ "وحدة التحكم" }function console_unprepare () { // الكود الذي يُلغي تهيئة "وحدة التحكم" }// ...function console_printNewLine () { // الكود الذي يُخرج سطرًا جديدًا }function console_printString ( /* String */ Value ) { // الكود الذي يطبع المعاملات }دالة console_printInteger ( /* عدد صحيح */ القيمة ) { // الكود الذي يطبع المعاملات }دالة console_printBoolean ( /* قيمة منطقية */ Value ) { // الكود الذي يطبع المعاملات }function console_scanNewLine () { // الكود الذي يبحث عن سطر جديد }دالة console_scanString ( /* سلسلة نصية */ القيمة ) { // الكود الذي يخزن البيانات في المعاملات }دالة console_scanInteger ( /* عدد صحيح */ القيمة ) { // الكود الذي يخزن البيانات في المعاملات }دالة console_scanBoolean ( /* قيمة منطقية */ ) { // الكود الذي يخزن البيانات في المعاملات }
تطبيق
// اسم الملف: consoledemo.phprequire_once ( "console.php" );function consoledemo_prepare () { console_prepare (); }function consoledemo_unprepare () { console_unprepare (); }دالة consoledemo_execute () { console_printString ( "Hello World" ); console_printNewLine (); console_scanNewLine (); }دالة consoledemo_main () { consoledemo_prepare (); consoledemo_execute (); consoledemo_unprepare (); }

ج

لاحظ أن هذا المثال ينطبق على لغة C الإجرائية بدون مساحات أسماء. يُنصح بإعطاء كل عنصر من عناصر الوحدة النمطية بادئة مرتبطة باسم الملف أو اسم الوحدة النمطية لتجنب تضارب المعرفات.

وحدة رأس التعريف
// اسم الملف: "consoles.h" #pragma oncevoid consolesPrepare (); void consolesUnprepare ();// ...void consolesPrintNewLine ();void consolesPrintString ( char * value ); void consolesPrintInteger ( int value ); void consolesPrintBoolean ( bool value );void consolesScanNewLine ();void consolesScanString ( char * value ); void consolesScanInteger ( int * value ); void consolesScanBoolean ( bool * value );
وحدة تعريف الجسم
// اسم الملف: "consoles.c"#include <ctype.h> #include <stdio.h> #include <string.h>#include "consoles.h"void consolesPrepare () { // الكود الذي يُهيئ وحدة التحكم }void consolesUnprepare () { // كود لإلغاء تهيئة وحدة التحكم }// ...void consolesPrintNewLine () { printf ( " \n " ); }void consolesPrintString ( char * value ) { printf ( "%s" , value ); }void consolesPrintInteger ( int value ) { printf ( "%d" , & value ); }void consolesPrintBoolean ( bool value ) { printf (( value ) ? ( "true" ) : ( "false" )); }void consolesScanNewLine () { getch (); }void consolesScanString ( char * value ) { scanf ( "%s" , value ); }void consolesScanInteger ( int * value ) { scanf ( "%d" , Value ); }void consolesScanBoolean ( bool * value ) { char temp [ 512 ]; scanf ( "%s" , temp );* القيمة = ( strcmp ( temp , "true" ) == 0 ); }
تطبيق
// اسم الملف: "consoledemo.c"#include "consoles.h"void consoledemoPrepare () { consolesPrepare (); } void consoledemoUnprepare () { consolesUnprepare (); } int consoledemoExecute () { consolesPrintString ( "Hello World" ); consolesPrintNewLine (); consolesScanNewLine (); return 0 ; } int main () { int result = 0 ;consoledemoPrepare (); result = consoledemoExecute (); consoledemoUnprepare ();أعد النتيجة ؛ }

باسكال الإجرائي

لاحظ أن هذا المثال ينطبق على لغة باسكال الإجرائية غير المعيارية. تدعم العديد من لهجات باسكال مساحات الأسماء، والتي تُسمى "وحدات". كما تدعم بعض اللهجات عمليات التهيئة والإنهاء.

إذا لم تكن مساحات الأسماء مدعومة، فمن المستحسن إعطاء جميع أسماء الأعضاء بادئة مرتبطة باسم الملف أو اسم الوحدة النمطية لمنع تضارب المعرفات.

تعريف
وحدات تحكم الوحدة ؛ (* اسم الملف: "consoles.pas" *)يستخدم crt ؛إجراء التحضير () ؛ ابدأ (* الكود الذي يُهيئ وحدة التحكم *) انتهى ؛ إجراء إلغاء التحضير () ؛ ابدأ (* الكود الذي يُلغي تحضير وحدة التحكم *) انتهى ؛// ... الإجراء printNewLine () ; ابدأ WriteLn () ; انتهى ؛ الإجراء printString ( Value : string ) ; ابدأ Write ( Value ) ; انتهى ؛ الإجراء printInteger ( Value : integer ) ; ابدأ Write ( Value ) ; انتهى ؛ الإجراء printBoolean ( Value : boolean ) ; ابدأ إذا ( Value ) ابدأ Write ( 'true' ) ; انتهى وإلا ابدأ Write ( 'false' ) ; انتهى ؛ انتهى ؛ الإجراء scanNewLine ( ) ; ابدأ SeekEoLn () ; انتهى ؛ الإجراء scanString ( Value : string ) ; ابدأ ReadLn ( Value ) ; انتهى ؛ الإجراء scanInteger ( Value : Integer ) ; ابدأ ReadLn ( Value ) ; انتهى ؛ الإجراء scanBoolean ( Value : Boolean ) ; var temp : string ; ابدأ ReadLn ( temp ) ; إذا ( Temp = 'true' ) ابدأ Value : = true ; انتهى وإلا ابدأ Value := false ; نهاية ؛ نهاية ؛
تطبيق
برنامج consoledemo ؛ // اسم الملف: "consoles.pas"يستخدم وحدات التحكم ؛إجراء التحضير () ؛ ابدأ وحدة التحكم . التحضير () ؛ نهاية ؛ إجراء إلغاء التحضير () ؛ ابدأ وحدة التحكم . إلغاء التحضير () ؛ نهاية ؛دالة execute ( ) : عدد صحيح ؛ ابدأ consoles.printString ( 'Hello World' ) ; consoles.printNewLine ( ) ; consoles.scanNewLine ( ) ; execute := 0 ; نهاية ؛ ابدأ prepare ( ) ; execute ( ) ; unprepare ( ) ; نهاية .

مقارنات مع مفاهيم أخرى

مساحات الأسماء

تتيح كل من مساحات الأسماء والوحدات النمطية تجميع عدة كيانات ذات صلة باستخدام مُعرّف واحد، وفي بعض الحالات، يمكن استخدامهما بشكل تبادلي. ويمكن الوصول إلى هذه الكيانات على مستوى العالم. والهدف الرئيسي من كلا المفهومين واحد.

في بعض السيناريوهات، يتطلب نطاق الاسم أن يتم تهيئة وإنهاء العناصر العامة التي يتكون منها بواسطة دالة أو استدعاء طريقة.

في العديد من لغات البرمجة، لا تُصمَّم مساحات الأسماء لدعم عملية التهيئة أو عملية الإنهاء بشكل مباشر، وبالتالي فهي لا تُعادل الوحدات النمطية. يمكن تجاوز هذا القيد بطريقتين: في مساحات الأسماء التي تدعم الدوال العامة، تُكتب دالة التهيئة ودالة الإنهاء مباشرةً، ويتم استدعاؤهما مباشرةً في كود البرنامج الرئيسي.

الفئات ومساحات الأسماء

تُستخدم الفئات أحيانًا كبديل للمساحات الاسمية أو معها . في لغات البرمجة التي لا تدعم المساحات الاسمية (مثل جافا سكريبت) ولكنها تدعم الفئات والكائنات، تُستخدم الفئات غالبًا كبديل للمساحات الاسمية. عادةً لا يتم إنشاء مثيلات لهذه الفئات، وتتكون حصريًا من أعضاء ثابتة.

الفئات الفردية ومساحات الأسماء

في لغات البرمجة الموجهة للكائنات حيث لا يتم دعم مساحات الأسماء بشكل كامل، يمكن استخدام نمط Singleton بدلاً من الأعضاء الثابتة داخل فئة غير قابلة للإنشاء.

العلاقة مع أنماط التصميم الأخرى

يمكن تطبيق نمط الوحدة باستخدام تخصص من نمط المفرد. ومع ذلك، يمكن تطبيق أنماط تصميم أخرى ودمجها في نفس الفئة.

يمكن استخدام هذا النمط كعنصر تزييني ، أو كوزن خفيف ، أو كمحول .

الوحدة كنمط تصميم

يمكن اعتبار نمط الوحدة نمطًا إنشائيًا ونمطًا هيكليًا . فهو يدير إنشاء وتنظيم العناصر الأخرى، ويجمعها كما يفعل النمط الهيكلي.

يمكن للكائن الذي يطبق هذا النمط أن يوفر ما يعادل مساحة الاسم ، مما يوفر عملية التهيئة والإنهاء لفئة ثابتة أو فئة ذات أعضاء ثابتة بصيغة ودلالات أنظف وأكثر إيجازًا .

يدعم هذا النظام حالات محددة يمكن فيها اعتبار فئة أو كائن بيانات هيكلية وإجرائية. والعكس صحيح، حيث يمكن ترحيل البيانات الهيكلية والإجرائية واعتبارها كائنية التوجه.

انظر أيضاً

مراجع

  1. سيدنجاد، ساسان (2016).البرمجة المعيارية باستخدام جافا سكريبت(الطبعة الأولى  ). برمنغهام، المملكة المتحدة: دار نشر باكت المحدودة. ص  274. رقم ISBN 978-1-78588-065-0.