overview
单例类是一种设计模式,在任何给定时间,程序中只能存在一个类的实例。这意味着每次从该类创建对象时,它都会返回相同的实例。当我们想要确保应用程序中只有一个类的实例时,通常使用单例类,例如应该在整个程序中使用的配置类。
另一方面,依赖注入是一种设计模式,其中对象的依赖项由外部实体注入到对象中,而不是对象自己创建它们。换句话说,对象不是创建自己的依赖项,而是提供来自外部的依赖项。这使得对象更具模块化和可测试性,因为它可以很容易地替换为模拟对象以进行测试。
依赖注入通常用于代码复杂性较高的大型应用程序中,并且需要减少应用程序不同部分之间的耦合。它还允许在应用程序的设计中具有更大的灵活性,使其更容易修改和扩展。
总之,单例类和依赖注入的主要区别在于单例确保一个类在程序中只存在一个实例,而依赖注入是一种从外部向对象提供其依赖的方法。它们可以一起使用,但是它们在软件设计中服务于不同的目的。
What is a singleton class?
单例类是一种设计模式,其中在任何给定时间,程序中只能存在一个类的实例。这意味着每次从该类创建对象时,它都会返回相同的实例。
下面是Java中一个单例类的例子:
1 | public class SingletonClass { |
在这个例子中,我们定义了一个名为SingletonClass
的类,它带有一个私有的静态类变量instance
来存储该类的实例。构造函数方法被设置为私有,以防止类从外部实例化。getInstance
方法用于获取类的实例,如果它还不存在,则创建一个实例。sayHello
方法只是一个简单的方法,用于演示该类的用法。
要使用Singleton
类,我们可以调用getInstance
方法来获取该类的实例,然后使用它来调用sayHello
方法,如下所示:
1 | SingletonClass instance1 = SingletonClass.getInstance(); |
在这个例子中,我们使用getInstance
方法创建了SingletonClass
的两个实例,但是我们只得到一个实例,因为这个类是Singleton
。在两个实例上调用sayHello
方法来演示该类的使用。
What is a dependency injected class?
依赖注入类是从外部注入依赖的类,而不是在内部创建依赖。换句话说,依赖关系是从外部传递给类的,而不是由类本身创建的。这允许在软件设计中有更大的灵活性和模块化,以及更容易的测试。
依赖注入是一种设计模式,在这种模式中,类的依赖关系通过其构造函数、方法或设置器传递给它,而不是在类本身内部创建。这有助于将类与其依赖项解耦,并使替换或修改依赖项变得更容易,而不会影响类的行为。
在依赖注入类中,依赖项通常被定义为接口或抽象类
,这允许多个实现可以互换使用。这就是所谓的控制反转(IoC),其中程序流的控制从类本身转移到管理依赖关系的外部实体。
例如,考虑一个依赖于类Service
的类Client
。不是在Client
类中创建Service
类的实例,而是将Service
实例传递给Client
构造函数,如下所示:
1 | public class Client { |
在这个例子中,我们定义了一个名为Client
的类,它依赖于另一个名为Service
的类。这里没有定义Service
类,但假定它存在。依赖项是通过Client
类的构造函数注入的。Client
类的doSomething
方法调用Service
类的一个方法来演示依赖项的使用。
要使用Client
类,我们需要创建Service
类的一个实例,并将其传递给Client
类的构造函数,如下所示:
1 | Service service = new Service(); |
在本例中,我们创建了Service
类的一个实例,并将其传递给Client
类的构造函数。调用Client
类的doSomething
方法来演示依赖项的使用。
依赖注入允许在软件设计中具有更大的灵活性,因为依赖项可以很容易地替换为用于测试目的的模拟对象,并且代码不那么紧密耦合。这使得随着时间的推移修改和扩展软件变得更加容易。
In conclusion
许多人会认为或者选择给出单例和依赖注入相似的例子,甚至用单例类作为例子来解释依赖注入也是一样的。然而,我们可以看到它们是两种完全不同的模式。
的确,每个对象只有一个类型对象,但相似之处就到此为止了。
当我们需要确保在整个应用程序的生命周期中只创建一个类的实例,并且它很容易被应用程序的其他部分访问时,使用单例模式。下面是一些单例模式可能有用的场景:
- 配置设置:
Singleton
类可用于存储需要从应用程序的不同部分频繁访问的应用程序配置设置。 - 数据库连接:
Singleton
类可用于管理到数据库的单个连接,该连接可在应用程序的不同部分之间共享。 - 日志记录:
Singleton
类可以用来管理应用程序的日志记录,可以从应用程序的不同部分访问。 - 缓存:
Singleton
可用于管理频繁访问数据的缓存,这些数据可在应用程序的不同部分之间共享。 - 线程池:
Singleton
可以用来管理线程池,这些线程可以在应用程序的不同部分重用。
一般来说,单例模式在我们需要确保特定类只有一个实例并且可以被应用程序的其他部分轻松访问的情况下是有用的。但是,应该谨慎地使用它,因为过度使用Singleton
模式会导致复杂和不灵活的设计。
然而,看看上面的列表——依赖注入类也可以符合上述所有要点。因此,在一个大型的复杂系统中,可以说依赖注入模式应该用于现代系统,而单例模式在今天的系统中并不真正需要。
在单例之上使用依赖注入的另一个好处是,你可以改变被注入的类。我的意思是,也许您从喜欢的logger
类开始。你可以从中得到你需要的大部分东西。但是,您会发现一个新的、更好的logger
类,它可以提供更多的输出。您可以注入这个新类,而无需更改太多代码。在您需要更改任何代码的地方,它是非常小的。
这意味着当您进行这些类型的更改时,需要做的工作更少,特别是在大型代码库上。
参考
What Is The Difference Between A Singleton Class And Dependency Injection