静态类和单例模式之间存在什么实际的区别?
两者都可以在没有实例化的情况下调用,两者都只提供一个“实例”,而且都不是线程安全的。还有其他区别吗?
静态类和单例模式之间存在什么实际的区别?
两者都可以在没有实例化的情况下调用,两者都只提供一个“实例”,而且都不是线程安全的。还有其他区别吗?
当前回答
我将努力超越WTMI和WTL;DR响应。
单身者是一个物体的实例。。。句点
你的问题基本上是问类和该类的实例之间的区别。我认为这很清楚,不需要详细说明。
singleton的类通常采取步骤来确保构建一个实例;这很聪明,但不是必须的。
示例:var connection=connection.Instance;
假设这是Connection类:
public sealed class Connection
{
static readonly Connection _instance = new Connection();
private Connection()
{
}
public static Connection Instance
{
get
{
return _instance;
}
}
}
请注意,您可以在该类上抛出一个接口并模拟它以进行测试,这是静态类无法轻易做到的。
其他回答
我不是一个伟大的OO理论家,但据我所知,我认为与Singleton相比,静态类唯一缺少的OO特性是多态性。但如果您不需要它,那么使用静态类,您当然可以继承(不确定接口实现)以及数据和函数封装。
Morendil的评论,“静态类中体现的设计风格纯粹是程序性的”我可能是错的,但我不同意。在静态方法中,您可以访问静态成员,这与单例方法访问其单个实例成员完全相同。
编辑:我现在实际上在想,另一个区别是,静态类在程序开始时被实例化,并且在整个程序的生命周期中都存在,而单例在某个时刻被显式实例化,也可以被销毁。
*或者它可能在第一次使用时被实例化,这取决于语言,我认为。
当我想要具有完整功能的类时,例如,有很多方法和变量,我使用单例;
如果我希望类中只有一个或两个方法,例如MailService类,它只有一个方法SendMail(),我使用静态类和方法。
从测试角度来看,Singleton是更好的方法。与静态类不同,singleton可以实现接口,您可以使用mock实例并注入它们。
在下面的示例中,我将对此进行说明。假设您有一个使用getPrice()方法的方法isGoodPrice(。
提供getPrice功能的singleton:
public class SupportedVersionSingelton {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
// calculate price logic here
return 0;
}
}
getPrice的使用:
public class Advisor {
public boolean isGoodDeal(){
boolean isGoodDeal = false;
ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
int price = supportedVersion.getPrice();
// logic to determine if price is a good deal.
if(price < 5){
isGoodDeal = true;
}
return isGoodDeal;
}
}
In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
Make your singleton implement an interface and inject it.
public interface ICalculator {
int getPrice();
}
最终Singleton实施:
public class SupportedVersionSingelton implements ICalculator {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){
if(instance == null){
instance = new SupportedVersionSingelton();
}
return instance;
}
@Override
public int getPrice() {
return 0;
}
// for testing purpose
public static void setInstance(ICalculator mockObject){
if(instance != null ){
instance = mockObject;
}
测试等级:
public class TestCalculation {
class SupportedVersionDouble implements ICalculator{
@Override
public int getPrice() {
return 1;
}
}
@Before
public void setUp() throws Exception {
ICalculator supportedVersionDouble = new SupportedVersionDouble();
SupportedVersionSingelton.setInstance(supportedVersionDouble);
}
@Test
public void test() {
Advisor advidor = new Advisor();
boolean isGoodDeal = advidor.isGoodDeal();
Assert.assertEquals(isGoodDeal, true);
}
}
如果我们选择使用静态方法来实现getPrice(),那么很难模拟getPrice)。您可以使用power mock模拟静态,但并非所有产品都可以使用它。
单个静态类实例(即一个类的单个实例,它恰好是一个静态或全局变量)与指向堆上该类实例的单个静态指针之间存在巨大差异:
当应用程序退出时,将调用静态类实例的析构函数。这意味着如果您将该静态实例用作单例,则单例将停止正常工作。如果仍有代码在运行,例如在不同的线程中使用该单例,则该代码可能会崩溃。
是什么让你说单例或静态方法都不是线程安全的?通常,这两者都应该实现为线程安全的。
单例和一堆静态方法之间的最大区别是,单例可以实现接口(或从有用的基类派生,尽管在我的经验中这不太常见),因此您可以将单例作为“另一个”实现来传递。