Factory method
パターンのWikiページには、次の例があります。
public interface IPerson
{
string GetName();
}
public class Villager : IPerson
{
public string GetName()
{
return "Village Person";
}
}
public class CityPerson : IPerson
{
public string GetName()
{
return "City Person";
}
}
public enum PersonType
{
Rural,
Urban
}
public class Factory
{
public IPerson GetPerson(PersonType type)
{
switch (type)
{
case PersonType.Rural:
return new Villager();
case PersonType.Urban:
return new CityPerson();
default:
throw new NotSupportedException();
}
}
}
ここでは、インスタンス化するオブジェクトを決定するためにPersonType
をオンに切り替えています。同じタイプの複数のオブジェクトからオブジェクトの作成を分離するためにFactory method
パターンを使用することは理にかなっていますが、上記のコードはopen-closed
の原則を満たしていません。新しいタイプのIPerson
があるときはいつでも、Factory
の実装に変更を加える必要があり、将来的に考えると、時間の経過とともにこのファクトリーメソッドはかなり大きくなる可能性があります。
Factory
パターンのもう1つのかなり一般的な例は、データベースのインスタンス化で、さまざまなデータベースサーバーから選択できます。この場合、設定ファイルを作成して、インスタンス化するデータベースを指定できます。また、複数の選択肢から1つのオブジェクトのみを作成するようなものです。上記のIPerson
の場合、複数の選択肢を持つ複数のオブジェクトをインスタンス化しています。 Factory
パターンは正しい選択ですか、それとも考えすぎですか?
上記のコードは、開閉の原則を満たしていません。新しいタイプのIPersonがあるときはいつでも、ファクトリーの実装に変更を加える必要があり、将来を考えると、時間の経過とともにこのファクトリーメソッドはかなり大きくなる可能性があります。
厳密にが開閉の原則に従っている場合、実際にはファクトリを変更しません。あなたはそれを拡張するでしょう。
たとえば、PersonType
という名前の新しいHomeless
を追加した場合、次のようにできます。
public class ExtendedFactory : Factory
{
public override IPerson GetPerson(PersonType type)
{
if (type == PersonType.Homeless) return new Hobo();
return base.GetPerson(type);
}
}
そうは言っても、この場合OCPに従うと本当に必要以上に複雑になるので、おそらく工場を適切に変更します。
はい、これは factory method の適切な例です:
GoF は、このパターンの実装のための2つの主要なバリアントを識別します。これは2番目のもので、Factory
はconcreteです。よりクリーンなバリアントは、抽象ファクトリメソッドをオーバーライドする具体的なファクトリを持つ抽象Factory
クラスです。
別のバリアントは、ファクトリメソッドの呼び出しに関するものです。基本的なパターンでは結合は作成されません。抽象Factory
クラスは依存関係の注入を目的としているため、具象メソッドは1種類の製品のみを返します。あなたの場合、それはparameterizedfactoryのより手の込んだバリアントです方法。
実際、具体化されたパラメーター化された実装により、ファクトリーとすべての専門分野の間のカップリングが作成されます。
オープン/クローズの原則 の意味でのより柔軟なアプローチは、すべての特殊化を動的に( 例 )ファクトリに登録させることです。次に、enum引数は動的ID(たとえば、登録時に返される)または文字列に置き換えられます。ただし、コードに不要な結合がなくなったとしても、ファクトリコンシューマとインスタンス化するクラスの間に依存関係が隠されています(使用できる引数を知っている必要があるため)。
オープンファクトリの原則に違反する静的ファクトリメソッドの懸念は、パターンがコードのメインサイドで使用されている場合、実際には懸念になりません。アプリケーション側で使用されている場合は、問題になる可能性があります。
コードがOpen-Close原則に従うと、コードはスケーラブルになります。ただし、複雑さも増します。したがって、開閉の原則に従うかどうかの決定は、トレードオフに基づいて実行する必要があります。コードを100%オープン/クローズにすると、複雑さが非常に高くなります。
アプリケーション(ビジネス)コードとメイン(ブートストラップ)コードにコードを分離することは、アプリケーション(Web、デスクトップ、埋め込みなど)の優れた設計です。
アプリケーション側コード
メインサイドコード
まとめ
静的ファクトリパターンは、通常、複雑さが低く、変更のコストも低いメインサイドコードで使用されます。
以下のクラス図は、視覚化に役立ちます。メイン側のクラス間の相互作用は示されていません。下の図では、bootstrappingMainとdependencyProjectはメインサイドコードと見なされます