In my hypothetical application, users can ask questions, which are then answered by an Oracle
. You can use the Predictor.predictor
method to get an appropriate Oracle
, to whom you can then direct your questions. When you #ask
a question, you'll get a response, along with the Oracle
's certainty (a floating-point 开发者_如何转开发number in the range 0..1) about its response.
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]
In this implementation, you get the same Oracle every time, an UnreliableOracle instance. What I would like to do is to change the implementation of Predictor.predictor so that methods which are invoked on it are delegated to a collection of Oracles, some of which are better than others. In other words, I want it to work something like this:
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]
What's the best way to do that?
This is essentially the strategy design pattern, where each Oracle is effectively a strategy for answering questions.
The easiest (and perhaps cleanest) approach is to construct a MetaOracle
that asks the other oracles what the right answer is and picks the best answer:
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
Now the Oracle with the best answer wins and will be the answer that you see.
精彩评论