65.9K
CodeProject 正在变化。 阅读更多。
Home

如何创建行为可被 Mock 对象覆盖的单例

starIconstarIconstarIconemptyStarIconemptyStarIcon

3.00/5 (1投票)

2010年3月1日

GPL3

1分钟阅读

viewsIcon

31812

downloadIcon

90

如何创建既具有 Singleton 的优点,又支持 Mock 对象和行为改变的类。

引言

我们如何创建一个类,它既具有 Singleton 的优势,又支持 Mock 对象和行为改变?

背景

Singleton 设计模式为开发者提供了一种特性,可以保证在应用程序的整个生命周期内只有一个实例。但是,这种行为并非免费的,并且存在一些问题。最大的问题是 Singleton 类的行为在未来无法改变。此外,无法创建 Mock 对象,因此由于绑定依赖关系,几乎不可能进行单元测试。

使用代码

考虑以下代码

class Singleton 
{  
    private Singleton static instance;
    protected Singleton()
    {
    }
    public static Singleton getInstance()
    { 
        if(instance == null) 
            instance = new Singleton();
        return instance; 
    }

    public void show()
    { 
        System.out.println("Bye..."); 
    }
}

虽然这个类保证了单例实例,但它不允许改变其方法(如 show())的行为。这可能不明显,但由于返回的实例始终是 Singleton 类,因此行为是不可变的!

接下来,我们可以进行一些依赖注入。现在,考虑类 MySingleton

class MySingleton
{    
    private static MySingleton instance;
        
    /**
     * Singleton creator
     */
    private static MySingletonCreator creator;
    
    public static void setCreator(MySingletonCreator creator) 
    {
        MySingleton.creator = creator;
    }    
    
    /**
     * Only subclass can use
     */
    protected MySingleton()
    {        
    }
    
    // This is the behavior which developer wants to change !
    public void show()
    {
        System.out.println("Hello...");
    }
    
    public static MySingleton getInstance()
    {
        if(instance == null)
        {
            if(creator == null)
                instance = new MySingleton();
            else 
                instance = creator.create();
        }
        return instance;
    }
    
    public static interface MySingletonCreator
    {
        public MySingleton create();
    }
}

如你所见,实例的创建是通过调用 creator.create() 方法完成的。

可以在任何实例被要求之前设置 creator,从而允许开发者安装一个 creator,甚至是返回专门的或 Mock Singleton 的 creator!

现在,这里有一个例子

public class SingletonDemo {

    public static void main(String[] args) 
    {
        // Set the creator
        MySingleton.setCreator(new MySingletonCreatorImpl());
        MySingleton ms = MySingleton.getInstance();
        ms.show();
    }

    static class MySingletonCreatorImpl implements MySingletonCreator
    {
        @Override
        public MySingleton create() 
        {
            return new MockSingleton();
        }
        
        class MockSingleton extends MySingleton
        {
            @Override
            public void show() 
            {
                System.out.println("Bye...");
            }
        }
        
    }
}

这里,我们可以看到,我们正在设置 creator,它就是我们的专门 creator,进一步返回一个 Mock Singleton。这个 MockSingleton 具有我们想要的行为。

对这个 Singleton 类进行单元测试非常容易,我们只需要在创建实例之前通过调用 setCreator() 安装我们的 creator。我们可以拥有自己的 MockSingleton,并覆盖任何方法。

关注点

Singleton 是一种福音,但当涉及到单元测试或 Mock 时,它们会使生活变得痛苦。通过这种方式,我们可以对 Singleton 获得一些控制权。

历史

不适用

© . All rights reserved.