调用Ruby Singleton的方法而不引用’instance’

我想调用Singleton对象的方法而不引用它的实例

SingletonKlass.my_method 

代替

 SingletonKlass.instance.my_method 

我想出了这个解决方案(在课堂上使用method_missing):

 require 'singleton' class SingletonKlass include Singleton def self.method_missing(method, *args, &block) self.instance.send(method, *args) end def my_method puts "hi there!!" end end 

这有什么缺点吗? 还有更好的解决方案吗? 你的任何推荐?

谢谢。

更新:

我的目标是让一个模块与单例类混合:

 module NoInstanceSingleton def method_missing(method, *args) self.instance.send(method, *args) end end 

结束然后在课堂上使用它:

 class SingletonKlass include Singleton extend NoInstanceSingleton def method1; end def method2; end ... def methodN; end end 

我想能够直接打电话:

 SingletonKlass.method1 

使用forwardable和def_delegators:

 require 'singleton' require 'forwardable' class SingletonKlass include Singleton class << self extend Forwardable def_delegators :instance, :my_method end def my_method puts "hi there!!" end end SingletonKlass.my_method 

编辑:如果你想包括你自己定义的所有方法,你可以做到

 require 'singleton' require 'forwardable' class SingletonKlass include Singleton def my_method puts "hi there!!" end class << self extend Forwardable def_delegators :instance, *SingletonKlass.instance_methods(false) end end SingletonKlass.my_method 

method_missing解决方案的问题在于,如果在SingletonKlass上不存在该名称的方法,它将仅将调用重定向到instance ,如果人们想通过您提供的此接口访问instance.__id__ ,则会导致问题。 以正常方式访问SingletonKlass.instance没有太大问题,但如果你真的想要创建一个快捷方式,最安全的是一个常量:

 KlassInstance = SingletonKlass.instance 

如果要动态定义常量,请使用Module#const_set

 const_set :KlassInstance, SingletonKlass.instance 

你也可以扩展这一点。 例如,您可以创建一个方法来为您创建这样的常量:

 def singleton_constant(singleton_class) const_set singleton_class.name, singleton_class.instance end 

当然,因为Module#const_setModule#const_set的方法,所以这种特定技术只能在模块或类的上下文中执行。 另一种可能性是mixin模块带有重载钩子方法:

 module SingletonInstance def included(base_class) const_set base_class.name, base_class.instance super end end 

这是一个替代方案,并不属于我的第一个答案的范围。 您可以创建一个mixin模块,该模块取消定义基类的所有方法,然后使用method_missing技术:

 module SingletonRedirect def included(base_class) instance = base_class.instance base_class.class_eval do methods.each &undef_method define_method :method_missing do |name, *arguments| instance.public_send name, *arguments end end end end 

为了实现这个想法, instance是一个局部变量,它通过闭包传递给Class#class_evalModule#define_method的调用中的块。 然后,我们不需要通过base_class.instance来引用它,因此我们可以清除所有方法,包括那个方法(一种称为空白平板的技术)。 然后,我们定义一个方法重定向系统,该系统利用平坦范围将instance称为变量,并仅调用通过Object#public_send公开可用的方法。

你为什么不使用“静态”课程? 例如:

 class StaticKlass class << self def method1; end def method2; end ... def methodN; end end end StaticKlass.method1 

我将使用UrlHelper这个名称作为一个更具体的例子,而不是SingletonKlass

 require 'singleton' class UrlHelperSingleton include Singleton def my_method ... end end UrlHelper = UrlHelperSingleton.instance # then elsewhere UrlHelper.my_method