5

当社のコア製品の一部は、さまざまなページ ウィジェットを利用する Web サイト CMS です。これらのウィジェットは、コンテンツの表示、製品の一覧表示、イベント登録の処理などを担当します。各ウィジェットは、基本ウィジェット クラスから派生したクラスによって表されます。ページをレンダリングするとき、サーバーはデータベースからページのウィジェットを取得し、正しいクラスのインスタンスを作成します。ファクトリーメソッドですよね?

Private Function WidgetFactory(typeId)
    Dim oWidget
    Select Case typeId
        Case widgetType.ContentBlock
            Set oWidget = New ContentWidget
        Case widgetType.Registration
            Set oWidget = New RegistrationWidget
        Case widgetType.DocumentList
            Set oWidget = New DocumentListWidget
        Case widgetType.DocumentDisplay
    End Select
    Set WidgetFactory = oWidget
End Function

とにかく、これで問題ありませんが、時間の経過とともにウィジェットの種類の数が約 50 に増加したため、ファクトリ メソッドはかなり長くなります。新しいタイプのウィジェットを作成するたびに、メソッドにさらに数行追加しますが、これは最善の方法ではないかもしれないという小さな警告が頭の中で鳴り響きます。私はそのアラームを無視する傾向がありますが、大きくなっています。

それで、私はそれを間違っていますか?このシナリオを処理するより良い方法はありますか?

4

7 に答える 7

15

自問すべき質問は、なぜここで Factory メソッドを使用しているのかということだと思います。

答えが「A のため」で、Aが正当な理由である場合は、追加のコードを意味する場合でも、それを続けてください。答えが「わかりません。なぜなら、このようにすべきだと聞いたからです」という場合は、再考する必要があります。

ファクトリを使用する標準的な理由について見ていきましょう。Factory メソッド パターンについてウィキペディアには次のように書かれています。

[...]、作成されるオブジェクトの正確なクラスを指定せずにオブジェクト (製品) を作成する問題を扱います。ファクトリ メソッド デザイン パターンは、オブジェクトを作成するための別のメソッドを定義することでこの問題を処理します。そのサブクラスは、作成される製品の派生型を指定するためにオーバーライドできます。

WidgetFactoryはであるため、これPrivateがこのパターンを使用する理由ではないことは明らかです。「ファクトリ パターン」自体はどうですか (ファクトリ メソッドを使用して実装するか、抽象クラスを使用して実装するかは関係ありません)。繰り返しますが、ウィキペディアは次のように述べています。

次の場合にファクトリ パターンを使用します。

  • オブジェクトを作成すると、コードを大幅に複製することなく再利用できなくなります。
  • オブジェクトの作成には、構成オブジェクト内に含めるのが適切ではない情報またはリソースへのアクセスが必要です。
  • 作成されたオブジェクトのライフタイム管理は、一貫した動作を保証するために一元化する必要があります。

あなたのサンプル コードから、これがあなたのニーズに一致するようには見えません。したがって、質問 (あなただけが答えることができます) は次のとおりです。(1)将来、ウィジェット用に集中化された Factory の機能が必要になる可能性はどのくらいありますか? (2) すべてを元に戻すにはどれくらいの費用がかかりますか?将来的に必要な場合、ファクトリー アプローチはありますか? どちらも低い場合は、当面は安全に Factory メソッドを削除できます。


編集:この一般的な詳細の後に、あなたの特別なケースに戻らせてください:通常、それはa = new XyzWidget()a = WidgetFactory.Create(WidgetType.Xyz)です。ただし、あなたの場合、typeIdデータベースからいくつかの(数値?)があります。マークが正しく書いたように、このtypeId -> className地図をどこかに持っている必要があります。

したがって、その場合、ファクトリ メソッドを使用する正当な理由は次のようになりConvertWidgetTypeIdToClassNameます。もし私がそれらを必要とするなら。」

WidgetType別の方法として、ウィジェットのクラス名をデータベースに保存し (おそらく、主キーを持つテーブルがすでにいくつかあるはずtypeIdですよね?)、リフレクションを使用してクラスを作成することもできます (言語でこのタイプが許可されている場合)。これには多くの利点があります (たとえば、新しいウィジェットで DLL をドロップでき、コア CMS コードを変更する必要はありません) が、欠点もあります (たとえば、コンパイル時にチェックされないデータベース内の「魔法の文字列」; 可能なコード誰がそのテーブルにアクセスできるかによって異なります)。

于 2009-12-17T09:55:52.540 に答える
5

WidgetFactory メソッドは、実際にはtypeId 列挙から具象クラスへのマッピングです。一般的には、列挙を完全に回避できることが最善ですが、(特に Web アプリケーションでは) ポリモーフィズムを理解しない環境 (ブラウザーなど) に往復する必要があり、そのような手段が必要な場合があります。

リファクタリングには、switch/select case ステートメントがコードの匂いである理由についてのかなり良い説明が含まれていますが、主に類似したスイッチが多数ある場合に対処しています。

WidgetFactory メソッドがその特定の列挙型をオンにする唯一の場所である場合、心配する必要はないと言えます。その地図をどこかに持っている必要があります。

別の方法として、マップをディクショナリとして定義することもできますが、コード行の量は大幅に減少しません。コード行を半分に削減できるかもしれませんが、複雑さの程度は同じままです。

于 2009-12-17T09:57:08.997 に答える
4

工場パターンの適用は正しいです。N タイプのどれが作成されるかを指示する情報があります。工場はそれを行う方法を知っているものです。(プライベートメソッドとしては少し奇妙ですIWidgetFactory。インターフェース上にあると思います。)

ただし、実装は、実装を具象型に密結合します。代わりに をマップtypeId -> widgetTypeした場合は、 を使用Activator.CreateInstance(widgetType)してファクトリに任意のウィジェット タイプを理解させることができます。

これで、必要に応じてマッピングを定義できます: シンプルなディクショナリ、検出 (属性/反射)、構成ファイルなどソース。

于 2009-12-18T20:00:44.033 に答える
2

ファクトリを実装する古典的な方法は、巨大なスイッチや if-ladder を使用するのではなく、オブジェクト タイプ名をオブジェクト作成関数にマップするマップを使用することです。これにより、実行時にファクトリを変更できます。

于 2009-12-17T10:04:29.660 に答える
2

それが適切かどうかにかかわらず、Factory を使用するのは、実行時まで利用できない情報に基づいて、どのオブジェクト タイプを作成するかを決定するときであると常に信じてきました。

フォローアップ コメントで、ウィジェット タイプがデータベースに格納されていることを示しました。あなたのコードは実行時までどのオブジェクトが作成されるかを知らないので、これは Factory パターンの完全に有効な使い方だと思います。ファクトリを使用すると、実際に決定が下されるまで、使用するオブジェクト タイプの決定をプログラムで延期できます。

于 2009-12-18T19:39:04.313 に答える
1

ファクトリが成長するので、その依存関係が必要ないというのは私の経験です。このマッピングが他の場所で重複している場合は、心配する必要があります。

于 2009-12-21T22:32:13.600 に答える
0

おそらく機能に基づいて、ウィジェットを分類してみてください。それらのいくつかが論理的に相互に依存している場合は、単一の構造でそれらを作成します

于 2009-12-17T09:52:52.500 に答える