الرئيسيةعريقبحث

النمط المفرد


☰ جدول المحتويات


في هندسة البرمجيات، يعد النمط المفرد (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)‏؟
  • كيف يمكن تقييد عدد أمثال الصنف ؟

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

  • إخفاء مُنشئ الصنف .(Hide the constructor of the class)‏
  • قم بتعريف (Define)‏عملية ثابتة عامة (public static operation)‏ (getInstance()) تقوم بإرجاع (returns)‏ المثيل الوحيد الصنف (sole instance of the class)‏ .

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

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

  • يمكن للمصنع المجرد ( abstract factory)‏، طريقة المصنع (factory method)‏، والباني ، وأنماط النموذج الأولي (prototype )‏ استخدام الانماط المفردة (singletons)‏ في تنفيذها.
  • غالبًا ما تكون كائنات الواجهة (Facade )‏مفردة (singletons)‏ لأن كائن واجهة (Facade )‏ واحد فقط مطلوب.
  • غالبًا ما تكون حالة للكائنات (State objects)‏ فردية (singleton)‏.
  • غالبًا ما تُفضل الأنماط المفردة (Singletons )‏ على المتغيرات العامة (global variables)‏ للأسباب التالية:
    • فهي لا تلوث مساحة الاسم العامة(global namespace)‏ (أومساحة الاسم التي تحتوي عليها، في اللغات ذات مساحات الأسماء المتداخلة(nested namespaces)‏) بمتغيرات غير ضرورية.
    • أنها تسمح بالتخصيص البطيء للذاكرة والتهيئة (lazy allocation and initialization)‏، في حين أن المتغيرات العامة في العديد من اللغات سوف تستهلك دائما الموارد المتاحة (resources)‏ .

التنفيذ (Implementation)‏

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

  • التأكد من وجود مثيل واحد فقط من صنف النمط الفردي (only one instance of the singleton class)‏؛ و
  • توفير الوصول العام ( global access)‏ إلى هذا المثيل (instance)‏.

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

  • الإعلان (declaring)‏عن بنائات (constructors )‏ الصنف لتكون بحالة الوصول الخاص(private)‏. و
  • توفير طريقة ثابتة (static method )‏ تقوم بإرجاع عنوان كمرجع ( reference)‏ إلى المثيل (instance)‏.

يتم تخزين المثيل عادة كمتغير ثابت خاص (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.

[a]

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

1 class Singleton { 2 3 static Singleton _instance; 4 5 static Singleton get instance => _instance ?? Singleton._(); 6 7 Singleton._() => _instance = this; 8 }

PHP implementation

1 class Singleton { 2 private static $instance = null; 3 4 private function __construct(){} 5 6 public static function getInstance(): self 7 { 8 if (null === self::$instance) { 9 self::$instance = new self(); 10 } 11 12 return self::$instance; 13 } 14 }

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

1 public class Coin { 2 3 private static final int ADD_MORE_COIN = 10; 4 private int coin; 5 private static Coin instance = new Coin(); // Eagerly Loading of single ton instance 6 7 private Coin(){ 8 // private to prevent anyone else from instantiating 9 } 10 11 public static Coin getInstance(){ 12 return instance; 13 } 14 15 public int getCoin(){ 16 return coin; 17 } 18 19 public void addMoreCoin(){ 20 coin += ADD_MORE_COIN; 21 } 22 23 public void deductCoin(){ 24 coin--; 25 } 26 }

تنفيذ Kotlin[6]

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

1 object Coin{ 2 // wrong example. 3 private var coin: Int = 0 4 5 fun getCoin():Int{ 6 return coin 7 } 8 9 fun addCoin(){ 10 coin += 10 11 } 12 13 fun deductCoin(){ 14 coin-- 15 } 16 }

تنفيذ دلفي و 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.  . مؤرشف من الأصل في 18 مايو 2020.
  5. "The Singleton design pattern - Problem, Solution, and Applicability". w3sDesign.com. مؤرشف من الأصل في 18 مايو 202016 أغسطس 2017.
  6. "Are you an Android Developer and not using Singleton Class yet?". مؤرشف من الأصل في 18 مايو 2020.

روابط خارجية

موسوعات ذات صلة :