不变/无状态单身人士不好吗?


12

最近,有人针对单身人士进行了某种革命,但是如果他们是无国籍的,他们有什么问题吗?

我知道过度使用的话题以及所有...这不仅适用于单例,还适用于所有情况。


1
不。单例在原则上还不错,只是被过度使用了。
Bart van Ingen Schenau 2013年

3
您最近是什么意思?
Manoj R

5
@Joachim Sauer:为什么要更换?如果它是无状态的,则可以直接对其进行测试。
m3th0dman

1
如果您具有无状态单身人士,那么您基本上会拥有一个静态实用程序类,该类倾向于发展为God Class反模式。通常,您可以在使用它们的上下文中使用静态方法来代替(甚至更好:在C#中使用扩展方法)。
Spoike

Answers:


12
  > Are immutable/stateless singletons bad?
  • 没有,如果他们不依赖于其他外部系统。
    • 示例:一个Stringutility,它在字符串内转义html。
    • 原因:在单元测试中,无需将其替换为模拟/模拟器。
  • 是,如果您的不变/无状态单例依赖于其他外部系统/服务,并且您要进行单元测试(在隔离中测试)
    • 示例:依赖于外部Tax-Calculator-Webservice的服务。
    • 原因:为了对此服务(单独)进行单元测试,您需要模拟/模拟外部系统/服务。

有关更多详细信息,请参见洋葱架构


  • Singleton-s可以使单元测试(孤立地)变得更加困难/不可能,并且
  • 如@yBee所述,隐藏的依赖关系/耦合可以看作是一个问题

我看不出不使用Singletons的其他原因。


如果您要测试您的类,即使它不是(无状态)单例,您仍然必须模拟该外部Web服务。
m3th0dman 2013年

@ m3th0dman我同意
k3b

10

它始终取决于用法。我认为革命来自于一个事实,即每一个程序员学习这种模式为面向对象模式。大多数人忘记考虑在哪里有意义,在哪里没有意义。
当然,每种模式都适用。仅仅通过使用模式,就不能创建好的代码或好的软件。

如果您有无状态单身人士,为什么不使用仅提供静态方法的类(或使用静态类)?

这里有一些关于全局变量和单例的文章。

我不会像作者那样严格,但是他表明,在大多数情况下,您认为需要单身人士,实际上并不需要。


1
为什么不将类与静态方法一起使用?例如继承...
m3th0dman

3
@ m3th0dman:听起来不是继承的好地方。
Billy ONeal 2013年

@BillyONeal如果您知道领域模型,那么可以说继承的好坏,以这种方式进行建模……
m3th0dman 2013年

2
@ m3th0dman:嗯,不。在不了解任何域模型的情况下,我可以很积极。继承是针对多态行为的。但是作为一个单例,您将不会有多态行为。
Billy ONeal

1
@ m3th0dman:因为要获取单例对象,需要在调用站点上指定单例的名称。这意味着您没有使用多态行为。这意味着组合比继承要灵活得多。
Billy ONeal 2013年

7

一个不变的无状态单例不能做静态类不能做的事情。

根本没有理由增加-> Instance()创建的额外复杂性,而对静态方法的普通调用将更加清晰,在资源方面更为保守并且可能更快。

不是说他们错了。这是一种更好的方法。在某些情况下,正常(“有状态”)单例是正确的方法。单例的弊端是它们经常被滥用,其结果与全局变量相同,但在某些特定情况下,使用单例是正确的。对于无国籍者,没有这样的情况。


我敢打赌,您可以构造一些单例具有某些优点的情况。可能取决于场景和编程语言(例如,利用延迟加载)。
StampedeXV

1
@StampedeXV:是的,肯定是有状态的单身人士。一个无状态且不可改变的例子-我真的很想听到任何例子,但我没有屏息。
SF。

好的,你有意思。我在那儿概括了您的答案。对于不变的无状态,我也看不到任何优势。
StampedeXV

1
对于仅具有静态函数的类,您不能使用继承/多态性,这是一个很大的限制...
m3th0dman 2013年

1
一个不变的无状态单例不能做静态类不能做的事情。好吧,静态方法不能实现单例可以实现的接口
Michal M

3

单例的主要问题在于,当在跨领域关注方案中使用时,它会隐藏依赖关系并特别是耦合。有关更多信息,请参阅“ 单身人士是病态的骗子”或“ 为什么单身人士是邪恶的 ”。

另一方面,如果不滥用状态,减少单身状态可能会有所帮助并提高性能。考虑一个例子:

interface Interface
{
    void Method();
}

class StatelessSingleton : Interface
{
    public static readonly StatelessSingleton Instance = new StatelessSingleton();
    private StatelessSingleton() { }

    public void Method() { }
}

class User
{
    public User(Interface i) { /* ... */ }
}

在此,StatelessSingleton充当接口的默认实现,并放入User构造函数中。没有硬编码的耦合和隐藏依赖性。由于底层接口,我们无法使用静态类,但是没有理由创建多个默认实例。这就是为什么无状态单身似乎是一个适当的选择的原因。

但是,也许我们应该对默认实现使用另一种模式:

class Implementation : Interface
{
    private readonly Action _method;

    public Implementation()
    {
        _method = new Action(() => { /* default */ });
    }

    public Implementation(Action custom)
    {
        _method = custom;
    }

    public void Method()
    {
        _method();
    }
}

它达到了StatelessSingleton的性能,但构成了接口的通用实现。IProgress接口使用类似的解决方案。

再一次,为什么允许创建多个默认行为实现?但是我们可以将两者结合起来:

class Implementation : Interface
{
    public readonly Implementation Default = new Implementation();

    private readonly Action _method;

    private Implementation()
    {
        _method = new Action(() => { /* default */ });
    }

    public Implementation(Action custom)
    {
        _method = custom;
    }

    public void Method()
    {
        _method();
    }
}

总之,我相信在某些地方(如所描述的默认设置),单例有用。Singleton的主要定义指出,不允许创建一个类的多个实例。这是核能。可以产生能量或炸弹。这取决于人类。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.