回答:
私は自分のクラスを「人」であるという観点からデザインパターンについて考えるのが好きです。パターンは、人々がお互いに話す方法です。
ですから、私にとっては、工場のパターンは採用代理店のようなものです。可変数のワーカーを必要とする人がいます。この人は彼らが雇う人々に必要ないくつかの情報を知っているかもしれませんが、それだけです。
そのため、新しい従業員が必要になったとき、彼らは採用代理店に電話して、必要なものを伝えます。さて、実際に誰かを雇うには、多くのことを理解する必要があります-利点、適格性の検証など。しかし、雇用する人はこれを知る必要はありません-雇用機関がすべてを処理します。
同様に、ファクトリを使用すると、コンシューマは、作成方法や依存関係の詳細を知らなくても、新しいオブジェクトを作成できます。実際に必要な情報を提供するだけで済みます。
public interface IThingFactory
{
Thing GetThing(string theString);
}
public class ThingFactory : IThingFactory
{
public Thing GetThing(string theString)
{
return new Thing(theString, firstDependency, secondDependency);
}
}
そのため、ThingFactoryのコンシューマーはThingを取得できます。コンシューマーからの文字列データを除いて、Thingの依存関係を知る必要はありません。
within an object instead of a Factory class
。私は彼がctorをプライベートにし、静的メソッドを使用してクラスをインスタンス化する(オブジェクトを作成する)シナリオを意味したと思います。ただし、この例に従うには、ThingFactory
まずクラスをインスタンス化してThing
オブジェクトを取得する必要がありますFactory class
。これにより、これが有効になります。
ファクトリーメソッドは、コンストラクターの代替として考える必要があります-ほとんどの場合、コンストラクターが十分に表現力がない場合、
class Foo{
public Foo(bool withBar);
}
次のような表現力はありません:
class Foo{
public static Foo withBar();
public static Foo withoutBar();
}
ファクトリクラスは、オブジェクトを作成するための複雑なプロセスが必要な場合、実際のクラスには不要な依存関係を作成する必要がある場合、異なるオブジェクトを作成する必要がある場合などに役立ちます。
私が個人的に意味のある別個のFactoryクラスを見つけた1つの状況は、作成しようとしている最後のオブジェクトが他のいくつかのオブジェクトに依存している場合です。例えば、PHPで:あなたが持っていると仮定House
順番に持つオブジェクト、Kitchen
およびLivingRoom
オブジェクトを、そしてLivingRoom
オブジェクトがありTV
、オブジェクトの内部を同様。
これを実現する最も簡単な方法は、各オブジェクトがそれらの構築メソッドで子を作成することですが、プロパティが比較的ネストされているHouse
場合、作成に失敗すると、おそらく何が失敗しているのかを特定するためにある程度の時間を費やすことになります。
別の方法は、次のことを行うことです(ファンシー用語が好きな場合は、依存性注入):
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
ここで、作成プロセスがHouse
失敗した場合、確認する場所は1つだけですが、新しいチャンクが必要になるたびにこのチャンクを使用する必要があるのHouse
は、あまり便利ではありません。工場を入力してください:
class HouseFactory {
public function create() {
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
return $HouseObj;
}
}
$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();
ここのファクトリーのおかげで、を作成するプロセスHouse
は抽象化され(を作成したいだけのときにすべての依存関係を作成して設定する必要がないためHouse
)、同時に集中化されるため、保守が容易になります。別個のファクトリーを使用することが有益である理由は他にもあります(例えば、テスト容易性)が、この特定のユースケースを見つけて、ファクトリークラスがどのように役立つかを最もよく示しています。
HouseFactory
クラスにどの程度正確に渡されますか?
create
メソッドに渡す必要はありません。たとえば、House
常に同じ種類を使用LivingRoom
する場合は、引数として渡されるのではなく、ファクトリクラスでパラメータをハードコードする方が理にかなっています。または、数種類のがあり、内部にスイッチがあり、それぞれのタイプごとにパラメーターがハードコーディングされている場合は、メソッドにtype
引数を提供することもできます。HouseFactory::create
LivingRoom
ファクトリーまたはファクトリーメソッドを使用する背後にあるアイデアを明確に区別することが重要です。どちらも、相互に排他的な異なる種類のオブジェクト作成問題に対処するためのものです。
「ファクトリーメソッド」について具体的に説明しましょう。
最初に、ライブラリまたはAPIを開発していて、それをさらにアプリケーション開発に使用する場合、ファクトリーメソッドは作成パターンの最適な選択肢の1つです。背後にある理由。必要な機能のオブジェクトをいつ作成するかはわかりますが、オブジェクトのタイプは未定のままか、渡される動的パラメーターによって決定されます。
今のポイントは、ファクトリーパターン自体を使用してもほぼ同じことが達成できますが、ファクトリーパターンが上記の強調表示された問題に使用される場合、システムに大きな欠点が1つ導入されます。つまり、異なるオブジェクト(サブクラスオブジェクト)を作成するロジックが特定のビジネス状況に固有であるため、将来、他のプラットフォーム用にライブラリの機能を拡張する必要がある場合(より技術的には、基本インターフェースまたは抽象クラスのサブクラスを追加して、ファクトリが既存のオブジェクトに加えてそれらのオブジェクトも返すようにする必要があります)いくつかの動的パラメーターに基づいて)その後、ファクトリクラスのロジックを変更(拡張)する必要があるたびに、操作のコストが高くなり、設計の観点からは良くありません。逆に、「工法」なら
interface Deliverable
{
/*********/
}
abstract class DefaultProducer
{
public void taskToBeDone()
{
Deliverable deliverable = factoryMethodPattern();
}
protected abstract Deliverable factoryMethodPattern();
}
class SpecificDeliverable implements Deliverable
{
/***SPECIFIC TASK CAN BE WRITTEN HERE***/
}
class SpecificProducer extends DefaultProducer
{
protected Deliverable factoryMethodPattern()
{
return new SpecificDeliverable();
}
}
public class MasterApplicationProgram
{
public static void main(String arg[])
{
DefaultProducer defaultProducer = new SpecificProducer();
defaultProducer.taskToBeDone();
}
}
次の場合は、オブジェクト内でファクトリメソッドを使用することをお勧めします。
次の場合は、抽象ファクトリクラスを使用することをお勧めします。
からのUML
製品: Factoryメソッドが作成するオブジェクトのインターフェースを定義します。
ConcreteProduct: Productインターフェースを実装します
作成者: Factoryメソッドを宣言します
ConcreateCreator: Factoryメソッドを実装して、ConcreteProductのインスタンスを返します。
問題の説明:ゲームインターフェイスを定義するファクトリメソッドを使用して、ゲームのファクトリを作成します。
コードスニペット:
import java.util.HashMap;
/* Product interface as per UML diagram */
interface Game{
/* createGame is a complex method, which executes a sequence of game steps */
public void createGame();
}
/* ConcreteProduct implementation as per UML diagram */
class Chess implements Game{
public Chess(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Chess game");
System.out.println("Opponents:2");
System.out.println("Define 64 blocks");
System.out.println("Place 16 pieces for White opponent");
System.out.println("Place 16 pieces for Black opponent");
System.out.println("Start Chess game");
System.out.println("---------------------------------------");
}
}
class Checkers implements Game{
public Checkers(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Checkers game");
System.out.println("Opponents:2 or 3 or 4 or 6");
System.out.println("For each opponent, place 10 coins");
System.out.println("Start Checkers game");
System.out.println("---------------------------------------");
}
}
class Ludo implements Game{
public Ludo(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Ludo game");
System.out.println("Opponents:2 or 3 or 4");
System.out.println("For each opponent, place 4 coins");
System.out.println("Create two dices with numbers from 1-6");
System.out.println("Start Ludo game");
System.out.println("---------------------------------------");
}
}
/* Creator interface as per UML diagram */
interface IGameFactory {
public Game getGame(String gameName);
}
/* ConcreteCreator implementation as per UML diagram */
class GameFactory implements IGameFactory {
HashMap<String,Game> games = new HashMap<String,Game>();
/*
Since Game Creation is complex process, we don't want to create game using new operator every time.
Instead we create Game only once and store it in Factory. When client request a specific game,
Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
*/
public GameFactory(){
games.put(Chess.class.getName(),new Chess());
games.put(Checkers.class.getName(),new Checkers());
games.put(Ludo.class.getName(),new Ludo());
}
public Game getGame(String gameName){
return games.get(gameName);
}
}
public class NonStaticFactoryDemo{
public static void main(String args[]){
if ( args.length < 1){
System.out.println("Usage: java FactoryDemo gameName");
return;
}
GameFactory factory = new GameFactory();
Game game = factory.getGame(args[0]);
if ( game != null ){
game.createGame();
System.out.println("Game="+game.getClass().getName());
}else{
System.out.println(args[0]+ " Game does not exists in factory");
}
}
}
出力:
java NonStaticFactoryDemo Chess
---------------------------------------
Create Chess game
Opponents:2
Define 64 blocks
Place 16 pieces for White opponent
Place 16 pieces for Black opponent
Start Chess game
---------------------------------------
Game=Chess
この例は、Factory
を実装することによるクラスを示していFactoryMethod
ます。
Game
あらゆる種類のゲームのインターフェースです。それは複雑な方法を定義します:createGame()
Chess, Ludo, Checkers
ゲームのさまざまなバリアントであり、 createGame()
public Game getGame(String gameName)
あるFactoryMethod
中でIGameFactory
、クラス
GameFactory
コンストラクターでさまざまなタイプのゲームを事前に作成します。IGameFactory
ファクトリメソッドを実装しています。
ゲーム名はコマンドライン引数として渡されます NotStaticFactoryDemo
getGame
in GameFactory
はゲーム名を受け入れ、対応するGame
オブジェクトを返します。
工場:
インスタンス化ロジックをクライアントに公開せずにオブジェクトを作成します。
FactoryMethod
オブジェクトを作成するためのインターフェースを定義しますが、インスタンス化するクラスはサブクラスに決定させます。Factoryメソッドにより、クラスはインスタンス化をサブクラスに遅らせることができます
使用事例:
いつ使用するか:Client
実行時に作成する必要がある具体的なクラスがわからないが、仕事をするクラスを取得したいだけ。
getArea()
はファクトリーメソッドではありません。
それは本当に好みの問題です。ファクトリークラスは必要に応じて抽象化/インターフェース化できますが、ファクトリーメソッドは軽量です(定義された型がないため、テストしやすい傾向がありますが、サービスと同様に既知の登録ポイントが必要になります)ロケータですが、ファクトリメソッドの検索用です)。
ファクトリクラスは、返されるオブジェクトタイプにプライベートコンストラクタがある場合、異なるファクトリクラスが返されるオブジェクトに異なるプロパティを設定する場合、または特定のファクトリタイプが返される具象タイプと結合されている場合に役立ちます。
WCFはServiceHostFactoryクラスを使用して、さまざまな状況でServiceHostオブジェクトを取得します。IISは.svcファイルのServiceHostインスタンスを取得するために標準のServiceHostFactoryを使用しますが、JavaScriptクライアントにシリアル化を返すサービスにはWebScriptServiceHostFactoryを使用します。ADO.NET Data Servicesには独自の特別なDataServiceHostFactoryがあり、ASP.NETにはそのサービスにプライベートコンストラクターがあるため、ApplicationServicesHostFactoryがあります。
ファクトリを消費するクラスが1つしかない場合は、そのクラス内でファクトリメソッドを使用できます。
OrderおよびCustomerクラスを設計する必要があるシナリオを検討してください。簡素化と初期要件のために、Orderクラスのファクトリの必要性を感じず、アプリケーションに多くの「new Order()」ステートメントを入力します。物事はうまく機能しています。
ここで、CustomerアソシエーションなしではOrderオブジェクトをインスタンス化できない(新しい依存関係)という新しい要件が登場します。今、あなたは以下の考慮事項を持っています。
1-新しい実装でのみ機能するコンストラクタオーバーロードを作成します。(受け付けできません)。2-あなたはOrder()署名を変更し、すべての呼び出しを変更します。(良い習慣ではなく、本当の苦痛です)。
代わりに、注文クラスのファクトリを作成した場合は、コードを1行変更するだけで済みます。ほとんどすべての集合体の関連付けにはFactoryクラスをお勧めします。お役に立てば幸いです。
使用に関して別のオブジェクトを作成する場合。それは便利です。
public class factoryMethodPattern {
static String planName = "COMMERCIALPLAN";
static int units = 3;
public static void main(String args[]) {
GetPlanFactory planFactory = new GetPlanFactory();
Plan p = planFactory.getPlan(planName);
System.out.print("Bill amount for " + planName + " of " + units
+ " units is: ");
p.getRate();
p.calculateBill(units);
}
}
abstract class Plan {
protected double rate;
abstract void getRate();
public void calculateBill(int units) {
System.out.println(units * rate);
}
}
class DomesticPlan extends Plan {
// @override
public void getRate() {
rate = 3.50;
}
}
class CommercialPlan extends Plan {
// @override
public void getRate() {
rate = 7.50;
}
}
class InstitutionalPlan extends Plan {
// @override
public void getRate() {
rate = 5.50;
}
}
class GetPlanFactory {
// use getPlan method to get object of type Plan
public Plan getPlan(String planType) {
if (planType == null) {
return null;
}
if (planType.equalsIgnoreCase("DOMESTICPLAN")) {
return new DomesticPlan();
} else if (planType.equalsIgnoreCase("COMMERCIALPLAN")) {
return new CommercialPlan();
} else if (planType.equalsIgnoreCase("INSTITUTIONALPLAN")) {
return new InstitutionalPlan();
}
return null;
}
}
処理する必要があるオブジェクトのサブクラスにオブジェクトの作成を延期するクラスは、ファクトリパターンの例と見なすことができます。
https://stackoverflow.com/a/49110001/504133の別の回答で詳細に言及しました
私はあなたがあなたのコードに持ち込みたい疎結合度に依存すると思います。
ファクトリメソッドは物事を非常にうまく分離しますが、ファクトリクラスはそうではありません。
つまり、ファクトリメソッドを使用する方が、単純なファクトリ(ファクトリクラスと呼ばれる)を使用するよりも変更が簡単です。
この例を見てください:https : //connected2know.com/programming/java-factory-pattern/。今、あなたは新しい動物を連れて行きたいと想像してください。FactoryクラスではFactoryを変更する必要がありますが、factoryメソッドでは、新しいサブクラスを追加するだけで済みます。
私は工場を図書館の概念にたとえています。たとえば、数値を処理するためのライブラリと、図形を処理するためのライブラリを用意できます。これらのライブラリの関数は、論理的に名前が付けられたディレクトリに、Numbers
またはShapes
ます。これらは、形状の場合、整数、フロート、ドーブル、ロングまたは長方形、円、三角形、五角形を含むことができる一般的なタイプです。
ファクトリペッターは、ポリモーフィズム、依存関係の注入、および制御の反転を使用します。
ファクトリーパターンの目的は次のとおりです。 Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
したがって、オペレーティングシステムまたはフレームワークを構築していて、すべての個別コンポーネントを構築しているとしましょう。
PHPのFactoryパターンの概念の簡単な例を次に示します。私はそれのすべてで100%ではないかもしれませんが、それは簡単な例として役立つことを意図しています。私は専門家ではありません。
class NumbersFactory {
public static function makeNumber( $type, $number ) {
$numObject = null;
$number = null;
switch( $type ) {
case 'float':
$numObject = new Float( $number );
break;
case 'integer':
$numObject = new Integer( $number );
break;
case 'short':
$numObject = new Short( $number );
break;
case 'double':
$numObject = new Double( $number );
break;
case 'long':
$numObject = new Long( $number );
break;
default:
$numObject = new Integer( $number );
break;
}
return $numObject;
}
}
/* Numbers interface */
abstract class Number {
protected $number;
public function __construct( $number ) {
$this->number = $number;
}
abstract public function add();
abstract public function subtract();
abstract public function multiply();
abstract public function divide();
}
/* Float Implementation */
class Float extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Integer Implementation */
class Integer extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Short Implementation */
class Short extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Double Implementation */
class Double extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Long Implementation */
class Long extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
$number = NumbersFactory::makeNumber( 'float', 12.5 );
NumbersFactory::makeNumber( 'float', 12.5 );
だけ言っオーバー私を与えるnew Float(12.5);
、私は私が必要と知っていればFloat
?これは私が工場について理解していないことです...ポイントは何ですか?