質問

次のメソッドとインターフェイスがあります:

public object ProcessRules(List<IRule> rules)
{
    foreach(IRule rule in rules)
    {
        if(EvaluateExpression(rule.Exp) == true) return rule.Result;
    }

    //Some error handling here for not hitting any rules
}

public interface IRule
{
    Expression Exp;
    Object Result;
    int Precedence;
}

ルールには優先順位があるため、実際には順序どおりに処理されることはありません。これにより、3つの解決策が得られると思います(

)。
  1. 評価者に渡す前にルールをソートします。
  2. パラメータタイプを、ソート順を強制するものに変更します。
  3. エバリュエーター内で並べ替えます。

オプション3は、常にソートされることを常に保証するため、オプション3が好きです。オプション1は、よりまとまりがありそうなので、オプション1が好きです。また、オプション2は妥協案のようです。

このコンテキスト固有/主観的なシナリオですか、ここに適用すべきベストプラクティスは本当にありますか?

役に立ちましたか?

解決

これは、デメテルの法則とカプセル化の違反のようなものだと思います。 EvaluateExpressionは、ルールに属しているように見えます。これを考慮してください:

public object ProcessRules(List<IRule> rules) {
    foreach(IRule rule in rules) {
        return rule.EvaluateExpression();
    }
}

public interface IRule {
    object EvaluateExpression();
}

そのように、ExpやResultなどのルールの内部を公開する必要はありません。

そして、もしあなたが望む振る舞いがルールが優先順位の順に評価されることであるなら、それらがソートされていることを確認してください。ルールの責任はそれ自体を評価することですが、それを評価する順序は呼び出し側の決定です。

他のヒント

オプション3に投票します。カップリングを最小限に抑えるために、関数に送信されるデータについてあまり多くの仮定をしないようにします。

別のクラスが後日これを使用する場合、それらは優先度順にソートされていると知っていると思いますか

このようなシナリオでは、次のようなことをします:

public class RuleProcessor
{   
     public void SortRules(List<IRule> rules){}

     //You could make this an abstract method
     public object ProcessSortedRules(List<IRule> rules)
     {
         foreach(IRule rule in rules)
         {
             if(EvaluateExpression(rule.Exp) == true) return rule.Result;
         }

     //Some error handling here for not hitting any rules

     }

     public object ProcessRules(List<IRule> rules)
     {
          SortRules(rules);
          ProcessSortedRules(rules);
     }

}

抽象クラスまたは他のクラスが集約する何らかの機能を作成できます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top