Как мне одновременно отправить метод в несколько экземпляров, когда раньше он отправлялся только в один?

#ruby #design-patterns

#ruby #шаблоны проектирования

Вопрос:

В моем гипотетическом приложении пользователи могут задавать вопросы, на которые затем отвечает Oracle . Вы можете использовать Predictor.predictor метод, чтобы получить соответствующего Oracle человека, которому вы затем можете направить свои вопросы. Когда вы #ask задаете вопрос, вы получите ответ вместе с Oracle уверенностью (число с плавающей запятой в диапазоне 0 .. 1) в его ответе.

 class BaseOracle; def ask(question); ...; end; end
class UnreliableOracle < BaseOracle; ...; end

module Predictor
  def self.predictor
    @predictor ||= UnreliableOracle.new
  end
end

Predictor.predictor.ask("How many fingers am I holding up?")
 # => ["three fingers", 0.2]
  

В этой реализации вы каждый раз получаете один и тот же Oracle, ненадежный экземпляр Oracle. Что я хотел бы сделать, так это изменить реализацию Predictor.predictor так, чтобы методы, которые вызываются на нем, делегировались коллекции оракулов, некоторые из которых лучше других. Другими словами, я хочу, чтобы он работал примерно так:

 class BaseOracle; ...; end
class UnreliableOracle < BaseOracle; ...; end
class PopCultureOracle < BaseOracle; ...; end
class ScienceOracle < BaseOracle; ...; end
class LiteraryOracle < BaseOracle; ...; end
class FingerCountingOracle < BaseOracle; ...; end

module Predictor
  def self.predictor
    ############## What goes here?
  end
end

# This actually asks several oracles for an answer and picks the best one.
Predictor.predictor.ask("How many fingers am I holding up?")
 # => ["four fingers", 1.0]
  

Каков наилучший способ сделать это?

Ответ №1:

По сути, это шаблон разработки стратегии, где каждый Oracle фактически является стратегией для ответов на вопросы.

Самый простой (и, возможно, самый чистый) подход заключается в создании MetaOracle , который запрашивает у других оракулов правильный ответ и выбирает наилучший ответ:

 class MetaOracle
  def oracles
    @oracles ||= [ScienceOracle.new, LiteraryOracle.new, # ...
  end

  def ask(question)
    oracles.map { |o| o.ask question }.        # Ask each Oracle a question ...
      sort_by { |answer| -answer.certainty }.  # sort by the best answers ...
      first                                    # ... and pick the best one.
  end
end

module Predictor
  def self.predictor
    @predictor ||= MetaOracle.new
  end
end
  

Теперь Oracle с лучшим ответом выигрывает и будет тем ответом, который вы видите.