סינגלטון (תבנית עיצוב)

תבנית סינגלטון (מאנגלית: Singleton, בעברית: יחידן לפי האקדמיה ללשון העברית) היא תבנית עיצוב (design pattern) בהנדסת תוכנה, אשר נועדה למקרים בהם מעוניינים להגביל את יצירת המופעים (Instances) של מחלקה (class) מסוימת למופע יחיד. תבנית זו שימושית כאשר נדרש רק מופע אחד על מנת לתאם פעולות במערכת. מתכנתים מסוימים מגדירים את התבנית הזו כתבנית anti-pattern, כלומר, תבנית שנראית מאוד פשוטה וברורה, אבל בפועל היא לא אופטימלית, או שימושית. הגדרה זו נובעת מכך שתבנית זו היא שכיחה מאוד בקרב מפתחים, ולעיתים רבות יוצרת הגבלות שלא לצורך, במצבים בהם אין צורך ממשי במופע יחיד.

==מימוש==
תרשים UML של מחלקה המממשת את תבנית סינגלטון
מימוש התבנית חייב לעמוד בשני עקרונות: מופע יחיד של המחלקה, וגישה גלובלית. נדרשת האפשרות לגשת לאיבר במחלקה סינגלטון מבלי ליצור אובייקט של המחלקה, וכן מנגנון אשר ישמור את ערכי האיברים של המופע שנוצר. התבנית מושגת באמצעות מחלקה הכוללת פונקציה, אשר בקריאה הראשונה יוצרת מופע חדש, ובקריאות הבאות, מחזירה מצביע לאותו מופע שיצרה קודם. כדי להבטיח שאכן יהיה מופע בודד של המחלקה ולא ניתן יהיה ליצור אותה בצורה אחרת, הגדרת הגישה לפונקציית הבנאי (Constructor) מוגדרת כ-private או protected.

ביישומים מרובי תהליכונים (multi-threaded applications) יש להיזהר במימוש התבנית. אם שני תהליכונים ניגשים לפונקציית הבנייה באותו הזמן, ייתכן מצב בו שניהם ייצרו מופע – מצב אותו אנו מנסים למנוע.

==דוגמאות מימוש==
=== Java ===
דרך בטוחה מבחינת תהליכונים (Threads) ב-Java הוצעה על ידי וילאם פו. היא נקראת גם "initialization on demand holder idiom" וממומשת בגישה של "אתחול עצל" (Lazy initialization). בגישה זו, יצירת המופע נדחית עד לרגע האחרון.

<syntaxhighlight lang="java">
public class Singleton { 
 // Private constructor suppresses generation of a (public) default constructor
 private Singleton() {}

 /**
 * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
 * or the first access to SingletonHolder.INSTANCE, not before.
 */
 private static class SingletonHolder { 
 private final static Singleton INSTANCE = new Singleton();
 }
 
 public static Singleton getInstance() {
 return SingletonHolder.INSTANCE;
 }
}
</syntaxhighlight>

דרך המימוש המסורתית האלגנטית והפשוטה מתחשבת בריבוי תהליכים, אך לא מממשת אתחול עצל:

<syntaxhighlight lang="java">
public class Singleton {
 private final static Singleton INSTANCE = new Singleton();
 
 // Private constructor suppresses generation of a (public) default constructor
 private Singleton() {}
 
 public static Singleton getInstance() {
 return INSTANCE;
 }
}
</syntaxhighlight>

=== #C ===
<syntaxhighlight lang="CSharp">
/// <summary>
/// Thread-safe singleton example without using locks
/// </summary>
public sealed class Singleton
{
 private static readonly Singleton instance = new Singleton();
 
 // Explicit static constructor to tell C# compiler
 // not to mark type as beforefieldinit
 static Singleton()
 {
 }
 
 Singleton()
 {
 }
 
 /// <summary>
 /// The public Instance property to use
 /// </summary>
 public static Singleton Instance
 {
 get { return instance; }
 }
}

</syntaxhighlight>

=== ++C ===
<syntaxhighlight lang="c++">
class Singleton
{
 private:
 /* Here will be the instance stored. */
 static Singleton* instance;

 /* Private constructor to prevent instancing. */
 Singleton();

 public:
 /* Static access method. */
 static Singleton* getInstance();
};

/* Null, because instance will be initialized on demand. */
Singleton* Singleton::instance = 0;

Singleton* Singleton::getInstance()
{
 if (instance == 0)
 {
 instance = new Singleton();
 }

 return instance;
}

Singleton::Singleton()
{}

</syntaxhighlight>

=== PHP 5 ===
תבנית סינגלטון ב-PHP, גרסה 5:

<syntaxhighlight lang="php">
<?php
class Singleton {
 // object instance
 private static $instance;
 
 private function __construct() {}
 
 private function __clone() {}
 
 public static function getInstance() {
 if (self::$instance === null) {
 self::$instance = new self;
 }
 return self::$instance;
 }

 public function doAction() {
 ...
 }
}

//usage
Singleton::getInstance()->doAction();

?>
</syntaxhighlight>

=== Objective-C ===
דרך פשוטה לממש סינגלטון ב-Objective-C:

<syntaxhighlight lang="objc">
@interface MySingleton : NSObject
{
}

+ (MySingleton *)sharedSingleton;
@end

@implementation MySingleton

+ (MySingleton *)sharedSingleton
{
 static MySingleton *sharedSingleton;
 
 @synchronized(self)
 {
 if (!sharedSingleton)
 sharedSingleton = Singleton
קטגוריה:1 (מספר)