ファクトリー・パターンは、Java で最もよく使われるデザイン・パターンの 1 つです。このタイプのデザイン・パターンは作成パターンで、オブジェクトを作成する最適な方法を提供します。ファクトリーパターンでは、作成ロジックをクライアントに公開することなく、新しく作成されたオブジェクトを指す共通のインターフェースを使用してオブジェクトを作成します。
はじめに
意図: オブジェクトを作成するためのインターフェイスを定義し、どのファクトリークラスをインスタンス化するかサブクラス自身に決定させます。
プライマリー・ソリューション:インターフェース選択のためのプライマリー・ソリューション
使用する場合:異なる条件下で異なるインスタンスを作成する場合に明示的に計画します。
解決方法:サブクラスにファクトリー・インターフェースを実装させ、抽象化された製品を返すようにします。
キーコード:作成プロセスはサブクラスで実行されます。
アプリケーションの例
- 車が必要であれば、その車がどのように作られ、車内に何が実装されているかを心配することなく、工場から直接受け取ることができます。
- Hibernate データベースを変更するには、方言とドライバを変更するだけです。
長所:
- オブジェクトを作成したい呼び出し元は、単にその名前を知っているだけです。
- 製品を追加したい場合は、ファクトリークラスを拡張するだけです。
- 製品の具体的な実装をマスクすることで、呼び出し元は製品のインターフェイスにのみ注意を払います。
デメリット:商品を追加するたびに、具象クラスとオブジェクト実装ファクトリーを追加する必要があるため、システム内のクラス数が指数関数的に増加し、システムの複雑性がある程度増加し、システムの具象クラスへの依存度も増加します。
使用シナリオ
- ロガー:記録はローカルハードディスク、システムイベント、リモートサーバーなどに記録されます。
- データベースへのアクセス。最終システムで使用されるデータベースの種類が不明な場合や、データベースに変更が加えられる可能性がある場合。
- POP3"、"IMAP"、"HTTP "の3つのプロトコルが必要です。
注意:生成パターンとして、ファクトリーメソッドパターンは複雑なオブジェクトを生成する必要があればどこでも使うことができます。注意点としては、複雑なオブジェクトはファクトリーパターンに適していますが、単純なオブジェクト、特にnewだけで生成できるオブジェクトはファクトリーパターンを使う必要はありません。ファクトリーパターンを使う場合は、ファクトリークラスを導入する必要があり、システムの複雑さが増します。
第二に、ファクトリーモデルの3つの形態
- シンプル・ファクトリー・パターン:スタティック・ファクトリー・メソッド・パターンとしても知られています。
- ファクトリーメソッドパターン:ポリモーフィックファクトリーパターン、仮想コンストラクタパターンとも呼ばれます。
- Abstract Factoryパターン:Toolboxパターンとしても知られています。
シンプルなファクトリーパターン
Simple Factory パターンは作成ベースのデザイン・パターンであり、23 の Gof デザイン・パターンの 1 つではありません。
定義: Simple Factory パターンは作成ベースのデザインパターンで、静的ファクトリーメソッドパターンとしても知られています。
気付く
シナリオ説明: 例えば、様々な種類の果物を専門に販売している農園があるとします。このシステムでは以下の果物を説明する必要があります。
- ブドウ
- ストロベリー
- Apple アップル
/**
* すべての果物に適用されるインターフェイスを定義し、すべての果物が持たなければならないメソッドを定義する:
* plantplant、harvestharvest()
*/
public interface Fruit {
//
void plant();
//
void grow();
//
void harvest();
default void log(String message){
System.out.println(message);
}
}
/**
*
*/
public class Apple implements Fruit {
//
private Integer treeAge;
@Override
public void plant() {
log("Apple工場を立ち上げる...");
}
@Override
public void grow() {
log("Apple成長を始める...");
}
@Override
public void harvest() {
log("Apple受信を開始する...");
}
public Integer getTreeAge() {
return treeAge;
}
public void setTreeAge(Integer treeAge) {
this.treeAge = treeAge;
}
}
/**
* 果物の生産を担当するファクトリークラス
*/
public class FruitFactory {
public static Fruit getFruit(String type) {
switch (type) {
case "apple":
return new Apple();
default:
throw new RuntimeException("ファームにはこの果実がない」)。;
}
}
}
テスト:出力:特徴:これは具象クラスで、非インタフェース、抽象クラスです。重要なgetFruit()メソッドがあります。
長所:
- デカップリング:要求クラスと実装クラスを分離し、ファクトリークラスを通じて相互作用することで、責任の分担を可能にします。
- サブクラスの追加、変更、削除は簡単で、他のクラスに影響を与えません。
- 再利用、サブクラスは複数回再利用可能
欠点:
- スケーラビリティの悪さ
- 製品によって必要な追加パラメータが異なる場合はサポートされません。
- オープン・クローズの原則との矛盾:延長にはオープン、修正にはクローズ
ファクトリーメソッドパターン
オブジェクトを生成するためのインターフェイスを提供し、その実装クラスがインスタンス化するクラスを決定し、その実装クラスが対応するクラスのインスタンスを生成します。
役割それはある程度まで切り離すことができ、消費者と製品の実装クラスは分離され、唯一の製品のインターフェイスに依存し、製品の実装クラスが変更される方法は、消費者から完全に独立しています。
ある程度スケーラビリティを向上させることができます、あなたが製品の実装を追加した場合、あなたは唯一の製品のインターフェイスを実装する必要があり、製品のメソッドを作成するファクトリを変更し、コンシューマは、非受容することができます。ある程度のカプセル化とコードの可読性を高めることができます。明確なコード構造は、消費者のために非常に少量のコードが多くの作業を行うことができます。また、抽象ファクトリは、ファクトリパターンの実際の意味であり、ファクトリメソッドは、抽象ファクトリのより一般的なケースです。
適用可能なシナリオ
コンシューマが作成したいオブジェクトのクラスを気にしない場合。
コンシューマが作成したいオブジェクトのクラスは知っているが、作成方法は知らない場合。
気付く
商品クラスへのインタフェースを提供します。製品クラスはすべてこのインタフェースを実装します。ファクトリ・クラスへのインタフェースを提供します。ファクトリ・クラスはこのインタフェースを実装します。ファクトリ実装クラスから製品クラスのインスタンスを作成します。ファクトリ実装クラスは、製品クラスをインスタンス化するメソッドを持つ必要があります。
/**
* ファクトリーインターフェイス
*/
public interface IMessageFactory {
public IMessage createMessage(String messageType);
}
/**
* 製品インターフェース
*/
public interface IMessage {
public Map<String, Object> getMessageParam();
public void setMessageParam(Map<String, Object> messageParam);
public void sendMesage() throws Exception;
}
/**
* 仮想製品クラス
*/
public abstract class AbstractMessage implements IMessage {
private Map<String, Object> messageParam;
@Override
public Map<String, Object> getMessageParam() {
return messageParam;
}
@Override
public void setMessageParam(Map<String, Object> messageParam) {
this.messageParam = messageParam;
}
}
/**
* メール製品クラス
*/
public class EmailMessage extends AbstractMessage {
@Override
public void sendMesage() throws Exception {
// TODO Auto-generated method stub
if (null == getMessageParam() || null == getMessageParam().get("EMAIL")
|| "".equals(getMessageParam().get("EMAIL"))) {
throw new Exception("SMSを送信するには、EMAILパラメータを渡す必要がある");
}
System.out.println("メールでの通知は、" + getMessageParam().get("EMAIL"));
}
}
/**
* SMS製品クラス
*/
public class SmsMessage extends AbstractMessage {
@Override
public void sendMesage() throws Exception {
if (null == getMessageParam()
|| null == getMessageParam().get("PHONENUM")
|| "".equals(getMessageParam().get("PHONENUM"))) {
throw new Exception("SMSを送信するには、PHONENUMパラメータを渡す必要がある");
}
System.out.println("SMSで、" + getMessageParam().get("PHONENUM"));
}
}
/**
* ファクトリーの実装
*/
public class MessageFactory implements IMessageFactory {
@Override
public IMessage createMessage(String messageType) {
// どの製品を生産するかはファクトリーに任されているのであれば、生産を制御するために渡されるパラメーターはないはずだ。
IMessage message;
Map<String, Object> messageParam = new HashMap<String, Object>();
// どの具体的な実装を作成するかは、ある条件に基づいて選択される。この条件は、渡されるか、他のソースから取得することができる。
// sms
if ("SMS".equals(messageType)) {
message = new SmsMessage();
messageParam.put("PHONENUM", "123456789");
} else {
message = new EmailMessage();
messageParam.put("EMAIL", "123456@MSN.com");
}
message.setMessageParam(messageParam);
return message;
}
}
テスト:出力結果:
抽象ファクトリーパターン
特定のクラスを指定することなく、関連または相互依存するオブジェクトのセットを作成するためのインターフェイスを提供します。
ファクトリーメソッドパターンとの違い
Abstract Factory パターンは、Factory Method パターンを更新したもので、関連する、または相互に依存するオブジェクトのセットを作成するために使用されます。
- ファクトリーメソッドパターンは単一の製品階層を対象とし、抽象ファクトリーパターンは複数の製品階層を対象とします。プログラミングでは、製品階層は通常インターフェースまたは抽象クラスとして表現されます。つまり、ファクトリーメソッドパターンが提供する製品はすべて同じインターフェースまたは抽象クラスから派生するのに対し、抽象ファクトリーパターンが提供する製品は異なるインターフェースまたは抽象クラスから派生します。
- 抽象ファクトリパターンには製品ファミリという概念があります。製品ファミリとは、異なる製品階層に位置する機能的に関連する製品のファミリです。抽象ファクトリパターンによって提供される製品の集合は製品ファミリを形成し、ファクトリメソッドによって提供される製品の集合は階層と呼ばれます。
適用シナリオ
- クライアントは、製品クラスのインスタンスがどのように作成され、実装されるかなどの詳細には依存しません。
- 関連する製品オブジェクトを組み合わせて使用することを重視 オブジェクトの作成には、多くの反復コードが必要
- クライアントが特定の実装に依存しないように、製品クラスのライブラリを提供します。
製品階層と製品ファミリーをよりよく理解するために、2つの図を見てください。 横の行が製品ファミリーで、縦の列が製品階層です。
気付く
ビジネスシナリオ:今、あなたは、Javaの手書きのメモ、Pythonの手書きのメモなど、ビデオだけでなく、手書きのメモを記録する必要がある場合は、ファクトリモデルに従って、Javaの手書きのメモクラス、Pythonの手書きのメモクラス、Javaの手書きのメモ工場、Pythonの手書きのメモ工場、手書きのメモ工場クラスを作成する必要があります、それは非常にクラスの爆発的な状況が発生するのは簡単です。Javaのビデオの1つは、pythonのビデオは、製品のクラスは、Javaのハンドブック、pythonのハンドブック、製品のクラスは、JavaのビデオとJavaのハンドブック同じ製品ファミリですビデオです。
//手書きファクトリー
public abstract class Article {
public abstract void produce();
}
//
public abstract class Video {
public abstract void produce();
}
//Java手書きファクトリー
public class JavaArticle extends Article {
@Override
public void produce() {
System.out.println("Javaコースハンドブックを書く");
}
}
//Java
public class JavaVedio extends Video {
@Override
public void produce() {
System.out.println("記録されたJavaコース");
}
}
//Python手書きファクトリー
public class PythonArticle extends Article {
@Override
public void produce() {
System.out.println("Pythonコースを書くためのハンドブック");
}
}
//Python
public class PythonVideo extends Video{
@Override
public void produce() {
System.out.println("記録されたPythonレッスン");
}
}
//抽象ファクトリー
public interface CourseFactory {
Video getVideo();
Article getArticle();
}
テスト:出力結果:
長所:
- 製品固有のコードはアプリケーション・レベルで分離されているため、詳細を作成する心配はありません。
- さまざまな製品ファミリーを統合して
- 主な利点は、製品ファミリは、クラス内で制約することができる、いわゆる製品ファミリは、一般的に多かれ少なかれ、特定の関連付けがある、抽象的な工場のパターンを定義し、特に管理するために新しいクラスを導入することなく、関連付けの製品ファミリのクラス内で記述することができます。
欠点:
- 新しい製品で製品ファミリーを拡張するのは難しく、抽象ファクトリーインターフェースを変更する必要があります。
- 抽象度が高まり、システムの理解が困難に
- 製品ファミリーの拡張は非常に手間のかかるもので、もし新しい製品を製品ファミリーに追加する必要がある場合、ほとんどすべてのファクトリークラスを変更する必要があります。