【问题标题】:Avoiding method overloading in Ruby避免 Ruby 中的方法重载
【发布时间】:2015-01-23 23:08:34
【问题描述】:

由于 Ruby 不支持重载(由于几个微不足道的原因),我正试图找到一种“模拟”它的方法。

在静态类型语言中,你不能使用instanceof,(当然某些特殊情况除外......)来指导应用程序。

所以,请记住这一点,这是重载我关心变量类型的方法的正确方法吗? (在这种情况下,我不关心参数的数量)

class User
  attr_reader :name, :car
end

class Car
  attr_reader :id, :model
end

class UserComposite
  attr_accessor :users

  # f could be a name, or a car id
  def filter(f)
    if (f.class == Car)
      filter_by_car(f)
    else
      filter_by_name(f)
    end
  end

  private

  def filter_by_name(name)
    # filtering by name...
  end

  def filter_by_car(car)
    # filtering by car id...
  end
end

【问题讨论】:

    标签: ruby overloading


    【解决方案1】:

    种情况下这是一种很好的方法,而 Ruby 为您提供了处理它的工具。

    但是,您的案例不清楚,因为您的示例自相矛盾。如果f.class == Carfilter_by_car 接受_car,而不是_car_id

    我假设您实际上是在传递类的实例,如果是这样,您可以这样做:

    # f could be a name, or a car
    def filter(f)
      case f
      when Car
        filter_by_car(f)
      else
        filter_by_name(f)
      end
    end
    

    case [x] 查看它的每个when [y] 子句并执行[y] === [x] 的第一个子句

    实际上这是在运行Car === f。当您在类对象上调用#=== 时,如果参数是该类的实例,则返回true。

    这是一个非常强大的结构,因为不同的类可以定义不同的“大小写相等”。例如,如果参数与表达式匹配,Regexp 类将大小写相等定义为 true,因此以下工作:

    case "foo"
    when Fixnum
      # Doesn't run, the string isn't an instance of Fixnum
    when /bar/
      # Doesn't run, Regexp doesn't match
    when /o+/
      # Does run
    end
    

    【讨论】:

      【解决方案2】:

      就我个人而言,我认为以这种方式进行分支并没有什么大问题。虽然使用case 会看起来更干净

      def filter(f)
        case f
        when Car
          filter_by_car(f)
        else
          filter_by_name(f)
        end
      end
      

      稍微复杂一点的例子涉及用对象替换分支(毕竟,ruby 是 oop 语言:))。在这里,我们为特定格式(类)的数据定义处理程序,然后通过传入的数据类查找这些处理程序。大致如下:

      class UserComposite
        def filter(f)
          handler(f).filter
        end
      
        private
        def handler(f)
          klass_name = "#{f.class}Handler"
          klass = const_get(klass_name) if const_defined?(klass_name)
          klass ||= DefaultHandler
          klass.new(f)
        end
      
        class CarHandler
          def filter
            # ...
          end
        end
      
        class DefaultHandler # filter by name or whatever
          def filter
            # ...
          end
        end
      end
      

      【讨论】:

      • 实际上,我发现后者的建议更像 Ruby-way。只需创建一个响应调用对象的方法。 :)
      • 好像你在使用反射,不是吗?你们在 Ruby 方面的经验比我多,所以我不知道这是否来自“Ruby 的世界”,但我必须相信你,尽管我不喜欢对这种简单的事情进行反思。那里没有设计模式吗?
      • @Quarktum:是的,这是反射。我也不是它的忠实粉丝。在你的情况下,我可能只使用case(除非你过于简单化)
      • @Quarktum:ruby 代码(尤其是 rails)充满了反射。它是 ruby​​ 的强大功能之一,因此它通常比在 java 中使用得更多。 :)
      • @SergioTulentsev:是的。只有在不超过 7 到 8 行的情况下,我才会使用 case。但是,一如既往的好答案。荣誉.. :)
      【解决方案3】:

      您的架构中可能潜伏着一个问题 - UserComposite 需要对 CarUser 了解太多。假设您需要添加更多类型? UserComposite 会逐渐变得臃肿。

      但是,很难给出具体的建议,因为过滤背后的业务逻辑并不清晰(架构应该始终适应您的实际用例)。

      您真的需要对Cars 和Users 执行共同的操作吗?

      如果不是,请不要将行为合并到单个 UserComposite 类中。

      如果是这样,您应该使用具有通用接口的装饰器。大致是这样的:

      class Filterable
        # common public methods for filtering, to be called by UserComposite
        def filter
          filter_impl  # to be implemented by subclasses
        end
      end
      
      class FilterableCar < Filterable
        def initialize(car)
          @car = car
        end
        private
        def filter_impl
          # do specific stuff with @car
        end
      end
      
      class DefaultFilterable < Filterable
        # Careful, how are you expecting this generic_obj to behave?
        # It might be better replace the default subclass with a FilterableUser.
        def initialize(generic_obj)
          # ...
        end
        private
        def filter_impl
          # generic behavior
        end
      end
      

      然后UserComposite 只需要关心它是否传递了Filterable,它所要做的就是在该对象上调用filter。拥有通用的可过滤接口使您的代码可预测,并且更易于重构。

      我建议您避免动态生成可过滤的子类名称,因为如果您决定重命名子类,将很难找到生成代码的代码。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-31
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多