调用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_set
是Module#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_eval
和Module#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