النمط المفرد
في هندسة البرمجيات، يعد النمط المفرد (بالإنجليزية: 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)) بمتغيرات غير ضرورية. [4]
- أنها تسمح بالتخصيص البطيء للذاكرة والتهيئة (بالإنجليزية: 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.
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;
ملاحظات
- 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.[بحاجة لمصدر]
المراجع
- Scott Densmore. Why singletons are evil, May 2004 نسخة محفوظة 1 ديسمبر 2019 على موقع واي باك مشين.
- Steve Yegge. Singletons considered stupid, September 2004 نسخة محفوظة 17 ديسمبر 2009 على موقع واي باك مشين.
- Clean Code Talks - Global State and Singletons نسخة محفوظة 3 مارس 2016 على موقع واي باك مشين.
- 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) - "The Singleton design pattern - Problem, Solution, and Applicability". w3sDesign.com. مؤرشف من الأصل في 18 مايو 2020. اطلع عليه بتاريخ 16 أغسطس 2017. الوسيط
|CitationClass=
تم تجاهله (مساعدة) - "Are you an Android Developer and not using Singleton Class yet?". مؤرشف من الأصل في 18 مايو 2020. الوسيط
|CitationClass=
تم تجاهله (مساعدة)
روابط خارجية
- المقال بالكامل " تقنيات نمط تصميم Singleton "
- أربع طرق مختلفة لتنفيذ المفرد في جاوا " طرق تنفيذ المفرد في جاوا "
- مقتطف من كتاب: تنفيذ نمط Singleton في C # بواسطة جون سكيت
- Singleton في Microsoft Developer & Practice Practice Center
- مقالة آي بي إم " قفل مزدوج ونمط Singleton " بقلم بيتر هاجار
- مقالة آي بي إم " استخدم أغانيك الفردية بحكمة " بقلم جيه بي رينزبيرجر
- مقال Javaworld " Simply Singleton " بقلم ديفيد جيري
- مقال على Google " لماذا تعد الجنايات الفردية مثيرة للجدل "
- كاشف Singleton من Google (يحلل رمز Java الثانوي لرصد المفردات)
- صور وملفات صوتية من كومنز
- بوابة برمجة الحاسوب
- بوابة علم الحاسوب