Одинак (шаблон проектування)

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до: навігація, пошук

Одинак (англ. Singleton) — шаблон проектування, відноситься до класу твірних шаблонів. Гарантує, що клас матиме тільки один екземпляр, і забезпечує глобальну точку доступу до цього екземпляра.

Мотивація[ред.ред. код]

Для деяких класів важливо, щоб існував тільки один екземпляр. Наприклад, хоча у системі може існувати декілька принтерів, може бути тільки один спулер. Повинна бути тільки одна файлова система та тільки один активний віконний менеджер.

Глобальна змінна не вирішує такої проблеми, бо не забороняє створити інші екземпляри класу.

Рішення полягає в тому, щоб сам клас контролював свою «унікальність», забороняючи створення нових екземплярів, та сам забезпечував єдину точку доступу. Це є призначенням шаблону Одинак.

Застосування[ред.ред. код]

Слід використовувати шаблон Одинак коли:

  • повинен бути тільки один екземпляр деякого класу, що легко доступний всім клієнтам;
  • єдиний екземпляр повинен розширюватись шляхом успадкування, та клієнтам потрібно мати можливість працювати з розширеним екземпляром не змінюючи свій код.

Структура[ред.ред. код]

Діаграма класів, що описує структуру шаблону проектування Одинак
  • Singleton — одинак:
    • визначає операцію Instance, котра дозволяє клієнтам отримувати доступ до єдиного екземпляру. Instance — це операція класу;
    • може нести відповідальність за створення власного унікального екземпляру.

Відносини[ред.ред. код]

Клієнти отримують доступ до єдиного об'єкта класу Singleton лише через його операцію Instance.

Реалізації[ред.ред. код]

Реалізації на C++[ред.ред. код]

// Заголовочний файл (.h)
//
// Ниттєбезпечна реалізація Одинака
//
// Ця версія виглядає оманливо просто, проте вона має застереження. Перше,
// якщо одинак міститься в якійсь бібліотеці. Ті, хто використовуватимуть цю бібліотеку
// матимуть екземпляр одинака протягом виконання застосунка, незалежно
// від того, чи використовується він чи ні.
//
// Друге, це випадок статичних залежностей файлів. Наприклад, уявімо що
// Singleton є якоюсь абстрактною фабрикою для типа BaseType, і
// застосовується метод create. Оскільки порядок ініціалізації статичних змінних
// протягом трансляції модулів не визначений, це може призвести
// до доступу до Одинака до моменту його конструювання, іншими словами
// до невизначеної поведінки, що є погана річ.
//
// namespace { const BaseType * const fileStaticVariable = Singleton::getInstance().create(); }
//
class Singleton
{
private: 
  static Singleton _instance;
 
  Singleton() {}
  ~Singleton() {} 	 
  Singleton(const Singleton &);	 
  Singleton & operator=(const Singleton &);
 
public:
  static Singleton getInstance();
};
 
// Джерельний файл (.cpp)
 
// Ініціалізація статичного члена.
Singleton Singleton::_instance;
 
Singleton& Singleton::getInstance()
{
 return _instance;
}

Реалізації на Java[ред.ред. код]

Базовими засобами мови[ред.ред. код]

Enum singleton, починаючи з Java 1.5:

public enum SingletonEnum {  
   INSTANCE;  
}

Проста реалізація зі створенням об'єкта при завантаженні його класу[1]

 public class Singleton {
   private Singleton(){}  
   private static final Singleton instance = new Singleton();
   public static Singleton getInstance() {
     return instance;
   }
 }

Реалізація з відкладений (ледачим) створенням об'єкта при потребі, із синхронізацією для багатопоточної безпеки[1]

 public class Singleton {
   private Singleton(){}  
   private static Singleton instance;
   public static synchronized Singleton getInstance() {
      if (instance==null) {
        instance = new Singleton();
      }
     return instance;
   }
 }

Реалізація з відкладений (ледачим) створенням об'єкта при потребі, яка є багатопоточно безпечною, використовується шаблон Initialization on demand holder. Проблемою реалізації є те, що коли виникає помилка з киданням винятку при виконанні статичної ініціалізації, клас не завантажується і екземпляр одинака більше неможливо створити.

 public class Singleton {
   private Singleton() {}
 
  private static class SingletonHolder {
    private static final Singleton instance = new Singleton();
  } 
 
   public static Singleton getInstance() {
     return SingletonHolder.instance;
   }
 }

Бібіліотечними засобами[ред.ред. код]

Якщо система розподілена, кожна JVM може мати свій екземляр Одинака. У EJB 3.1 з'явилась аннотація @Singleton, яка забезпечує унікальність Одинака на різних JVM[2]

@Singleton
public class SingletonA { 
}

За допомогою аспектів[ред.ред. код]

Особливістю реалізації засобами мови програмування є необхідність для клієнта використовувати не конструктор, а фабричний метод для одержання об'єкта.

За допомогою засобів аспектно-орієнтованого програмування можна зробити реалізацію Одинака з використанням конструктора.

Реалізація за допомогою AspectJ [3]

 public abstract aspect AbstractSingletonAspect {
   private Object singleton = null;
   abstract pointcut singletonPointcut();
   Object around(): singletonPointcut() {
     if (singleton == null) {
       singleton = proceed();
     }
     return singleton;
   }
 }
 
 public aspect SingletonAspect extends AbstractSingletonAspect {
   pointcut singletonPointcut() : call(Stats.new(..));
 }

Реалізація за допомогою JBoss AOP[3]. Код аспекта:

 package aop.patterns.singleton;
 import org.jboss.aop.advice.Interceptor;
 import org.jboss.aop.joinpoint.Invocation;
 
 public class SingletonInterceptor implements Interceptor {
   private Object singleton;
   public Object invoke(Invocation invocation) throws Throwable {
     if (singleton==null) {
       singleton = invocation.invokeNext();
     }
     return singleton;
   }
 }

Конфігурація у jboss-aop.xml

 <bind pointcut="execution(aop.patterns.singleton.Singleton-&gt;new())">
   <interceptor class="aop.patterns.singleton.SingletonInterceptor" />
 </bind>

Реалізація на Actionscript 3.0[ред.ред. код]

package {
	public class Singleton  {
 
		private static var _instance:Singleton = new Singleton();
 
		public function Singleton () {	
	            if (_instance){
		        throw new Error( 
                            "Singleton can only be accessed through Singleton.getInstance()" 
                        );
                    }
		}
 
		public static function getInstance():Singleton {
			return _instance;
		}
 
	}
}


Реалізація на Ruby[ред.ред. код]

Мова програмування Ruby має вбудовану підтримку деяких шаблонів[4], зокрема й Одинака.

Модуль Singleton з бібіліотеки singleton робить конструктор приватним та надає фабричний метод.

 require 'singleton' 
 
 class MyClass 
   include Singleton 
 end 
 
 a = MyClass.instance

Реалізація на Scala[ред.ред. код]

У Scala шаблон підтримується засобами мови:

object Singleton
 
// Використання:
val singleton = Singleton

Реалізація на Smalltalk[ред.ред. код]

Реалізація на Smalltalk [5]:

new
    self error: 'cannot create new object'
 
default
    SoleInstance isNil ifTrue: [SoleInstance := super new].
    ^ SoleInstance


Реалізація на PHP5[ред.ред. код]

Реалізація на 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();
?>

Реалізація на Delphi[ред.ред. код]

Для Delphi 2005 та вище підходить наступний приклад:

Для більш ранніх версій треба перемістить код класу до окремого модулю, а оголошення Instance замінити оголошенням глобальної змінної в його секції implementation (до Delphi 7 включно секції class var та strict private були відсутніми).

Джерела[ред.ред. код]

  1. а б Peter Haggar, IBM developerWorks: Double-checked locking and the Singleton pattern
  2. Singleton EJB
  3. а б Foundations of AOP for J2EE Development. Renaud Pawlak, Lionel Seinturier, and Jean-Philippe Retaillé. Apress 2005. ISBN 1-59059-507-6.
  4. http://www.rubycentral.com/book/lib_patterns.html
  5. Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. Addison-Wesley, 1994. ISBN 0-201-63361-2

Див. також[ред.ред. код]

Зовнішні посилання[ред.ред. код]

Література[ред.ред. код]

Алан Шаллоуей, Джеймс Р. Тротт Шаблоны проектирования. Новый подход к объектно-ориентированному анализу и проектированию = Design Patterns Explained: A New Perspective on Object-Oriented Design. — М.: «Вильямс», 2002. — 288 с. — ISBN 0-201-71594-5.