Java中等价于Ruby的singleton的是什么?

3
在Ruby中,我可以创建特定于实例的方法(单例方法)。
class C;end

v1,v2 = C.new, C.new #=>two instances of class C

def v1.meth
  puts "I am only available in instance v1"
end

puts v1.meth #=> prints -> I am only available in instance v1
puts v2.meth #=> throws -> undefined method 'meth'

在Java中它的等价物是什么?


1
你最终从Ruby转到了Java ... :) - Arup Rakshit
1
这有点奇怪。我不了解Ruby,但这不是CS世界其他人理解的Singleton模式。我会称其为特定实例方法(Java中没有相应的方法)。世界其他地方理解的singleton是指一个类只能存在一个实例。Ruby真的改变了“singleton”的含义吗?编辑:显然是这样。这是一种可怕的做法。 - CPerkins
@CPerkins:我不确定你的意思。首先,Ruby和Java是不同的语言。它们之间的工作方式不同,这不是“可怕的做法”,这只是正常的。其次,单例对象、单例类和单例方法之间的区别非常清楚。第三,单例类可以只有一个实例。第四,“singleton”是一个通用的英语单词,意思是“一次性的”。这完美地描述了Ruby中单例方法和单例类的功能。最后:Ruby比Java更古老,所以如果有什么变化,那就是Java改变了含义。 - Jörg W Mittag
@JörgWMittag,“singleton”这个概念,就像模式中的那样,并不是起源于Java。 - CPerkins
4个回答

4
你能做的最接近的是使用匿名类。
class C {}

C v1 = C() {
    void meth() {
        puts("I am only available in instance v1");
    }
};
C v2 = new C();

// prints -> I am only available in instance v1
v1.getClass().getMethod("meth").invoke(v1); 
// throws NoSuchMethodException
v2.getClass().getMethod("meth").invoke(v2); 

在Java 8中,您可以编写:
interface C {
    void meth();
}

C v1 = () -> puts("I am only available in instance v1");
C v2 = () -> { throws new UnsupportedOperationException(); }

v1.meth();
v2.meth();

在自然的Java方法调用中,方法是静态检查的,您不能调用编译器无法确定存在的方法。(您可以使用上面的反射来执行此操作)


哦,没想到可以使用反射来访问匿名子类中的新方法,谢谢提醒 :) 然而,反射是危险的,不应轻易或恶意地使用(例如用于规避框架中的可见性限制)。 - hiergiltdiestfu
@hiergiltdiestfu 我同意你应该避免反射,但也要避免任何不进行静态类型检查的东西。 ;) - Peter Lawrey
1
你是指像 Ruby 一样的语言吗? :D - hiergiltdiestfu
1
Ruby在某些情况下很好用,但你必须能够接受由于Java在编译时会检测到的错误而导致程序编译失败。对于动态语言,答案是编写更好的测试覆盖率。 - Peter Lawrey

1
你可以尝试使用类似策略模式来实现这一点。提供默认策略的实现,该策略会抛出UnsupportedOperationException异常。当然,这意味着你不能动态添加这些“单例方法”,你必须提前创建这些方法。

0

您可以向类的匿名子类添加方法,这有点像“该方法仅在该实例中可用”。

由于该方法在类的已知契约中缺失,因此无法从外部访问,但可以通过同一匿名子类实例中的其他重写方法来调用它。

这将看起来像这样:

    List<String> list = new LinkedList<String>(){
        @Override
        public int size() {
            if (this.contains("fox"))
                return sizeOfFox();

            return super.size();
        }

        private int sizeOfFox() {
            return 4;
        }};

}

您正在创建LinkedList的匿名子类,该子类携带了一个额外的方法,该方法仅在该实例中可用:sizeOfFox()。每当列表包含像"fox"这样的字符串时,此方法将由size()方法的重写版本调用。

这种方法的实际用途有限,不能真正与Ruby单例方法相比。通常,在实例化抽象Listener-Interfaces等并提取代码路径以保持中央方法清洁时使用此类实现。

NB:在Java中,“Singleton”通常是通过应用Singleton Design Pattern来定义的。


0
据我所知,在Java中没有这样的东西!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接