2017-01-16 4 views
3

シナリオこのシナリオで列挙型に対して多型を使用する利点はありますか?

私は別のコンポーネント(レポートビルダ)に送信する動的なクエリビルダを作成しています。

クエリの一部にプレースホルダがあります。例えば:

SELECT DISTINCT ID, NAME AS VALUE FROM EVENTS 
WHERE {{ESTABLISHMENTFILTER.ID}} IS NULL OR ESTABLISHMENT_ID = {{ESTABLISHMENTFILTER.ID}} 

データ句は整数、文字列、日付とすることができ、それぞれが、例えば、異なる挙動を有する(ここで置換される:文字列の値の周囲に一重引用符を含みます場合)。 、

public enum FilterType 
{ 
    Integer, 
    String 
} 

、私はまた私のコードにSOLID原則を適用しています

switch (filter.Type) 
{ 
    case FilterType.Integer: 
     //Do replace logic for an integer 
     break; 
    case FilterType.String: 
     //Do replace logic for a string 
     break; 
    default: 
     break; 
} 

(例えば、ビジネス層に)このようにそれを使用します。

私の最初のアプローチは、列挙型を作成することでしたこれがOCPを破る可能性があることが分かりました。だから私は、基本クラス

public abstract class FilterType 
{ 
    public abstract string Replace(string baseString, string oldValue, string newValue); 
} 

を使用するようにリファクタリングされ、各タイプは、独自の実装を持っています

public class FilterTypeInteger : FilterType 
{ 
    public override string Replace(string baseString,string oldValue, string newValue) 
    { 
     //Do logic to replace for an Integer type 
    } 
} 

固溶体は、私のテストのために働いていた問題が、生産コードでタイプを決定するためのint列がデータベースにあります。だから、私は基本的には、適切なFilterTypeをインスタンス化するためにこの列をチェックしなければならないdatalayerにswitch-caseロジックを転送しています(まだ実装されていないので、以下のコードは擬似コードです):

if (dataReader["FILTERTYPE"] == 1) 
     filter.Type = new FilterTypeInteger(); 
    else if (dataReader["FILTERTYPE"] == 2) 
     filter.Type = new FilterTypeString(); 

質問

1)上記 'のif-else' ロジックを実装する方法は、OCPを壊していますか?新しいTypeが作成された場合は、新しいelse節を実装する必要があります
2)ou if-else節を使用せずにSOLID OCPの原則をデータベースとビジネスコードの両方に保持する方法がありますか?

+0

SQL文を作成する場合は、ライブラリとその準備文を使用してそれらの処理を行うのはなぜですか? – Seth

+0

クエリは既存のユーザーインターフェイスを通じて作成されるため、テンプレートに定義されたプレースホルダをサポートする必要があります。また、カスケードクエリをサポートする必要があります。そのため、自分のコンポーネントをビルドすることにしました。 –

答えて

1

Replacing contionnal with polymorphysimは意思決定が一度しか行われないようにするため、おそらく良い考えです。ある時点でタイプごとに特殊な操作が追加されている場合は、実装が容易でなければなりません。

ここで、具体的なタイプを作成するために、このロジックを工場でカプセル化することができます。最も単純な形式では、工場は大きなswitch文を持つ静的なものになります。それはOCPを尊重するものではありませんが、ほとんどの場合、今でも受け入れられる設計です。

しかし、デザインで拡張可能にしたい場合や実行時にはそうしない場合、実行時に新しい型を発見/登録する方法を導入する必要があります。

これは多くの方法で行うことができますが、新しいタイプを登録できる方法を工場で使用することが考えられます。

など。

filterTypeFactory.RegisterFilter(1, typeof(FilterTypeInteger)); 

あなたが所有して独自のSQLステートメントビルダーを構築する前に、既存のライブラリを参照する必要があります。中間のDSL(テンプレート)をASTに解析し、このASTを処理してSqlCommandなどを生成することができます。

+0

それは良い解決策です。私は、これから学んだ教訓は、時にはSOLIDを使わないでいいパターンを保つことです。私があなたが言及したそれらのライブラリについてもっと検索します。 –

+0

@DaniloRuziskaソリッドの原則はガイドラインですが、あなたは実用的な状態を保たなければなりません。静的なファクトリで作業が完了した場合は、新しいフィルタタイプを必要としないときに自動的に検出できる非常に洗練された拡張可能なマカニズムを構築するのではなく、それに固執する方がよいでしょう。 – plalx

+0

@plalxオッカムのカミソリは、「違反する」原則の良い言い訳です。 – CSharpie

関連する問題