0

私はいくつかのものを保持するRubyのクラスを持っています、私は呼び出しますFooBox:

class FooBox
  ...
end

FooBox呼び出されたものBoxABoxB、異なる特性を持つが同じインターフェイスを持つ 2 つの可能なバッキング データ ストアがあります。

class BoxA
  include Enumerable
  def put_stuff(thing)
    ...
  end
end


class BoxB
  include Enumerable
  def put_stuff(thing)
    ...
  end
end

をインスタンス化FooBoxし、パラメータに基づいて、BoxAまたはBoxB実装でそれをバックアップするかどうかを決定するにはどうすればよいですか? 実装をコンストラクターに渡したくありません。使用する種類を決定するために何かを渡したいだけです。

class FooBox
  def initialize(implementation_choice)
    # ???
  end
end
4

2 に答える 2

1

私は通常、次のようなことをします:

class BoxA
  def self.match? options
    # figure out if BoxA can be used given options
  end
end

# Implement BoxB (and other strategies) similarly to BoxA

class FooBox
  STRATEGIES = [BoxA, BoxB]

  def initialize options
    @options = options
  end

  def strategy
    @strategy ||= STRATEGIES.detect { |strategy| strategy.match? @options }
  end
end

これにより、(コンテキスト クラスをモノリシックにするのではなく) 戦略が戦略自体の中で使用できるかどうかを「知る」責任が保持され、それが機能することを示しているリストの最初のものを選択するだけです。

私はこのパターン (およびわずかに異なる問題に対する同様のバリエーション) を数回使用しましたが、非常にクリーンであることがわかりました。

于 2013-03-11T03:30:57.450 に答える
0

簡単な解決策は、@Andrew Marshallのソリューションと同様に、戦略のタイプと戦略クラスのマッピングを作成することです

しかし、より良いものにするために、次の2つのことを検討します。

  • FooxBoxストラテジーのホルダー (ここでは これは柔軟なアプローチではありません。ある日、別の戦略を追加したい場合は、コードに移動して追加しますか? ruby を使用すると、「自己登録」で簡単に実行できます。
  • 戦略ホルダーが乱暴に実装を返すことは望ましくありません。つまり、「BoxA」と「BoxB」の両方、またはいつか「BoxXYZ」の両方が同じ戦略概念に属している必要があります。Java では、おそらくそれらすべてが を実装する必要があることを意味しますinterface。私たちは一般的にそれを行いますinclude SomeMoudle

私のアプリケーションでは、次のソリューションを使用しています(デモのみ)

module Strategies
  def self.strategies
    @@strategies ||= {}
  end

  def self.strategy_for(strategy_name)
    @@strategies[strategy_name]
  end
end

module Strategy
  def self.included(base)
    base.class_eval do
      def self.strategy_as(strategy_name)
        Strategies.strategies[strategy_name] = self
      end
    end
  end 
end


class BoxA
  include Strategy

  strategy_as :box_a

  def do_stuff
    puts "do stuff in BoxA"
  end
end 

class BoxB
  include Strategy

  strategy_as :box_b

  def do_stuff
    p "do stuff in BoxB"
  end
end

## test 
Strategies.strategy_for(:box_a).new.do_stuff
Strategies.strategy_for(:box_b).new.do_stuff

マッチブロックで戦略を検出したい場合はstrategy_as、ブロックを受け入れるように変更できます。次に使用するStrategies.strategy_for{...}.new.do_stuff

于 2013-03-11T04:34:38.433 に答える