Change log
Home
Singleton pattern
Links
|
Waarom deze versie niet
Hier wordt een object teruggeven vanuit zijn class-definitie, dit houdt o.a. in
dat er meer beschikbaar is dan wenselijk kan zijn. Als je de interface teruggeeft
is dit beter te beheersen. Zo weet je bijvoorbeeld zeker dat er geen constructor
beschikbaar is voor derden, op deze manier wordt oneigenlijk gebruik behoorlijk
effectief tegengehouden.
Bij het instantieƫren van een Singleton wil je er in de Factory ook zeker van zijn
dat dit echt een Singleton is. Dit is voor een subclass vrij eenvoudig vast te stellen, voor
een interface is dat wat lastiger.
Verder zijn de afgeleide interfaces en classes een stuk doorzichtiger als een interface
wordt gebruikt als basis, met als extra voordeel dat reeds bestaande class-definities
op een eenvoudige manier een Singleton interface kunnen gaan implementeren, als
dat nodig is.
Een thread-safe singleton baseclass in C# met SingletonFactory.
(versie 1)
using System;
using System.Reflection;
using System.Collections;
using System.Threading;
namespace DesignPatterns
{
public class SingletonException : Exception
{
public SingletonException(string message): base(message){}
}
public class SingletonFactory
{
static private Hashtable singletonTable = new Hashtable();
public class Singleton
{
}
static protected Singleton Instance(Type SingletonType)
{
Object _singleton = null;
string WarningMessage = ": class must have Singleton as a baseclass";
if (!SingletonType.IsSubclassOf(typeof(Singleton)))
throw new SingletonException(SingletonType.ToString() + WarningMessage);
Mutex mutex = new Mutex();
mutex.WaitOne();
_singleton = singletonTable[SingletonType];
if (_singleton == null)
{
_singleton = Activator.CreateInstance(SingletonType);
singletonTable.Add(SingletonType, _singleton);
}
mutex.Close();
return _singleton as Singleton;
}
}
}
Een SingletonFactory implementatie.
using System;
namespace DesignPatterns
{
public interface derivedSingleton
{
string name { get; set; }
}
public interface SingletonA : derivedSingleton
{
}
public interface SingletonB : derivedSingleton
{
}
internal class derivedSingletonClass : SingletonFactory.Singleton, derivedSingleton
{
private string _name;
public string name { get {return _name;} set {_name = value;}}
}
internal class SingletonAClass : derivedSingletonClass, SingletonA
{
}
internal class SingletonBClass : derivedSingletonClass, SingletonB
{
}
public class MySingletonFactory : SingletonFactory
{
public MySingletonFactory()
{
}
static public SingletonA singletonA()
{
return Instance(typeof(SingletonAClass)) as SingletonA;
}
static public SingletonB singletonB()
{
return Instance(typeof(SingletonBClass)) as SingletonB;
}
}
}
En een Form om de code in werking te zien.
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using DesignPatterns;
namespace SingletonTest
{
public class SingletonForm : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
public SingletonForm()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(42, 32);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(104, 23);
this.button1.TabIndex = 0;
this.button1.Text = "Show singletons";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// SingletonForm
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(192, 101);
this.Controls.Add(this.button1);
this.Name = "SingletonForm";
this.Text = "Singleton test";
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new SingletonForm());
}
private void button1_Click(object sender, System.EventArgs e)
{
string ShowString = "";
SingletonA TestSingletonA = MySingletonFactory.singletonA();
SingletonB TestSingletonB1 = MySingletonFactory.singletonB();
SingletonB TestSingletonB2 = MySingletonFactory.singletonB();
TestSingletonB2.name = "B2";
TestSingletonB1.name = "B1";
TestSingletonA.name = "A";
ShowString = "value of name in A/B1/B2 : "
+ TestSingletonA.name + "/"
+ TestSingletonB1.name + "/"
+ TestSingletonB2.name;
MessageBox.Show(this, ShowString, "Sample", MessageBoxButtons.OK);
}
}
}
|