النمط المفرد

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

النمط المفرد
صنف فرعي من
أنماط تصميم البرمجيات
جزء من
فروع
الموضوع
نمط تصميم ابداعي

يعتبر النقاد أن المفرد هو نمط مضاد (بالإنجليزية: anti-pattern)‏ لأنه يستخدم بشكل متكرر في السيناريوهات حيث لا يكون مفيدًا، ويقدم قيودًا غير ضرورية في المواقف التي لا يكون فيها مثيل (بالإنجليزية: instance)‏ وحيد للصنف (بالإنجليزية: class)‏ مطلوبًا بالفعل، ويدخل الحالة العامة (بالإنجليزية: global state)‏ في التطبيق.[1][2][3]

نظرة عامة


يُعد نمط التصميم المفرد[4] أحد أنماط التصميم الثلاثة والعشرون المعروفة باسم "عصابة الأربعة" (بالإنجليزية: "Gang of Four" design patterns)‏ التي تصف كيفية حل مشكلات التصميم المتكررة لتصميم برامج كائنية التوجه قابلة لإعادة الاستخدام ومرنة، أي الكائنات التي يسهل فيها التنفيذ (بالإنجليزية: implement )‏ والتغيير والاختبار وإعادة الاستخدام.

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

  • كيف يمكن التأكد من أن الصنف لديه مثيل(بالإنجليزية: instance)‏ واحد فقط؟
  • كيف يمكن الوصول إلى المثيل الوحيد الصنف بسهولة؟
  • كيف يمكن الصنف التحكم في تمثيها(بالإنجليزية: instantiation)‏؟
  • كيف يمكن تقييد عدد أمثال الصنف ؟

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

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

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

التنفيذ (بالإنجليزية: Implementation)‏

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

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

يتم تخزين المثيل عادة كمتغير ثابت خاص (بالإنجليزية: private static variable)‏؛ يتم إنشاء المثيل عند تهيئة (بالإنجليزية: initialized )‏المتغير، في مرحلة ما قبل استدعاء (بالإنجليزية: static method )‏ لأول مرة. فيما يلي نموذج تنفيذ مكتوب بلغة Java .

public final class Singleton {

  private static final Singleton INSTANCE = new Singleton();

  private Singleton() {}

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

تنفيذ C# implementation

public sealed class Singleton {

  private static readonly Singleton INSTANCE = new Singleton();

  private Singleton() {}

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

في سي شارب (بالإنجليزية: #C)‏ ، يمكنك أيضًا استخدام أصناف ثابتة (بالإنجليزية: static class)‏ لإنشاء أنماط فردية (بالإنجليزية: create singletons)‏، حيث يكون الصنف نفسه هو نمط مفرد (بالإنجليزية: singleton)‏.

public static class Singleton {

  private static readonly MyOtherClass INSTANCE = new MyOtherClass();

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

التهيئة البطيئة (بالإنجليزية: Lazy initialization)

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

[lower-alpha 1]

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;
  }
}

Dart implementation

class Singleton {
   
  static Singleton _instance;
  
  static Singleton get instance => _instance ?? Singleton._();
  
  Singleton._() => _instance = this;
}

PHP implementation

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]

public class Coin {

  private static final int ADD_MORE_COIN = 10;
  private int coin;
  private static Coin instance = new Coin(); // Eagerly Loading of single ton instance

  private Coin(){
    // private to prevent anyone else from instantiating
  }

  public static Coin getInstance(){
    return instance;
  }

  public int getCoin(){
    return coin;
  }

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

  public void deductCoin(){
    coin--;
  }
}

تنفيذ Kotlin[6]

الكلمة المفتاحية لكائن كوتلن (بالإنجليزية: Kotlin object keyword )‏يعلن (بالإنجليزية: declares)‏ عن صنف نمط مفرد (بالإنجليزية: singleton class)‏

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

  fun getCoin():Int{
    return coin
  }

  fun addCoin(){
    coin += 10
  }

  fun deductCoin(){
    coin--
  }
}

تنفيذ دلفي و Free Pascal

GetInstance الدالة عبارة عن تنفيذ خيوط أمن (بالإنجليزية: thread safe implementation)‏ للنمط المفرد (بالإنجليزية: Singleton)‏ .

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;

ملاحظات

  1. In Java, to avoid the synchronization overhead while keeping lazy initialization with thread safety, the preferred approach is to use the initialization-on-demand holder idiom.[بحاجة لمصدر]

    المراجع

    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. مؤرشف من الأصل في 18 مايو 2020. الوسيط |CitationClass= تم تجاهله (مساعدة)صيانة CS1: أسماء متعددة: قائمة المؤلفون (link)
    5. "The Singleton design pattern - Problem, Solution, and Applicability". w3sDesign.com. مؤرشف من الأصل في 18 مايو 2020. اطلع عليه بتاريخ 16 أغسطس 2017. الوسيط |CitationClass= تم تجاهله (مساعدة)
    6. "Are you an Android Developer and not using Singleton Class yet?". مؤرشف من الأصل في 18 مايو 2020. الوسيط |CitationClass= تم تجاهله (مساعدة)

      روابط خارجية

      • بوابة برمجة الحاسوب
      • بوابة علم الحاسوب
      This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.