我可以用这种方式为所有派生的单身人士定义一个抽象类吗?
这是我的抽象类,每次我想创建一个Singleton时都必须派生它:
public abstract class Singleton where T : Singleton { private static readonly Lazy _instance = new Lazy(() => { var constructor = typeof(T).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[0], null); return (T)constructor.Invoke(null); }); public static T Instance { get { return _instance.Value; } } public Singleton() { } }
所以,每次我需要遵循Singleton设计模式时,我可以这样做:
sealed class Server : Singleton { private Server() { } ... }
这是完全正确的,如果没有,为什么?
编辑:
- 在派生类示例上添加了私有构造函数并在抽象基础上调用。
编辑:
- 重写类型参数初始化。
自我实现的单身人士是一种反模式。 如果你只是实现一个工厂,那么inheritance并将你的类锁定为特定forms的需要就会消失:
public class Server {} //Not coupled to any inheritance hierarchy. public class Factory { private readonly Lazy _server = new Lazy (() => new Server()); public Server Server { get { return _server.Value; } } }
但是,您实际上将工厂用作服务定位器,并且服务定位器也被视为反模式,因为您可以轻松地使用DI将Server实例注入到消费类中。
public class MyServerConsumer { public MyServerConsumer(Server server) { //Do stuff. } }
温莎风格注册:
... Component.For(); ...
注意单词singleton从未被提及过? 您仍然可以获得“对象的单个实例”,但您不必编写代码来维护该关系,并且您的类从一开始就不受“单例”概念的约束和破坏
不,你不能,因为当你想要使用new T()
你应该有一个公共构造函数,它与单例定义不同。 因为在单例中你应该有一个私有构造函数,在这种情况下(公共一个),每个人都可以创建对象的新实例,而不是单例。
您正在使用的这种方法具有明显的缺点。 您将您的课程结合到Singleton课程。 除了通常不是SOLID之外,您将失去从您可能需要的类派生的能力(如果该类不是Singleton)。
最佳实践是您需要使用dependency injection和IoC容器。 所有IoC容器都允许您指定类是否为Singleton的天气。
这样,类完全无视它被实例化为Singleton的事实,并且很容易在不改变依赖性的情况下即时更改它。
C#不保证何时创建静态字段_instance
。 这是因为C#标准只是声明类(在IL中标记为BeforeFieldInit)可以在访问字段之前的任何时间初始化其静态字段。 这意味着它们可能在第一次使用时被初始化,它们可能在之前的某个时间初始化,您无法确定何时。
删除懒惰用法
我建议删除Lazy
构造并引入静态ctor来创建实例。 这样你就可以利用C#标准的BeforeFieldInit
,但是你会失去懒惰。 虽然它在某种程度上是懒惰的,但它不是在使用类型之前创建的。 这很好,因为无论如何都会使用大多数单身人士。
public abstract class Singleton where T : class, new() { private static readonly T _instance; public static T Instance { get { return _instance; } } public static Singleton() { _instance = new T(); } }
公共问题
你现在遇到的问题是new T()
构造迫使你有一个公共ctor。 这对单身人士来说并不是很好。 您可以使用通过reflection调用的私有ctor来解决此问题。
这只是对pjvds回复的评论(我无法以常规方式发表评论,因为我没有足够的分数……)。
您可以使用私有init方法,而不是通过reflection使用私有构造函数,并在静态Singlton方法中的“new T()”之后调用它。