「单例都去哪儿了?」阐述了依赖注入已经让获取实例变得容易,在构造函数中需要实例时,它可以减轻第一篇文章中抨击的糟糕全局单例背后的基本需求。单例只不过是全局状态,全局状态意味着你的对象可以秘密地获取其 API 中未声明的内容,因此,单例会让你的 API 变成病态说谎者。
我认为混淆的原因在于人们不知道单例模式的真正应用。我再强调一遍,单例不是用于包装全局变量的模式。单例模式只应用于确保在运行时期间仅存在一个给定类的实例。
人们认为单例是邪恶的,是因为他们在将其用作全局变量。正是由于这种混淆,才导致单例模式被轻视。请不要混淆单例和全局变量。如果按照它所设计的目的去使用,你会从单例模式中获得极大的好处。
setInstance
方法。)不过这几乎无关紧要——那些“需要”单例的蒟蒻们对封装一窍不通,也不知道可变全局状态有何问题,所以他为每个字段都提供了设置器(是的,这种情况经常发生。几乎我见过的所有单例都是设计上可变的,而且通常令人尴尬)。 - cHaogetInstance
或类似的方法公开它,并防止存在第二个实例。实际上,在那个时候,你甚至可以完全没有这个一个实例。 - cHao单例模式的一个比较不好的地方是很难进行扩展。如果想改变它们的行为,基本上必须内置某种装饰器模式或类似的东西。此外,如果有一天你想以多种方式完成某个任务,根据代码布局的方式,更改可能会相当痛苦。
需要注意的一点是,如果确实使用了单例模式,请尽量将它们传递给需要它们的人,而不是直接访问它们...否则,如果您决定以多种方式完成单例模式执行的任务,每个类都嵌入了对该单例的依赖关系,则更改将非常困难。
因此,简而言之:
public MyConstructor(Singleton singleton) {
this.singleton = singleton;
}
与其说是:
public MyConstructor() {
this.singleton = Singleton.getInstance();
}
我相信这种模式被称为依赖注入,通常被认为是一件好事。
但是,就像任何模式一样...需要仔细思考并考虑在给定情况下是否不适当地使用它...通常规则都是可以打破的,而模式也不应该毫无考虑地随意应用。
getInstance()
,那么(b)就不再完全成立。 - cHaogetInstance()
,你实际上就丢掉了单例模式和普通引用之间唯一有用的区别。就代码的其余部分而言,单例已不再是一个属性。只有调用者需要知道或关心是否存在多个实例。对于只有一个调用者的情况,类可靠地强制执行单例模式的成本比让调用者存储一个引用并重用它更加费力和缺乏灵活性。 - cHao单例模式通过静态方法实现。但是由于静态方法无法被模拟或存根,因此进行单元测试时,人们通常会避免使用它们。在本网站上,大多数人都是单元测试的支持者。通常最广泛接受的避免使用静态方法的约定是使用控制反转模式。
public class SingletonDao {
// songleton's static variable and getInstance() method etc. omitted
public void writeXYZ(...){
synchronized(...){
// some database writing operations...
}
}
}