نمط المفرد

احد انماط البرمجة المذكورة في كتاب عصابة الاربعة

في هندسة البرمجيات، يعد النمط المفرد أو الاحادي (بالإنجليزية: singleton pattern)‏ نمط تصميم برامجيات يقيد إنشاء مثيل برمجي لصنف واحد بمثيل «احادي». مفيد عندما تكون هناك حاجة إلى كائن واحد بالضبط لتنسيق الإجراءات عبر النظام. المصطلح يأتي من المفهوم الرياضي للأحادي.

singleton pattern

يعتبر النقاد أن المفرد هو نمط مضاد لأنه يستخدم بشكل متكرر في السيناريوهات حيث لا يكون مفيدًا، ويقدم قيودًا غير ضرورية في المواقف التي لا يكون فيها مثيل برمجي وحيد للصنف مطلوبًا بالفعل، ويدخل الحالة البرمجية العامة في التطبيق.[1][2][3]

نظرة عامة

عدل

يُعد نمط التصميم المفرد[4] أحد أنماط التصميم الثلاثة والعشرون المعروفة باسم "عصابة الأربعة" التي تصف كيفية حل مشكلات التصميم المتكررة لتصميم برامج كائنية التوجه قابلة لإعادة الاستخدام ومرنة، أي الكائنات التي يسهل فيها التنفيذ البرمجي والتغيير والاختبار وإعادة الاستخدام.

يحل نمط التصميم الفردي مشاكل مثل:[5]

  • كيف يمكن التأكد من أن الصنف لديه مثيل برمجي واحد فقط؟
  • كيف يمكن الوصول إلى المثيل الوحيد الصنف بسهولة؟
  • كيف يمكن الصنف التحكم في تمثيها البرمجي؟
  • كيف يمكن تقييد عدد أمثال الصنف؟

يصف نمط التصميم الفردي كيفية حل هذه المشاكل:

  • إخفاء مُنشئ الصنف.
  • قم بتعريف عملية ثابتة عامة برمجياً (بالإنجليزية: public static)‏ (()getInstance) تقوم بإرجاع برمجي (بالإنجليزية: returns)‏ المثيل الاحادي للصنف.

الفكرة الرئيسية في هذا النمط هي جعل الصنف نفسه مسؤول عن التحكم في استنساخه (التي يتم استنساخه مرة واحدة فقط). يضمن المُنشئ المخفي (المُعلن بوصول خاص (بالإنجليزية: declared private)‏) أنه لا يمكن إنشاء مثيل الصنف على الإطلاق من خارج الصنف. يمكن الوصول إلى العملية الثابتة العامة البرمجية بسهولة باستخدام اسم الصنف واسم العملية (()Singleton.getInstance).

الاستخدامات الشائعة

عدل
  • يمكن للمصنع المجرد، طريقة المصنع، والباني، وأنماط النموذج الأولي استخدام الانماط الاحادية في تنفيذها.
  • غالبًا ما تكون كائنات الواجهة احادية لأن كائن واجهة واحد فقط مطلوب.
  • غالبًا ما تكون كائنات الحالة احادية.
  • غالبًا ما تُفضل الأنماط المفردة على المتغيرات العامة للأسباب التالية:
    • فهي لا تلوث مساحة الاسم العامة (بالإنجليزية: global namespace)‏ (أومساحة الاسم التي تحتوي عليها، في اللغات ذات مساحات الأسماء المتداخلة) بمتغيرات غير ضرورية. [4]
    • أنها تسمح بالتخصيص البطيء للذاكرة والتهيئة، في حين أن المتغيرات العامة في العديد من اللغات سوف تستهلك دائما الموارد المتاحة.

التنفيذ

عدل

تنفيذ النمط المفرد يجب أن يتبع التالي:

  • التأكد من وجود مثيل برمجي واحد فقط من صنف النمط الفردي؛ و
  • توفير الوصول العام إلى هذا المثيل البرمجي.

عادة، يتم ذلك عن طريق:

  • الإعلان البرمجي عن بنائات الصنف لتكون بحالة الوصول الخاص. و
  • توفير طريقة ثابتة برمجياً تقوم بإرجاع عنوان برمجي كمرجع (بالإنجليزية: reference)‏ إلى المثيل.

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

تنفيذ جافا[6]

عدل
public class Coin {

  private static final int ADD_MORE_COIN = 10;
  private int coin;
  private static Coin instance = new Coin(); // تحميل باسرع وقت ممكن لمثيل احادي

  private Coin(){
    // private 
    // وضع وصول خاص لمنع اي شخص من انشاء مثيل برمجي
  }

  public static Coin getInstance(){
    return instance;
  }

  public int getCoin(){
    return coin;
  }

  public void addMoreCoin(){
    coin += ADD_MORE_COIN;
  }

  public void deductCoin(){
    coin--;
  }
}
public final class Singleton {

  private static final Singleton INSTANCE = new Singleton();

  private Singleton() {}

  public static Singleton getInstance() { 
    return INSTANCE;
  }
}

التهيئة البطيئة

عدل

قد ينفذ نمط الاحادي التهيئة البطيئة (بالإنجليزية: Lazy initialization)، حيث يتم إنشاء المثيل عندما يتم استدعاء الطريقة الثابتة برمجياً لأول مرة. إذا كان من الممكن استدعاء الطريقة الثابتة من خيوط متعددة (بالإنجليزية: Multiple threads)‏ بشكل متزامن، فقد يلزم اتخاذ تدابير لمنع ظروف السباق التي قد تؤدي إلى إنشاء مثيلات برمجية متعددة من الصنف. ما يلي هو تنفيذ نموذج سلامة الخيوط (بالإنجليزية: thread-safe)‏، باستخدام التهيئة البطيئة مع القفل المزدوج (بالإنجليزية: double-checked locking)‏، المكتوب بلغة جافا.

public final class Singleton {
 
  private static volatile Singleton instance = null;

  private Singleton() {}

  public static Singleton getInstance() {
    if (instance == null) {
      synchronized(Singleton.class) {
        if (instance == null) {
          instance = new Singleton();
        }
      }
    }

    return instance;
  }
}
public sealed class Singleton {

  private static readonly Singleton INSTANCE = new Singleton();

  private Singleton() {}

  public static Singleton Instance { 
    get {
      return INSTANCE;
    }
  }
}

في سي شارب، يمكنك أيضًا استخدام أصناف ثابتة لإنشاء أنماط احادية، حيث يكون الصنف نفسه هو نمط احادي.

public static class Singleton {

  private static readonly MyOtherClass INSTANCE = new MyOtherClass();

  public static MyOtherClass Instance {
    get {
      return INSTANCE;
    }
  }
}

تنفيذ لغة دارت

عدل
class Singleton {
   
  static Singleton _instance;
  
  static Singleton get instance => _instance ?? Singleton._();
  
  Singleton._() => _instance = this;
}
class Singleton {
  private static $instance = null;

  private function __construct(){}

  public static function getInstance(): self
  {
    if (null === self::$instance) {
      self::$instance = new self();
    }

    return self::$instance;
  }
}

تنفيذ كوتلن[6]

عدل

الكلمة المفتاحية لكائن كوتلن object يعلن برمجياً عن صنف من النمط الاحادي.

object Coin{
  // wrong example.
  private var coin: Int = 0

  fun getCoin():Int{
    return coin
  }

  fun addCoin(){
    coin += 10
  }

  fun deductCoin(){
    coin--
  }
}

تنفيذ دلفي وفريباسكال

عدل

GetInstance الدالة عبارة عن تنفيذ خيوط حاسوبي آمن للنمط البرمجي الاحادي.

unit SingletonPattern;

interface

type
 TTest = class sealed
 strict private
  FCreationTime: TDateTime;
 public
  constructor Create;
  property CreationTime: TDateTime read FCreationTime;
 end;

function GetInstance: TTest;

implementation

uses
 SysUtils
 , SyncObjs
 ;

var
 FCriticalSection: TCriticalSection;
 FInstance: TTest;

function GetInstance: TTest;
begin
 FCriticalSection.Acquire;
 try
  if not Assigned(FInstance) then
   FInstance := TTest.Create;

  Result := FInstance;
 finally
  FCriticalSection.Release;
 end;
end;

constructor TTest.Create;
begin
 inherited Create;
 FCreationTime := Now;
end;

initialization
 FCriticalSection := TCriticalSection.Create;

finalization
 FreeAndNil(FCriticalSection);

end.

طريقة الاستخدام هي كالتالي:

procedure TForm3.btnCreateInstanceClick(Sender: TObject);
var
 i: integer;
begin
 for i := 0 to 5 do
  ShowMessage(DateTimeToStr(GetInstance.CreationTime));
end;

ملحق: مسرد المصطلحات الإنجليزية

عدل
مَسرد المفردات وفق أقسام المقالة
المقدمة
نمط تصميم برامجيات software design pattern
إنشاء مثيل برمجي instantiation
لصنف class
«احادي» single
احادي singleton
نمط مضاد anti-pattern
الحالة البرمجية العامة Global variables
عصابة الأربعة (الأنماط البرمجية) "Gang of Four" design patterns
تنفيذ برمجي implement
منشىْ الصنف the constructor of the class
تعريف برمجي Define
خاصية الثبات بالنسبة للصنف static
خاصية حالة الوصول عامة public
مثيل احادي للصنف sole instance of the class
خاصية حالة الوصول الخاص private
صنف من النمط الاحادي singleton class
الكلمة المفتاحية لكائن كوتلن Kotlin object keyword
يعلن برمجياً declares
تنفيذ خيوط حاسوبي أمن thread safe implementation
فريباسكال Free Pascal
للمصنع المجرد abstract factory
طريقة المصنع factory method
أنماط النموذج الأولي prototype
الانماط الاحادية Singletons
واجهة Facade
كائنات الحالة State objects
المتغيرات العامة global variables
التخصيص والتهيئة lazy allocation and initialization
مساحات الأسماء المتداخلة nested namespaces
موادر برمجية resources
التنفيذ Implementation
الوصول العام global access
المثيل البرمجي instance
بنائات constructors
تهيئة بطيئة Lazy initialization

ملاحظات

عدل

المراجع

عدل
  1. ^ Scott Densmore. Why singletons are evil, May 2004 نسخة محفوظة 1 ديسمبر 2019 على موقع واي باك مشين.
  2. ^ Steve Yegge. Singletons considered stupid, September 2004 نسخة محفوظة 17 ديسمبر 2009 على موقع واي باك مشين.
  3. ^ Clean Code Talks - Global State and Singletons نسخة محفوظة 3 مارس 2016 على موقع واي باك مشين.
  4. ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. ص. 127ff. ISBN:0-201-63361-2. مؤرشف من الأصل في 2020-05-18.{{استشهاد بكتاب}}: صيانة الاستشهاد: أسماء متعددة: قائمة المؤلفين (link)
  5. ^ "The Singleton design pattern - Problem, Solution, and Applicability". w3sDesign.com. مؤرشف من الأصل في 2020-05-18. اطلع عليه بتاريخ 2017-08-16.
  6. ^ ا ب "Are you an Android Developer and not using Singleton Class yet?". مؤرشف من الأصل في 2020-05-18.

روابط خارجية

عدل