Design patterns
Singleton
Sök…
Anmärkningar
Singleton-designmönstret betraktas ibland som " Anti-mönster ". Detta beror på att det har några problem. Du måste själv bestämma om du tycker att det är lämpligt att använda det. Detta ämne har diskuterats flera gånger på StackOverflow.
Se: http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons
Singleton (C #)
Singletoner används för att säkerställa att endast en instans av ett objekt skapas. Singleton tillåter bara en enda instans av sig själv att skapa vilket innebär att den styr dess skapelse. Singleton är en av Gang of Fours designmönster och är ett kreativt mönster .
Trådsäkert Singleton-mönster
public sealed class Singleton
{
private static Singleton _instance;
private static object _lock = new object();
private Singleton()
{
}
public static Singleton GetSingleton()
{
if (_instance == null)
{
CreateSingleton();
}
return _instance;
}
private static void CreateSingleton()
{
lock (_lock )
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
}
Jon Skeet tillhandahåller följande implementering för en lat, trådsäker singleton:
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
private Singleton()
{
}
}
Singleton (Java)
Singletons i Java liknar mycket C # eftersom båda språken är objektorienterade. Nedan är ett exempel på en singleton-klass, där endast en version av objektet kan vara levande under programmets livstid (förutsatt att programmet fungerar på en tråd)
public class SingletonExample {
private SingletonExample() { }
private static SingletonExample _instance;
public static SingletonExample getInstance() {
if (_instance == null) {
_instance = new SingletonExample();
}
return _instance;
}
}
Här är den trådsäkra versionen av det programmet:
public class SingletonThreadSafeExample {
private SingletonThreadSafeExample () { }
private static volatile SingletonThreadSafeExample _instance;
public static SingletonThreadSafeExample getInstance() {
if (_instance == null) {
createInstance();
}
return _instance;
}
private static void createInstance() {
synchronized(SingletonThreadSafeExample.class) {
if (_instance == null) {
_instance = new SingletonThreadSafeExample();
}
}
}
}
Java har också ett objekt som heter ThreadLocal
, som skapar en enda instans av ett objekt på en tråd för trådbasis. Detta kan vara användbart i applikationer där varje tråd behöver sin egen version av objektet
public class SingletonThreadLocalExample {
private SingletonThreadLocalExample () { }
private static ThreadLocal<SingletonThreadLocalExample> _instance = new ThreadLocal<SingletonThreadLocalExample>();
public static SingletonThreadLocalExample getInstance() {
if (_instance.get() == null) {
_instance.set(new SingletonThreadLocalExample());
}
return _instance.get();
}
}
Här är också en Singleton- implementering med enum
(som endast innehåller ett element):
public enum SingletonEnum {
INSTANCE;
// fields, methods
}
Varje Enum-klassimplementering säkerställer att det bara finns en instans av dess varje element kommer att existera.
Bill Pugh Singleton-mönster
Bill Pugh Singleton Pattern är den mest använda metoden för Singleton klass eftersom det inte kräver synkronisering
public class SingletonExample {
private SingletonExample(){}
private static class SingletonHolder{
private static final SingletonExample INSTANCE = new SingletonExample();
}
public static SingletonExample getInstance(){
return SingletonHolder.INSTANCE;
}
}
med att använda privat inre statisk klass laddas inte innehavaren förrän någon anropar getInstance-metoden. Bill Pugh-lösningen är trådsäker och den kräver inte synkronisering.
Det finns fler Java-singleton-exempel i Singletons ämne under Java-dokumentationstaggen.
Singleton (C ++)
Enligt Wiki : I programvaruteknik är singletonmönstret ett designmönster som begränsar inställningen av en klass till ett objekt.
Detta krävs för att skapa exakt ett objekt för att koordinera åtgärder över hela systemet.
class Singleton
{
// Private constructor so it can not be arbitrarily created.
Singleton()
{}
// Disable the copy and move
Singleton(Singleton const&) = delete;
Singleton& operator=(Singleton const&) = delete;
public:
// Get the only instance
static Singleton& instance()
{
// Use static member.
// Lazily created on first call to instance in thread safe way (after C++ 11)
// Guaranteed to be correctly destroyed on normal application exit.
static Singleton _instance;
// Return a reference to the static member.
return _instance;
}
};
Lazy Singleton praktiskt exempel på java
Verkliga användningsfall för Singleton-mönster;
Om du utvecklar en klient-serverapplikation behöver du en enda instans av ConnectionManager
, som hanterar livscykeln för klientanslutningar.
De grundläggande API: erna i ConnectionManager:
registerConnection
: Lägg till en ny anslutning till befintlig lista över anslutningar
closeConnection
: Stäng anslutningen antingen från händelse som utlöses av klient eller server
broadcastMessage
: Några gånger måste du skicka ett meddelande till alla abonnemangsklientanslutningar.
Jag tillhandahåller inte fullständig implementering av källkoden eftersom exempel kommer att bli väldigt långa. På hög nivå kommer koden att vara så här.
import java.util.*;
import java.net.*;
/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class LazyConnectionManager {
private Map<String,Connection> connections = new HashMap<String,Connection>();
private LazyConnectionManager() {}
public static LazyConnectionManager getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
}
/* Make sure that De-Serailzation does not create a new instance */
private Object readResolve() {
return LazyHolder.INSTANCE;
}
public void registerConnection(Connection connection){
/* Add new connection to list of existing connection */
connections.put(connection.getConnectionId(),connection);
}
public void closeConnection(String connectionId){
/* Close connection and remove from map */
Connection connection = connections.get(connectionId);
if ( connection != null) {
connection.close();
connections.remove(connectionId);
}
}
public void broadcastMessage(String message){
for (Map.Entry<String, Connection> entry : connections.entrySet()){
entry.getValue().sendMessage(message);
}
}
}
Exempel Serverklass:
class Server implements Runnable{
ServerSocket socket;
int id;
public Server(){
new Thread(this).start();
}
public void run(){
try{
ServerSocket socket = new ServerSocket(4567);
while(true){
Socket clientSocket = socket.accept();
++id;
Connection connection = new Connection(""+ id,clientSocket);
LazyConnectionManager.getInstance().registerConnection(connection);
LazyConnectionManager.getInstance().broadcastMessage("Message pushed by server:");
}
}catch(Exception err){
err.printStackTrace();
}
}
}
Andra fall för praktisk användning för Singletons:
- Hantera globala resurser som
ThreadPool, ObjectPool, DatabaseConnectionPool
etc. - Centraliserade tjänster som
Logging
applikationsdata med olikaDEBUG,INFO,WARN,ERROR
somDEBUG,INFO,WARN,ERROR
etc - Global
RegistryService
där olika tjänster är registrerade med en central komponent vid start. Den globala tjänsten kan fungera som enFacade
för applikationen
C # Exempel: Multithreaded Singleton
Statisk initialisering är lämplig för de flesta situationer. När din ansökan måste försena inställningen, använda en icke-standardkonstruktör eller utföra andra uppgifter innan inställningen och arbeta i en multitrådad miljö behöver du en annan lösning. Det finns emellertid fall där du inte kan lita på den vanliga språkens körtid för att säkerställa gängesäkerhet, som i Static Initialization-exemplet. I sådana fall måste du använda specifika språkfunktioner för att se till att endast en instans av objektet skapas i närvaro av flera trådar. En av de vanligaste lösningarna är att använda Double-Check Locking [Lea99] -pråket för att förhindra separata trådar från att skapa nya instanser av singletonet samtidigt.
Följande implementering tillåter endast en enda tråd att komma in i det kritiska området, som låsblocket identifierar, när ingen instans av Singleton ännu inte har skapats:
using System;
public sealed class Singleton {
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance {
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}
Denna strategi säkerställer att endast en instans skapas och endast när instansen behövs. Variablen förklaras också vara flyktig för att säkerställa att tilldelningen till instansvariabeln slutförs innan instansvariabeln kan nås. Slutligen använder denna metod en syncRoot-instans för att låsa på, snarare än att låsa på själva typen, för att undvika dödlås.
Denna låsning med dubbelkontroll löser problem med trådens samtid samtidigt som du undviker ett exklusivt lås i varje samtal till fastighetsmetoden Instance. Det låter dig också fördröja inställning tills objektet först har åtkomst. I praktiken kräver en applikation sällan denna typ av implementering. I de flesta fall är den statiska initieringsmetoden tillräcklig.
Referens: MSDN
Tack
[Gamma95] Gamma, Helm, Johnson och Vlissides. Designmönster: Beståndsdelar av återanvändbar objektorienterad programvara. Addison-Wesley, 1995.
[Lea99] Lea, Doug. Samtidig programmering i Java, andra upplagan. Addison-Wesley, 1999.
[Sells03] Sells, Chris. "Förslutna suger." sellsbrothers.com Nyheter. Finns på: http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 .
Singleton (PHP)
Exempel från phptherightway.com
<?php class Singleton { /** * @var Singleton The reference to *Singleton* instance of this class */ private static $instance; /** * Returns the *Singleton* instance of this class. * * @return Singleton The *Singleton* instance. */ public static function getInstance() { if (null === static::$instance) { static::$instance = new static(); } return static::$instance; } /** * Protected constructor to prevent creating a new instance of the * *Singleton* via the `new` operator from outside of this class. */ protected function __construct() { } /** * Private clone method to prevent cloning of the instance of the * *Singleton* instance. * * @return void */ private function __clone() { } /** * Private unserialize method to prevent unserializing of the *Singleton* * instance. * * @return void */ private function __wakeup() { } } class SingletonChild extends Singleton { } $obj = Singleton::getInstance(); var_dump($obj === Singleton::getInstance()); // bool(true) $anotherObj = SingletonChild::getInstance(); var_dump($anotherObj === Singleton::getInstance()); // bool(false) var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)
Singleton designmönster (i allmänhet)
Obs: Singleton är ett designmönster.
Men det betraktades också som ett antimönster.
Användningen av en singleton bör övervägas noggrant före användning. Det finns vanligtvis bättre alternativ.
Huvudproblemet med en singleton är detsamma som problemet med globala variabler. De introducerar externt globala muterbara tillstånd. Detta innebär att funktioner som använder en singleton inte bara är beroende av ingångsparametrarna utan också singletons tillstånd. Detta innebär att testning kan äventyras allvarligt (svårt).
Problemen med singletons kan mildras genom att använda dem i samband med skapningsmönster; så att den första skapelsen av singleton kan kontrolleras.