首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ruby:调用Singleton实例方法的DRY类方法

Ruby:调用Singleton实例方法的DRY类方法
EN

Stack Overflow用户
提问于 2016-01-16 15:48:49
回答 3查看 1.6K关注 0票数 4

我有一个Singleton类ExchangeRegistry,它保存了所有的Exchange。

而不需要调用:ExchangeRegistry.instance.exchanges

我希望能够使用:ExchangeRegistry.exchanges

这是可行的,但我对重复一遍并不满意:

代码语言:javascript
复制
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

我对课堂方法中的重复不满意。

我试过使用ForwardableSimpleDelegator,但似乎无法让它干涸。(大多数示例不是针对类方法,而是针对实例方法)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-01-16 22:12:34

转发模块将完成这一任务。由于您是转发类方法,所以必须打开本征类并在那里定义转发:

代码语言:javascript
复制
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"
票数 7
EN

Stack Overflow用户

发布于 2016-01-16 18:16:42

公认的答案是聪明的,但似乎是不必要的复杂(更不用说method_missing的性能损失了。

解决这个问题的通常方法是将实例赋值给常量。

代码语言:javascript
复制
class ExchangeRegistrySingleton
  include Singleton

  # ...
end

ExchangeRegistry = ExchangeRegistrySingleton.instance
票数 2
EN

Stack Overflow用户

发布于 2016-01-16 16:11:52

您可以利用method_missing钩子并将方法调用委托给instance

代码语言:javascript
复制
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中动态创建类方法

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34828891

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档