静态构造函数——c#中的单例设计模式
本文关键字:单例 设计模式 构造函数 静态 | 更新日期: 2023-09-27 18:04:03
如果我在单例设计模式中用静态构造函数代替私有构造函数会怎样?
public sealed class Singleton
{
private static Singleton instance=null;
private Singleton()
{
}
public static Singleton Instance
{
get
{
if (instance==null)
{
instance = new Singleton();
}
return instance;
}
}
}
静态构造函数将只被调用一次,我在实现中找不到任何区别。我们可以用静态构造函数代替私有构造函数吗?
在这种情况下,私有构造函数真正做的是防止类外部的任何东西实例化Singleton类的实例,这几乎可以肯定是有意为之,因为Singleton应该只有一个实例。
静态类构造函数在类型或其任何静态成员被使用之前,在未知的时间为类型运行一次。静态字段在运行静态构造函数之前初始化。
所以,我认为你可以用一个静态的构造函数来代替这个构造函数,但是这样就会给你Singleton类型上的隐式无参数构造函数,这将允许任何人实例化一个实例,这可能与你最初使用Singleton模式的原因不一致。实际上,它也不会改变类的构造方式,那么为什么要这样做呢?
以以下类为例:
public class Test { }
在底层,因为没有声明的构造函数,c#编译器隐式地为类添加了一个无参数的公共构造函数,允许消费者创建实例。
public class Program {
public static void Main() {
var test = new Test();
}
}
如果您希望能够创建类的实例,那么这一切都很好。单例模式打算只向使用者提供类型的单个实例。我们可以像这样将这个静态实例添加到测试类型中:
public class Test { public static Test Instance {get;} = new Test(); }
,我们可以得到这样的静态实例:
public class Program {
public static void Main() {
var test = Test.Instance; // good
var other = new Test(); // less than ideal
}
}
所以我们通过它的实例字段提供了对单例对象的访问,正如预期的那样,但是我们仍然可以创建单例类型的实例,这就不太好了,因为它违背了单例的目的(即只有一个共享实例)
因此,为该类型添加一个私有的无参数构造函数。
public class Test {
private Test() {}
public static Test Instance {get;} = new Test();
}
向类型添加构造函数将导致c#编译器不添加隐式公共无参数构造函数。将其设为私有允许在类作用域中访问它,该类作用域用于实例化我们的instance属性,并防止其他任何东西实例化该对象。最终结果是:
public class Program {
public static void Main() {
var test = Test.Instance; // good
var other = new Test(); // Compile time error
}
}
你的单例对象现在可以防止该类的其他实例被实例化,使用它的唯一方法是通过instance属性。
简单来说,如果您删除了私有构造函数,那么任何人都可以创建Singleton
的新实例:
// With the private constructor, the compiler will prevent this code from working.
// Without it, the code becomes legal.
var newInstance = new Singleton();
如果有人可以像上面那样实例化Singleton
,那么你就不再有一个单例了。
另一种更干净的方法是在您的私有实例上使用readonly
。
这是更少的代码和线程安全。CLR为你照顾一切,不需要lock
,检查null和东西。
public sealed class Singleton
{
private static readonly Singleton _instance = new Singleton();
public static Singleton Instance {
get {
return _instance;
}
}
private Singleton()
{
}
}
然后简单地测试:
[TestMethod]
public void IsSingleton()
{
Assert.AreSame(Singleton.Instance, Singleton.Instance);
}
编辑:示例使用lock
public sealed class Singleton
{
private static readonly object _lock = new object();
private static Singleton instance = new Singleton();
public static Singleton Instance
{
get
{
lock(_lock)
{
if (instance==null)
{
instance = new Singleton();
}
return instance;
}
}
}
private Singleton()
{
}
}
简单来说,如果删除private
,默认的公共构造函数将暴露。然后外人将被允许使用new Singleton();
并创建一些Singleton类的实例。所以这里没有单例模式。
另外,这个经典的单例模式(private constructor + static getInstance() with either lazy-loading or eager loading)
的实现是如此的邪恶。在现代,你必须改用依赖注入框架。
这应该可以正常工作。您还可以使类静态和泛型,这样您就可以在instance
中存储任何类型的值。这将促进关注点分离,保持单例模式和它将包含的类分离。