在OOP中使用可选的单例

本文关键字:单例 OOP | 更新日期: 2023-09-27 17:50:54

我正在。net中编写PCL,并且我有一个围绕HttpClient的包装器类,该包装器类以多种不同的方法从URI加载HtmlAgilityPack.HtmlDocument。它是无状态,所以我真的想让它静态,因为在我看来,用new实例化的东西给人的印象是它包含状态。但是,我希望它继承几个接口,所以它不能是静态的。这就是我想把它变成单例的地方。下面是一些代码片段:

public class ConcurrentClient : IAsyncClient<HtmlDocument>
{
    private static readonly ConcurrentClient _Instance = new ConcurrentClient();
    private ConcurrentClient() { }
    public static ConcurrentClient Instance
    {
        get { return _Instance; }
    }
    public HtmlDocument LoadUri(string uri)
    {
        return LoadUriAsync(uri).Result;
    }
    // ...
    public async Task<HtmlDocument> LoadUriAsync(string uri, 
        Encoding e, NetworkCredential creds, Action<HtmlDocument> prehandler)
    {
        // ...
    }
}

我在想,如果我应该把开头部分改成这样:

private static readonly ConcurrentClient _SharedInstance = new ConcurrentClient();
public static ConcurrentClient SharedInstance
{
    get { return _SharedInstance; }
}

这样做的原因是我不确定是否使用单例模式,主要是因为我很少看到它在其他库中使用(可能是WinRT的Application.Current ?),我认为它会鼓励我的PCL用户编写耦合代码,因为在任何地方调用ConcurrentClient.Instance比将其作为参数传递要容易得多。

然而,我确实希望鼓励使用共享实例,因为排除上述原因,调用new ConcurrentClient()几乎没有意义,因为它所做的只是创建更多的内存开销。而且,我想不出更好的方法来实现不依赖于状态的方法继承。

在OOP中使用可选的单例

你的Singleton已经实现了2个接口。真正的问题是,这个Singleton的依赖项在哪里,为什么在那里?
如果答案是这些依赖关系的存在是因为它们需要实现那些接口,那么我会说这是错误的。
做SOLID设计的重点是依赖于接口,而不是任何具体的实现。因此,任何需要这两个接口的人都应该通过依赖注入获得这些接口。因此,这意味着接口将通过其构造函数传递,或者通过方法调用中的额外参数,策略模式…

参见:http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx

创建单例可能是有原因的,但根据你的解释,这不是那么清楚。

花更多的时间在使用依赖注入上。如果你已经控制了这一点,再进一步研究如何使用控制反转容器。

而且,当您可以通过Singleton.Instance访问对象时,很容易忘记DI和将对象作为参数传递。

你忘记了单元测试。如果将接口传递给类构造函数,就可以很容易地模拟这些接口并测试类的功能。有了单例,你的类就真的需要这个单例了。单元测试将更加困难。当然Instance很容易访问,它是一个全局的,因为人们总是回到面向对象编程的旧习惯,这就是为什么它如此受欢迎的原因。