النمط المفرد

في هندسة البرمجيات، يعد النمط المفرد (بالإنجليزية: 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.

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

روابط خارجية

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