コンストラクター vs..NET Frameworkのファクトリ
-
18-09-2019 - |
質問
以下は、.net Framework のパターンの使用に関する記事です。以下の抜粋の太字の部分がよくわかりません。オブジェクトの作成の詳細を変更すると、コンストラクターの引数も変更される (可能性がある) ということを暗示しているのでしょうか?
フレームワークには、次のようなケースが多数あります。 構造体またはクラスの新しいインスタンスを取得できます コンストラクタを自分で呼び出す必要はありません。ザ System.Convert クラスには、静的な このように動作するメソッド。整数を変換するには を Boolean に変換すると、 Convert.ToBoolean を呼び出し、整数を渡します。ザ このメソッド呼び出しの戻り値は新しいブール値です 整数が 0 以外の場合は "true" に設定され、 それ以外の場合は "false"です。Convert クラスは、 正しい値を持つブール値。その他の種類 変換方法も同様に機能します。解析 Int32 と Double のメソッドは新しいインスタンスを返します これらのオブジェクトのうち、適切な値に設定されたオブジェクトのうち 文字列のみが与えられます。
新しいオブジェクトインスタンスを作成するためのこの戦略は、工場パターンとして知られています。オブジェクトのコンストラクターを呼び出すのではなく、オブジェクト工場にインスタンスを作成するように依頼することができます。そうすれば、工場のクラスは、オブジェクトの作成の複雑さを隠すことができます(文字列から二重を解析する方法など)。の詳細を変更したい場合 オブジェクトを作成するには、 工場自体。 コンストラクターが呼び出されるコード内のすべての場所を変更する必要はありません。
解決
実際のところ、彼らが提供した例は必ずしも素晴らしい例ではないと思います。
Factory パターンは、.NET でクラスを構築するときにさらに便利になります。たとえば、次を見てください。 WebRequest クラス.
このクラスは通常、以下を呼び出すことによってインスタンス化されます。
WebRequest request = WebRequest.Create(url);
の WebRequest.Create メソッドは Factory パターンを使用します。URL のタイプに応じて、異なるタイプ (サブクラス) の WebRequest が作成されます。それを渡すと、 http://
たとえば、実際に作成するのは HttpWebRequest インスタンス - ftp://
URL が作成します FtpWebRequest.
ここで Factory パターンを使用すると、クライアント側のコードを変更することなく、後でさらに多くの URL タイプを追加できます。別の URL を (文字列として) 渡して、新しいオブジェクトを取得するだけです。
他のヒント
工場に対する考え方全体が違うようです。これは実装の複雑さを隠すだけでなく、制御の反転 (IoC) にも当てはまります。
- 作成する代わりに
Sender
そしてReceiver
自分だけのオブジェクトを作りましょうMessageFactory
それらの作成を担当するオブジェクト。 - 最初に実装したと想像してみましょう
TcpMessageFactory
(MessageFactory
子孫) 作成TcpSender
そしてTcpReceiver
オブジェクト。これで、アプリケーションは TCP で動作するようになりました。 - 少し後、UDP の方が高速であることがわかりました。そこで私たちは実装しました
UdpSender
そしてUdpReciever
. 。さらに、私たちが実装したのは、UdpMessageFactory
(MessageFactory
子孫も同様) - これで、ユーザーが使用するプロトコルを選択できるようになりました。これに基づいて、ファクトリ オブジェクト (次のいずれか) を作成します。
TcpMessageFactory
またはUdpMessageFactory
) そしてそれをアプリケーションでさらに使用します。
この例では MessageFactory.CreateSender
そして MessageFactory.CreateReciever
抽象メソッドである必要があります。の方法 Sender
& Reciever
パブリック API (コントラクト) の形成も抽象的である必要があります。
ところで、当初ファクトリは主にオブジェクトの作成に使用されていました。メインの .exe に対して独自の型のセットを作成できるようにする必要がある C++ ライブラリ (DLL) を想像してください。インスタンスの構造は特定のコンパイラに依存するため、異なるモジュール間でインスタンスを渡すことはほとんど不可能です。ただし、インターフェイスを渡すことは可能です。したがって、そのような DLL は次のようにする必要があります。
- ファクトリインターフェイスを返す関数をエクスポートします。
IDllTypeFactory
- それを実装するオブジェクトは返さなければなりません
IDllTypeXxx
呼び出し時のオブジェクトCreateXxx
メソッド。これらIDllTypeXxx
実際には、当初エクスポートする予定だったタイプによって実装されます。
しかし、ご存知のとおり、統一されたアセンブリ形式を備えた .NET により、異なるモジュール間でオブジェクトを渡すことが可能になります。さらに、リフレクションにより、まったく知らないタイプを作成することができます。したがって、.NET のファクトリが使用されることはほとんどありません。
Factory Pattern は、私がプログラムで最もよく使用するパターンです。場合によっては非常に役立ちますが、使用する場合は注意が必要です。 ファクトリがコンストラクター オーバーロードのように見える場合は、おそらくコンストラクター オーバーロードであるはずです。 MSDN の記事で示されている例は適切ではありません。実際、私は長い間、Int や String などのオブジェクトは相互にオーバーロードを考慮していないと考えてきました。 構造体 構造体コンストラクターは、原則として、例外をスローすべきではありません (たとえば、「hello world」を int にフィードした場合に例外が発生します)。しかし、私はそう思っていました。
もちろん、ファクトリ パターンを使用するタイミングとその利点について、より適切な説明を見つけることができる場所は Web 上にたくさんあります。Reed が示した例は最高のものの 1 つであり、ファクトリーを使用するための私のルールに従っています。特定のインターフェイスを実装するクラス階層または多数のクラスがあり、それらのオブジェクトの 1 つを構築したいが、オブジェクト自体ではなくスーパークラス/インターフェイスのオブジェクトを受け取りたい場合に、ファクトリを使用します。そうすることで、ファクトリを呼び出しているオブジェクトが 実装の詳細について心配する必要はありません. 。これは、特定のクラスのオブジェクトを期待していることを認識しており、それがキャストである場合でも、それを取得します。
現在構築しているアプリケーション (プログラム ジェネレーター) では、データテーブル SQL 定義を解析する必要があります。これを行うには、自作のパーサーを使用します。パーサーが変数 (「IDENTIFIER VARIABLE-TYPE」) を検出するたびに、ファクトリを呼び出して文字列を渡します。次に、ファクトリは変数タイプの部分文字列をチェックし、私に返します。 SQL変数, 、それは実際には 整数Sql変数 または CharSql変数.
メインのパーサー オブジェクトは、どの変数を取得したかを知りません。SqlVariable をリストにプッシュし、次の行を読み取ります。もちろん、すべての変数タイプを処理する単一のクラスを作成することもできます。私は個人的にはそうしないことを選択しています。
はい、コンストラクターのオーバーロードを使用すると、ソース コードのすべての領域を変更せずにコンストラクターを変更できますが、十分に注意しないと、すぐに膨大な数のコンストラクターが必要になります。
この記事の一般的な考え方は、コンストラクターの変更を考慮して大規模なコンストラクターのオーバーロードを必ずしも防止するのではなく、実装を隠すというものだと思います。オブジェクトであるアイデアは、それがどのように構築されるかについての知識を持っていてはなりません。
この例では、文字列または double から int になる方法で Int クラスを詰まらせたくないので、Y パラメーターから X オブジェクトを作成することだけを担当するファクトリーを作成します。
デザイン パターンを学ぶための優れた入門書として、Head First Design Patterns の本をぜひお勧めします。例は Java ベースですが、その背後にあるロジックは、使用している言語に関係なく適用されます。