ホームページ Java &#&チュートリアル ファクトリ メソッド パターンを理解する

ファクトリ メソッド パターンを理解する

Jan 05, 2025 am 10:49 AM

Understanding the Factory Method Pattern

導入

皆さん、こんにちは。私はデザイン パターンについて学び続けているので、私の知識を共有するためにこの投稿を書いています。今日は、実際のアプリケーションで一般的に使用されるデザイン パターンであるファクトリー メソッド パターンを紹介します。私の投稿に間違いがある場合は、お気軽に以下にコメントしてください。喜んで修正して更新します。

ファクトリ メソッド パターンは、スーパークラスでオブジェクトを作成するためのインターフェイスを提供しますが、サブクラスは作成されるオブジェクトのタイプを変更できます。

問題

銀行アプリケーションがあり、銀行振込、PayPal 振込などのさまざまな方法で送金するための機能を構築しているとします。

ファクトリー メソッド パターンを使用する前に、それを使用しないシナリオを調べてみましょう。

Java で実装された例を示します。

状況: 人物 1 が振込方法 (銀行振込または PayPal 振込) を使用して人物 2 に送金します。

フォルダー構造:

problem/
├─ BankApp.java
├─ service/
│  ├─ PaypalTransferPayment.java
│  ├─ BankTransferPayment.java
├─ data/
│  ├─ Person.java
ログイン後にコピー
ログイン後にコピー

メイン アプリケーションで、デフォルトの金額を持つ 2 人の人物を作成します。

package problem;

import problem.data.Person;

public class BankApp {
    public static void main(String[] args) {
        Person person1 = new Person("John", 1000);
        Person person2 = new Person("Jane", 500);
    }
}
ログイン後にコピー
ログイン後にコピー

BankTransferPayment クラスと PaypalTransferPayment クラスを作成します。

package problem.service;

import problem.data.Person;

public class BankTransferPayment {
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Bank transfer payment success.");
    }
}
ログイン後にコピー
ログイン後にコピー
package problem.service;

import problem.data.Person;

public class PaypalPayment {
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Paypal transfer payment success.");
    }
}
ログイン後にコピー

メイン関数にロジックを実装します。

package problem;

import problem.data.Person;
import problem.service.BankTransferPayment;
import problem.service.PaypalPayment;

public class BankApp {
    public static void main(String[] args) {
        Person person1 = new Person("John", 1000);
        Person person2 = new Person("Jane", 500);

        String paymentMethod = "BANK_TRANSFER";

        if (paymentMethod.equals("BANK_TRANSFER")) {
            BankTransferPayment bankTransferPayment = new BankTransferPayment();
            bankTransferPayment.processPayment(person1, person2, 100);

            System.out.println("===Method bank_transfer===");
            System.out.println(person1.getName() + " has " + person1.getAmount());
            System.out.println(person2.getName() + " has " + person2.getAmount());
        } else if (paymentMethod.equals("PAYPAL")) {
            PaypalPayment paypalPayment = new PaypalPayment();
            paypalPayment.processPayment(person1, person2, 100);

            System.out.println("===Method paypal===");
            System.out.println(person1.getName() + " has " + person1.getAmount());
            System.out.println(person2.getName() + " has " + person2.getAmount());
        }
    }
}

ログイン後にコピー

現在の実装の問題:

  1. 反復コード: processPayment メソッドのロジックは、支払い方法ごとに繰り返されます。
  2. 密結合コード: アプリケーションは支払い方法オブジェクト自体を作成する必要があるため、アプリケーションの拡張が困難になります。
  3. スケーラビリティの問題: 新しい支払い方法が追加されると、ソース コードがより複雑になり、保守が困難になります。

解決

上記の状況の解決策は、ファクトリ メソッド パターンを使用することです。では、それをどのように適用すればよいでしょうか?

上記の例では:

  1. 各 if-else ブロックは processPayment メソッドを呼び出すため、コードの繰り返しが発生します。
  2. オブジェクトは支払いタイプの条件に基づいて作成されるため、過剰な if-else ステートメントでコードが複雑になります。

これらの問題を解決するために、Factory Method パターンが段階的に実装されます。

フォルダー構造 (ソリューション):

solution/
├─ BankApp.java
├─ service/
│  ├─ payments/
│  │  ├─ Payment.java
│  │  ├─ PaymentFactory.java
│  │  ├─ BankTransferPayment.java
│  │  ├─ PaypalTransferPayment.java
├─ data/
│  ├─ Person.java
ログイン後にコピー

ステップ 1: Payment インターフェースを作成し、共通メソッド processPayment を宣言します

package solution.service.payments;

import solution.data.Person;

// Step 1: Create an interface for the payment
public interface Payment {
    void processPayment(Person fromAccount, Person toAccount,float amount);
}
ログイン後にコピー

ステップ 2: Payment インターフェイスを実装する BankTransferPayment クラスと PaypalTransferPayment クラスを作成します。

package solution.service.payments;

import solution.data.Person;

// Step 2: Create a class that implements the Payment interface
public class BankTransferPayment implements Payment {
    @Override
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Bank transfer payment success.");
    }
}
ログイン後にコピー
package solution.service.payments;

import solution.data.Person;

public class PaypalPayment implements Payment{
    @Override
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Paypal transfer payment success.");
    }
}
ログイン後にコピー

ステップ 3: PaymentFactory クラスを作成します。このクラスは、支払いタイプの条件に基づいてオブジェクトを作成する役割を果たします。

package solution.service.payments;

public class PaymentFactory {
    public Payment createPayment(String paymentType) {
        if (paymentType == null) {
            return null;
        }
        if (paymentType.equalsIgnoreCase("BANK_TRANSFER")) {
            return new BankTransferPayment();
        } else if (paymentType.equalsIgnoreCase("PAYPAL")) {
            return new PaypalPayment();
        }
        return null;
    }
}
ログイン後にコピー

ステップ 4: メイン アプリケーションでファクトリを使用します。

ファクトリ メソッド パターンを使用するように main 関数を変更します。

problem/
├─ BankApp.java
├─ service/
│  ├─ PaypalTransferPayment.java
│  ├─ BankTransferPayment.java
├─ data/
│  ├─ Person.java
ログイン後にコピー
ログイン後にコピー

ファクトリ メソッド パターンを使用する利点

  • コードはよりクリーンで、より構造化されています。
  • 複数の if-else ブロックでの processPayment への繰り返しの呼び出しは 排除されます
  • オブジェクトの作成はファクトリーに委任され、保守性が向上します。

ボーナス

PaymentFactory クラスをオープン/クローズ原則 (SOLID 原則から) に準拠させるには、戦略パターン を使用して動的登録メカニズムを実装できます。

PaymentFactory.java を更新しました:

package problem;

import problem.data.Person;

public class BankApp {
    public static void main(String[] args) {
        Person person1 = new Person("John", 1000);
        Person person2 = new Person("Jane", 500);
    }
}
ログイン後にコピー
ログイン後にコピー

メイン アプリケーションで更新されたファクトリーを使用します。

package problem.service;

import problem.data.Person;

public class BankTransferPayment {
    public void processPayment(Person fromAccount, Person toAccount, float amount) {
        fromAccount.withdraw(amount);
        toAccount.deposit(amount);
        System.out.println("Bank transfer payment success.");
    }
}
ログイン後にコピー
ログイン後にコピー

このアプローチを適用することで、コードは オープン/クローズの原則 に準拠し、PaymentFactory ロジックを変更せずに新しい支払い方法を追加できるようになります。

この投稿がお役に立てば幸いです。

参考文献:

第一人者のデザインパターン

以上がファクトリ メソッド パターンを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

会社のセキュリティソフトウェアはアプリケーションの実行に失敗していますか?それをトラブルシューティングと解決する方法は? 会社のセキュリティソフトウェアはアプリケーションの実行に失敗していますか?それをトラブルシューティングと解決する方法は? Apr 19, 2025 pm 04:51 PM

一部のアプリケーションが適切に機能しないようにする会社のセキュリティソフトウェアのトラブルシューティングとソリューション。多くの企業は、内部ネットワークセキュリティを確保するためにセキュリティソフトウェアを展開します。 ...

名前を数値に変換してソートを実装し、グループの一貫性を維持するにはどうすればよいですか? 名前を数値に変換してソートを実装し、グループの一貫性を維持するにはどうすればよいですか? Apr 19, 2025 pm 11:30 PM

多くのアプリケーションシナリオでソートを実装するために名前を数値に変換するソリューションでは、ユーザーはグループ、特に1つでソートする必要がある場合があります...

MapsTructを使用したシステムドッキングのフィールドマッピングの問題を簡素化する方法は? MapsTructを使用したシステムドッキングのフィールドマッピングの問題を簡素化する方法は? Apr 19, 2025 pm 06:21 PM

システムドッキングでのフィールドマッピング処理は、システムドッキングを実行する際に難しい問題に遭遇することがよくあります。システムのインターフェイスフィールドを効果的にマッピングする方法A ...

エンティティクラス変数名をエレガントに取得して、データベースクエリ条件を構築する方法は? エンティティクラス変数名をエレガントに取得して、データベースクエリ条件を構築する方法は? Apr 19, 2025 pm 11:42 PM

データベース操作にMyBatis-Plusまたはその他のORMフレームワークを使用する場合、エンティティクラスの属性名に基づいてクエリ条件を構築する必要があることがよくあります。あなたが毎回手動で...

Intellijのアイデアは、ログを出力せずにSpring Bootプロジェクトのポート番号をどのように識別しますか? Intellijのアイデアは、ログを出力せずにSpring Bootプロジェクトのポート番号をどのように識別しますか? Apr 19, 2025 pm 11:45 PM

intellijideaultimatiateバージョンを使用してスプリングを開始します...

Javaオブジェクトを配列に安全に変換する方法は? Javaオブジェクトを配列に安全に変換する方法は? Apr 19, 2025 pm 11:33 PM

Javaオブジェクトと配列の変換:リスクの詳細な議論と鋳造タイプ変換の正しい方法多くのJava初心者は、オブジェクトのアレイへの変換に遭遇します...

Redisキャッシュソリューションを使用して、製品ランキングリストの要件を効率的に実現する方法は? Redisキャッシュソリューションを使用して、製品ランキングリストの要件を効率的に実現する方法は? Apr 19, 2025 pm 11:36 PM

Redisキャッシュソリューションは、製品ランキングリストの要件をどのように実現しますか?開発プロセス中に、多くの場合、ランキングの要件に対処する必要があります。

eコマースプラットフォームSKUおよびSPUデータベースデザイン:ユーザー定義の属性と原因のない製品の両方を考慮する方法は? eコマースプラットフォームSKUおよびSPUデータベースデザイン:ユーザー定義の属性と原因のない製品の両方を考慮する方法は? Apr 19, 2025 pm 11:27 PM

eコマースプラットフォーム上のSKUおよびSPUテーブルの設計の詳細な説明この記事では、eコマースプラットフォームでのSKUとSPUのデータベース設計の問題、特にユーザー定義の販売を扱う方法について説明します。

See all articles