我有一个Singleton类ExchangeRegistry,它保存了所有的Exchange。
而不需要调用:ExchangeRegistry.instance.exchanges
我希望能够使用:ExchangeRegistry.exchanges
这是可行的,但我对重复一遍并不满意:
require 'singleton'
# Ensure an Exchange is only created once
class ExchangeRegistry
include Singleton
# Class Methods ###### Here be duplication and dragons
def self.exchanges
instance.exchanges
end
def self.get(exchange)
instance.get(exchange)
end
# Instance Methods
attr_reader :exchanges
def initialize
@exchanges = {} # Stores every Exchange created
end
def get(exchange)
@exchanges[Exchange.to_sym exchange] ||= Exchange.create(exchange)
end
end我对课堂方法中的重复不满意。
我试过使用Forwardable和SimpleDelegator,但似乎无法让它干涸。(大多数示例不是针对类方法,而是针对实例方法)
发布于 2016-01-16 22:12:34
转发模块将完成这一任务。由于您是转发类方法,所以必须打开本征类并在那里定义转发:
require 'forwardable'
require 'singleton'
class Foo
include Singleton
class << self
extend Forwardable
def_delegators :instance, :foo, :bar
end
def foo
'foo'
end
def bar
'bar'
end
end
p Foo.foo # => "foo"
p Foo.bar # => "bar"发布于 2016-01-16 18:16:42
公认的答案是聪明的,但似乎是不必要的复杂(更不用说method_missing的性能损失了。
解决这个问题的通常方法是将实例赋值给常量。
class ExchangeRegistrySingleton
include Singleton
# ...
end
ExchangeRegistry = ExchangeRegistrySingleton.instance发布于 2016-01-16 16:11:52
您可以利用method_missing钩子并将方法调用委托给instance。
require 'singleton'
class ExchangeRegistry
include Singleton
# Missing methods will be delegated to `instance` if an implementation is available.
# Else `NoMethodError` will be raised via call to `super`
def self.method_missing method_name, *args
if instance.respond_to? method_name
puts "** Defining new method: '#{method_name}'"
(class << self; self; end).instance_eval do
define_method(method_name) do |*args|
instance.send(method_name, *args)
end
end
instance.send(method_name, *args)
else
super
end
end
attr_reader :exchanges
def initialize
@exchanges = {} # Stores every Exchange created
end
def get(exchange)
@exchanges[Exchange.to_sym exchange] ||= Exchange.create(exchange)
end
end
# By default, there is no class method - `exchanges`
p ExchangeRegistry.singleton_methods.grep(/exchanges/)
#=> []
p ExchangeRegistry.exchanges
#=> ** Defining new method: 'exchanges'
#=> {}
# After first call to `exchanges`, a new class method is now available
# Future calls will not hit `method_missing` again.
p ExchangeRegistry.singleton_methods.grep(/exchanges/)
#=> [:exchanges]
p ExchangeRegistry.exchanges
#=> {}此问题的另一个答案表示处理method_missing存在性能损失。因此,当第一次报告method_missing时,我更新了答案以定义类方法。更新基于文章:在Ruby中动态创建类方法
https://stackoverflow.com/questions/34828891
复制相似问题