为什么单例模式中需要用到 sealed?

使用单例设计模式,需要确保在任何给定的时间点对于整个应用程序只有一个特定类的实例可用。使用私有构造函数,可以避免类在外部被实例化,但是却无法避免由于内部类(嵌套类)的继承导致多个实例被创建,如下:

public class GuidService
{
    private static int counter = 0;
    private static GuidService? _guidService = null;
    public static GuidService GetGuidService
    {
        get
        {
            if (_guidService == null)
                _guidService = new GuidService();
            return _guidService;
        }
    }

    private GuidService()
    {
        counter++;
        Console.WriteLine("Counter Value " + counter.ToString());
    }
    public void PrintDetails(string message)
    {
        Console.WriteLine(message);
    }
}

GuidService里边定义私有构造函数,此时如果外部类继承GuidService就会报错,“GuidService.GuidService()”不可访问,因为它具有一定的保护级别,但是却可以定义内部类继承GuidService,如下:

public class GuidService
{
    private static int counter = 0;
    private static GuidService? _guidService = null;
    public static GuidService GetGuidService
    {
        get
        {
            if (_guidService == null)
                _guidService = new GuidService();
            return _guidService;
        }
    }

    private GuidService()
    {
        counter++;
        Console.WriteLine("Counter Value " + counter.ToString());
    }
    public void PrintDetails(string message)
    {
        Console.WriteLine(message);
    }
    public class SubGuidService : GuidService
    {

    }
}

调用:

using DesignDemo;

GuidService guidService1 = GuidService.GetGuidService;
guidService1.PrintDetails("guidService1");
GuidService guidService2 = GuidService.GetGuidService;
guidService2.PrintDetails("guidService2");

GuidService.SubGuidService subGuidService = new GuidService.SubGuidService();
subGuidService.PrintDetails("subGuidService");
Console.ReadKey();

输出:

Counter Value 1
guidService1
guidService2
Counter Value 2
subGuidService

输出结果清楚地显示计数器值已经增加到2,这证明私有构造函数执行了两次,创建了单例类的多个实例。因此,通过删除密封关键字,我们可以继承单例类,也可以创建单例类的多个对象。这违反了单例设计原则。所以,将GuidService类用sealed修饰,如下:

public sealed class GuidService{
    
}

这时,内部类继承GuidService就会报错,“GuidService.SubGuidService”: 无法从密封类型“GuidService”派生。因此,从这一点出发,得出结论,c#中的私有构造函数只能帮助我们防止类的任何外部实例化,而密封关键字将防止类继承。
另外,上面的实现方式是非线程安全的。GuidService类允许两个不同的线程同时进行测试 if(instance = = null) 并且发现它为true,它们都创建了实例,这依旧违反了单例设计模式原则。

posted @ 2023-01-18 22:14  初晨~  阅读(29)  评论(0编辑  收藏  举报