0

私はオンライン ストアを開発していますが、顧客は注文を削除して、商品を自動的に補充する機能を必要としています (たとえば、テスト注文の場合)。これを実装する最初の試みは次のとおりです。

class Order < ActiveRecord::Base
  def destroy_and_restock
    restock_products
    destroy
  end

  protected

  def restock_products
    line_items.each do |li|    
      li.product.quantity_on_hand += li.quantity
      li.product.save
    end
  end
end

destroy_and_xしかし、後で別のメソッドを作成する必要がある場合はどうすればよいでしょうか? X をパラメーターとしてdestroy()メソッドに渡すことを許可しないのはなぜですか? だから今、私はこれで行くことを考えています:

alias :old_destroy :destroy
def destroy(options = {})
  if options['restock'] == true
    restock_products
  end
  old_destroy
end

protected

def restock_products
  line_items.each do |li|    
    li.product.quantity_on_hand += li.quantity
    li.product.save
  end

これはより拡張可能ですが、私はやや汚いと感じます。汚いと感じるのは間違っていますか?これを行うより良い方法はありますか?

4

4 に答える 4

2

「はい、これは汚いです」と言うでしょう。あなたの意図は、「destroy」メソッドの動作を変更することではなく、ドメイン固有の作業を行ってから を実行することdestroyです。あなたの最初のアプローチは素晴らしいです。あなたが望むことをするメソッドを定義し、必要に応じて呼び出しdestroyます。あなたが考えているように、メソッドを「ラッピング」または「モンキーパッチ」することは、標準的なオブジェクト指向アプローチを使用できない場合に最適な手法であると思います。制御の範囲外で定義および使用されるクラス。

メソッド自体の動作を変更すること検討している場合でも、メソッドをラップするのではなく、ここでメソッドをオーバーライドすることをお勧めします。destroy

def destroy(options = {})
  restock_products if options['restock']
  super() # I think parens are necessary here, to avoid passing options up the chain
end
于 2009-06-16T04:19:48.503 に答える
0

ブロックを使うのはどうですか?そうすれば、クラスでこれをデザインするときに髪を引き離す必要はなく、必要なときに必要なときにさらに多くのことができます。

def destroy_after &block
  yield if block
  destroy
end

次に、次のように呼び出します。

order.destroy_after { order.restock_products }

この関数の良い名前は思いつかない...でも、あなたがそのアイデアを理解してくれることを願っている。

于 2009-06-16T04:48:57.807 に答える
0

ホレス、私はあなたの質問を誤解しました。私はあなたがこれを探していると思います:

http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

これで、メソッドを保護したままにし、好きなだけ before_destroy を追加できます。destroy をオーバーライドせずにこれが機能することを願っています。

幸運を祈ります。

于 2009-06-16T10:20:32.950 に答える
0

モンキー パッチを適用しても夜眠れない場合は、サブクラス化することで同じことを実現できます。簡単なハックや簡単なデバッグ ハックが必要な場合は、パッチも適用します。

于 2009-06-16T10:24:43.207 に答える