【问题标题】:Optimal Design of a Ruby Data Structures LibraryRuby 数据结构库的优化设计
【发布时间】:2011-06-05 21:06:28
【问题描述】:

我正在研究 Ruby 中的数据结构基础知识,以便在 CS 大二/初级阶段学习。

我的问题:鉴于以下代码,是否有人发现这种方法在 Ruby 中用于数据结构库的任何设计问题?特别是 Module#abstract_method。就鸭子打字哲学而言可以这样做吗?这是否使静态语言的人的代码更清晰,并提供一些界面的外观?

class Module

  def abstract_method(symbol)
    module_eval <<-"end_eval"
      def #{symbol.id2name}(*args)
        raise MethodNotImplementedError
      end
    end_eval
  end

end

class AbstractObject < Object

  abstract_method :compare_to
  protected :compare_to

  class MethodNotImplementedError < StandardError; end

  def initialize
    super
  end

  include Comparable

  def <=>(other)
    if is_a?(other.class)
      return compare_to(other)
    elsif other.is_a?(self.class)
      return -other.compare_to(self)
    else
      return self.class <=> other.class
    end
  end

end

# methods for insertion/deletion should be provided by concrete implementations as this behavior
# is unique to the type of data structure. Also, concrete classes should override purge to discard
# all the contents of the container

class Container < AbstractObject

  include Enumerable

  def initialize
    super
    @count = 0
  end

  attr_reader :count
  alias :size :count

  # should return an iterator
  abstract_method :iter

  # depends on iterator object returned from iter method
  # layer of abstraction for how to iterate a structure
  def each
    i = iter
    while i.more?
      yield i.succ
    end
  end

  # a visitor provides another layer of abstraction for additional
  # extensible and re-usable traversal operations
  def accept(visitor)
    raise ArgumentError, "Argument must be a visitor" unless visitor.is_a?(Visitor)
    each do |obj|
      break if visitor.done?
      visitor.visit(obj)
    end
  end

  # expected to over-ride this in derived classes to clear container
  def purge
    @count = 0
  end

  def empty?
    count == 0
  end

  def full?
    false
  end

  def to_s
    s = ""
    each do |obj|
      s << ", " if not s.empty?
      s << obj.to_s
    end
    self.class + "{" + s + "}"
  end


end

class List < Container

  def initialize
    super
  end

  def compare_to(obj)
   "fix me"
  end

end

【问题讨论】:

    标签: ruby oop data-structures


    【解决方案1】:

    几点说明:

    • 定义一个只引发 NotImplemented 错误的方法有点多余,因为如果该方法不存在,Ruby 无论如何都会这样做。您在那里编写的代码与简单地添加注释说“您必须实现一个名为 compare_to 的方法”一样有用。事实上,这就是 Ruby 标准库中的 Enumerable 模块所做的——在文档中明确指出,为了使用 Enumerable 中的功能,您必须定义一个 each() 方法。

    • compare_to 方法也是多余的,因为这正是 运算符的用途。

    • 在 Ruby 中使用实际的迭代器对象有点矫枉过正,因为块往往具有更加优雅和简单的方法。您的访问者模式也是如此 - 当您只需将块传递给 traverse 方法时,您不需要将访问者用于“可扩展和可重用的遍历操作”。例如,您在 Enumerable 中有很多:each、each_with_index、map、inject、select、delete_if、partition 等。所有这些都以不同的方式使用块来提供不同类型的功能,并且可以添加其他功能以相当简单和一致的方式(尤其是当你有公开课时)。

    • 关于接口,在 Ruby(以及几乎任何其他动态语言,如 Python)中,人们通常使用隐式的接口,这意味着您实际上并没有在代码。相反,您通常依靠文档和适当的测试套件来确保代码能够很好地协同工作。

    我认为您的代码可能更符合来自 Java 世界的人,因为它坚持“Java 方式”做事。然而,对于其他 Ruby 程序员来说,您的代码会令人困惑且难以使用,因为它并没有真正坚持“Ruby 方式”的做事方式。例如,使用迭代器对象的选择函数的实现:

    it = my_list.iter
    results = []
    
    while it.has_next?
      obj = it.next
    
      results << obj if some_condition?
    end
    

    对于 Ruby 程序员来说,比:

    results = my_list.select do |obj|
      some_condition?
    end
    

    如果您想查看 Ruby 中的数据结构库示例,可以在此处查看算法 gem:http://rubydoc.info/gems/algorithms/0.3.0/frames

    还可以查看 Enumerable 模块中默认提供的内容:http://www.ruby-doc.org/core/classes/Enumerable.html。当您包含 Enumerable 时,您将免费获得所有这些功能。

    我希望这会有所帮助!

    【讨论】:

    • 我会更进一步:问题中的代码对于 Ruby 程序员来说不仅仅是“令人困惑且难以使用”,它根本不是 Ruby。时期。它是带有 Ruby 语法的 Java。好吧,实际上,由于它也不是真正面向对象的,它更像是带有 Ruby 语法的 Pascal。
    • 因此,将枚举策略作为可以是抽象的类并因此可以任意替换为具体实现的类没有任何优势吗?似乎一个块只是一种用于快速一次性工作的匿名方法,并且不能被其他算法重用或轻松替换,等等。
    • 它很容易替换,当您调用枚举方法时,您可以在需要不同算法时简单地将不同的块传递给方法;)此外,可以通过将块转换为Proc 或 lambda 然后可以传递给其他方法,存储在变量中等。使用对象的枚举策略在 Ruby 1.9 中也可以使用 Enumerator 对象,但使用 Iterators 的 Java 方法需要大量额外的“样板” 90% 的枚举用例:Ruby 主义者认为是糟糕的设计。
    • 谢谢,帮助。我觉得这种语言比我想象的更强大。
    • 再次阅读本文后,我认为每个方法都是使用迭代器的方法,这使得它成为第一次出现的更强大的模式。我不认为你会说它 = my_list.iter,你会说 my_list.each,它在内部使用基于具体 iter 实现的迭代器。所以 my_list.each {|x| do_stuff } 根据为特定列表实施的策略而有所不同。
    猜你喜欢
    • 2011-11-30
    • 1970-01-01
    • 2010-09-11
    • 2011-04-09
    • 1970-01-01
    • 1970-01-01
    • 2015-06-17
    • 1970-01-01
    • 2019-08-19
    相关资源
    最近更新 更多