空对象 - 实例化或单例的东西?

时间:2012-10-23 14:56:39

标签: java null singleton

这更像是一个风格问题,而不是“我遇到问题”。对于Null占位符对象(我使用正确的术语吗?),通常首选使用Singleton模式吗?为便于讨论,这是一个例子:

public interface Foo {
    void myMethod();
}

public class RealFoo implements Foo {
    void myMethod() { /* Do something productive */ }
}

public class MyUniverse {
    public static void main(String args[]) {
        Foo[] fooArray = new Foo[10];
        // do something productive that might result in Null objects in the array
        for (Foo f : fooArray) {
            f.myMethod(); // I DONT WANT TO DO if (f != null) blah blah
        }
    }
}

好的,这就是我的情景,是否更喜欢做A或B?

// A
public class NullFoo implements Foo {
    public NullFoo() {}       
    public void myMethod() { /* don't need to do anything */ }
}

// B
public class NullFoo implements Foo {
    private static NullFoo _instance = null;
    protected NullFoo() {}
    public static NullFoo getInstance() {
        if (_instance == null) _instance = new NullFoo();
        return _instance;
    }
    public void myMethod() {  /* don't need to do anything */ }
}

谢谢!我本能地认为B几乎总是优越但也许我错过了什么,所以我问......

5 个答案:

答案 0 :(得分:3)

我会选择后者。在这方面,我可能会有一种趋势,但我并不认为单身人士本身就是邪恶的。如果一个类没有可变状态,那么单例就可以了。

我会将构造函数设为私有,但不受保护。此外,你的懒惰负载容易出现竞争;我只是在声明行(private static final Foo instance = new NullFoo();)上实例化NullFoo。最后,不要忘记让类实际实现接口。 :)

答案 1 :(得分:1)

从虚拟机的角度来看,B解决方案会更好,因为java最多会实例化一个对象。

答案 2 :(得分:0)

好吧,有趣。不能说我曾经面对这个但是...

我建议是否要一致地使用实例(即它总是会做同样的事情)然后再用B.那样,你只有一个代表你的null对象的共享实例。这是一个节省空间的优化(而不是用NullFoos混乱你的记忆。与Collections#emptyList大致相同。

我必须说,就dsign而言,我不明白你为什么 //做一些有效的事情,可能会导致数组中的Null对象,这会占用{{1在Foo中,然后将其替换为null。我确定你有理由。

答案 3 :(得分:-1)

我将单例实现为枚举。

enum NullFoo implements Foo{
  INSTANCE{
    // implement methods here
  }
}

请参阅:Singleton > The Enum Way或阅读
第3项: 使用私有强制执行单例属性 构造函数或枚举类型
Effective Java 2nd Ed by Joshua Bloch

答案 4 :(得分:-1)

我认为你不应该在这里使用接口。接口描述了一组操作,实现它的类需要支持。但是你正在使用NullFoo类来基本规避这个要求。

那么为什么不使用一个在myMethod实现中什么都不做的基类:

public class BaseFoo
{
    public void myMethod()
    {
        // do nothing
    }
}

public class DerivedFoo extends BaseFoo
{
    public void myMethod()
    {
        // do actual work
    }
}

或者,如果您的实际情况确实需要接口,那么请继续编写if (foo != null) ...测试。