【问题标题】:Return an array of items that satisfies a specific rule返回满足特定规则的项目数组
【发布时间】:2020-01-09 16:09:04
【问题描述】:

我有一个示例类,它充当如下规则,将来它们将成为更多规则。在这种情况下,它会检查一个项目是否是保险,如果是,那么satisfied? 方法就会发挥作用:

class ItemAvailabilityRule
  def applicable?(item:)
    item.name == Item::INSURANCE
  end

  def satisfied?(bookable:, item:)
    applicable?(item) && bookable.duration_in_days < 365
  end
end

我有另一个类将规则应用于以下项目:

class ItemsAvailabilityPolicy
  def initialize(rules: [])
    @rules = rules
  end

  def apply(bookable:, items:)
    items.map do |item|
      applicable_rules = rules.select { |rule| rule&.applicable?(item: item) && rule&.applicable?(bookable: bookable, item: item) }
      applicable_rules.detect { |rule| !rule.satisfied?(bookable: bookable, item: item) }
    end
  end
end

我认为我的 apply 方法不太正确..

我想通过这个 apply 方法实现的是,对于使用这个的单个项目: applicable_rules = rules.select { |rule| rule.applicable?(item: item) } 会给我所有适用于该项目的规则。 然后我想检查是否至少有一个不满意的规则 我为此做了: applicable_rules.detect { |rule| !rule.satisfied?(bookable: bookable, item: item) }

然后我想从数组中删除不满足所有适用规则的项,并返回一个仅包含满足规则的数组。我怎样才能做到这一点?

【问题讨论】:

  • 所以你想选择满足所有适用规则的项目?

标签: ruby-on-rails ruby


【解决方案1】:

你差点就吃完了:

class ItemsAvailabilityPolicy
  def initialize(rules: [])
    @rules = rules
  end

  def apply(bookable:, items:)
    items.select do |item|
      applicable_rules = rules.select { |rule| rule&.applicable?(item: item) && rule&.applicable?(bookable: bookable,
 item: item) }
      non_satisfactory = applicable_rules.detect { |rule| !rule.satisfied?(bookable: bookable, item: item) }
      non_satisfactory.blank?
    end
  end
end

更改很少,首先将map 更改为select,因此您只选择从您的块中返回true 的项目。 Enumerable#select 需要从块中的每个项目返回真值或假值,因此我们使用 blank?

【讨论】:

    【解决方案2】:

    如果我理解正确(如 Stefan 所问),您想退回所有满足所有适用规则的物品吗?而且您有一个“可预订”对象,您想针对集合中的所有项目进行测试。这假设每个规则将以相同的方式应用(即使用相同的变量等)

    您实际上不需要在此处使用任何局部变量,因为 Array#select 是您需要的(对于项目),您可以再次使用 select 来获取适用规则并将其与 Array#all? 链接以确保项目(您可能选择的)通过了所有(适用的)规则......

    这是代码(比解释更容易理解!)

    class ItemsAvailabilityPolicy
      def initialize(rules: [])
        @rules = rules
      end
    
      def apply(bookable:, items:)
        items.select do |item|
          @rules.select { |rule| rule.applicable?(item: item) }.all? do |rule|
            rule.satisfied?(bookable: bookable, item: item)
          end
        end
      end
    end
    

    注意我使用@rules 是因为您使用了实例变量,而没有使用attr_readerattr_accessor

    希望有帮助

    【讨论】:

      猜你喜欢
      • 2020-11-08
      • 2019-09-01
      • 2018-05-18
      • 1970-01-01
      • 2015-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多