Peter Bucher - Mein Experiment, meine Spielereien, meine Welt...   ·   Stefan Falz   ·   Jürgen Gutsch   ·   Golo Roden   ·   ASP.NET Zone   ·   Microsoft ASP.NET
Willkommen bei ASP.NET Zone. Anmelden | Registrieren | Hilfe

Singleton Pattern

Auf gehts, das nächste Pattern nach Strategy.

Heute geht es darum, sicherzustellen, das von einer Klasse nur eine Instanz erstellt werden kann, dies ist bspw. bei einer Logging Klasse, einem Desktop Programm oä. nützlich.
Im Grunde verhindert dieses Pattern das Erstellen von Instanzen durch den Konstruktor.

Der ganze Trick besteht darin, den Konstruktor private zu setzen, sodass dieser nur intern verwendet werden kann.
Zudem braucht es einen statischen Member in der Klasse, der die einzigartige Instanz hält.

Um an trotzdem von Aussen an eine Instanz zu kommen, spendieren wird der Klasse eine öffentliche Methode bspw. Namens "getInstanz", in dieser wird - wen noch nicht vorhanden - ein Objekt erstellt, und zurückgegeben.
Eine Klasse die das Singleton Pattern anwendet, ist nicht "nur" ein Singleton, sondern enthält (sinnvollerweise) immer auch noch weitere Daten und Methoden (Wie am zweiten Beispiel zu sehen ist).

(Die Beispiele lehnen sich an Java an, in C# wirds auch mit einer Eigenschaft + get gehen)

Minimales Beispiel:

using System;
using System.Collections.Generic;
using System.Text;


namespace SingletonExample
{
    class Program
    {
        static void Main(string[] args)
        {
            Logger l = Logger.getInstance();
            Console.WriteLine(l == null);
            Console.Read();
        }
    }

    public class Logger {
        private static Logger instance;

        private Logger() {
           
        }

        public static Logger getInstance() {
            if (instance == null)
                instance = new Logger();

            return instance;
        }
    }
}

Ein "erweitertes" Beispiel mit mehr Sinn:

using System;
using System.Collections.Generic;
using System.Text;


namespace SingletonExample
{
    public class App
    {
        private Logger _logger;

        public void Run() {
            this._logger = Logger.getInstance();
            this._logger.Add("Programm Fehler");

            this._logger = Logger.getInstance();

            foreach (string error in this._logger.Errors) {
                Console.WriteLine(error);
            }
            Console.Read();
        }
    }

    public class Logger
    {
        private List<string>  _errors = new List<string>();
        private static Logger  instance;

        public List<string> Errors {
            get { return this._errors; }
            set { this._errors = value; }
        }

        private Logger() { }

        public static Logger getInstance() {
            if (instance == null) {
                instance = new Logger();
            }
            return instance;
        }

        public void Add(string error) {
            this._errors.Add(error);
        }
    }
}

Definition des Singleton Patterns:

Das Singleton-Muster sichert, dass es nur eine Instanz einer Klasse gibt, und bietet einen globalen Zugriffspunkt für diese Instanz.

Und am Schluss das kleine aber feine Klassendiagramm:

Veröffentlicht Donnerstag, 27. März 2008 18:15 von Peter Bucher
Abgelegt unter: , ,

Kommentare

# re: Singleton Pattern

Nicht thread-sicher.

Ich guck morgen mal in meinem Code, da habe ich Singleton-Pattern die thread-sicher sind. (Habe ich auch im Internet gefunden)

Donnerstag, 27. März 2008 20:23 by Uwe Keim

# re: Singleton Pattern

public sealed class Logger

{

   /// <summary>

   /// Access the current instance of the class.

   /// </summary>

   /// <value>The current.</value>

   public static Logger Current

   {

       get

       {

           if ( _current == null )

           {

               // According to  

               // http://www.dofactory.com/Patterns/PatternSingleton.aspx,

               // it is sufficient to lock only the creation.

               //

               // Quote:

               //        Support multithreaded applications through

               //        'Double checked locking' pattern which (once

               //        the instance exists) avoids locking each

               //        time the method is invoked                    

               //

               // http://geekswithblogs.net/akraus1/articles/90803.aspx

               // has the correct way of locking: declaring as "volatile".

               //

               // http://www.ibm.com/developerworks/java/library/j-dcl.html

               // has an in-deep discussion.

               lock ( _typeLock )

               {

                   if ( _current == null )

                   {

                       _current = new LogCentral();

                       _current.ConfigureLogging();

                   }

               }

           }

           return _current;

       }

   }

   private static readonly object _typeLock = new object();

   private static volatile Logger _current = null;

   // ... Actual methods follow here ... //

}

Freitag, 28. März 2008 05:28 by Uwe Keim

# re: Singleton Pattern

Hallo Uwe,

prinzipiell hast Du zwar recht, dass Peters Variante nicht thread-safe ist, die von Dir vorgeschlagene Lösung mit Hilfe des Double-Checked-Locking-Idioms ist dies aber (je nach Plattform) erstens auch nicht, und zweitens mega-umständlich.

Warum, wieso, weshalb und wie man es besser machen kann: Siehe http://www.yoda.arachsys.com/csharp/singleton.html

Viele Grüße,

Golo

Freitag, 28. März 2008 08:28 by Golo Roden

# re: Singleton Pattern

Salute zusammen

Mir ging es nicht darum, ein thread saved Beispiel zu zeigen, sondern ein höchst minimales :-)

Vielen Dank für eure Ergänzungen.

@Golo

Genau diese Seite hab ich mir auch durchgelesen :-)

Freitag, 28. März 2008 08:40 by Peter Bucher

# re: Singleton Pattern

Der Hyperlink von Golo zeigt doch auf genau so ein Beispiel wie von mir. So what?!?

Freitag, 28. März 2008 15:28 by Uwe Keim

# re: Singleton Pattern

Hallo Uwe

Öhm, ja klar.

Aber:

1. Geht es mir hier nicht in erster Linie um ein Thread sicheres Beispiel (s.o.)

2. Steht im Link von Golo zu deiner Variante "// Bad code! Do not use!" ;-)

So, that.

Freitag, 28. März 2008 16:17 by Peter Bucher

# Generic Singleton

Wenn ich Projekte habe wo ich den Singleton Pattern einsetze, nutze ich generell Generics. Damit kann ich den Pattern beliebig auf jede Klasse anwenden. Bin mir net sicher, aber dürfte ja kein verstoss gegen das Singleton Pattern sein oder?

Hier ein (einfaches) Beispiel:

namespace SingletonPattern

{

   public static class cSingleton<T> where T : new()

   {

       private static T instance;

       public static T getInstance()

       {

           if (instance == null)

           {

               instance = new T();

           }

           return instance;

       }

   }

}

und der Aufruf wäre dann z.B.

       public Form1()

       {

           InitializeComponent();

           cTestclass clsTestclass = cSingleton<cTestclass>.getInstance();

       }

Samstag, 12. April 2008 20:23 by roeb

# Facade Pattern und ein Anwendungsbeispiel: SessionFacade

Vor einiger Zeit habe ich über das Strategy-Pattern und Singleton-Pattern geschrieben, dort sind auch

Samstag, 13. Dezember 2008 00:40 by Peter Bucher
Anonyme Kommentare sind nicht zugelassen