【インタビュー特集】デザインパターン①

1.工場設計パターン

ファクトリ デザイン パターンは、オブジェクトを作成するためのインターフェイスを提供する作成パターンですが、作成されるオブジェクトの特定のタイプは実行時に決定できます。ファクトリ デザイン パターンは、主にオブジェクト作成時の柔軟性の問題を解決します。

ファクトリ設計パターンには主に、単純ファクトリパターン、ファクトリメソッドパターン、抽象ファクトリパターンの 3 種類があります。

  1. 単純なファクトリ パターン: 他のクラスのインスタンスの作成を担当するクラスを明確に定義することにより、作成されたインスタンスは通常、共通の親クラスを持ちます。このモデルは、静的ファクトリ メソッド モデルとも呼ばれる革新的なクラス モデルに属します。単純な工場モデルは「開閉原則」に大きく違反しており、拡張するのが困難です。
  2. ファクトリ メソッド パターン: 製品オブジェクトを作成するファクトリ インターフェイスを定義し、実際の作成作業をサブクラスに延期します。コア ファクトリ クラスは製品の作成を担当しなくなり、コア クラスは抽象ファクトリの役割となり、特定のファクトリ サブクラスが実装する必要があるインターフェイスのみを担当します。このさらなる抽象化の利点は、ファクトリ メソッド パターンにより、システムが特定のファクトリの役割を変更せずに新しい製品を導入できることです。
  3. 抽象ファクトリー パターン: スーパー ファクトリーの周囲に他のファクトリーを作成します。ギガファクトリーは他の工場の工場としても知られています。

単純な工場パターン:

//抽象产品
interface Product {
    void doSomething();
}
 
//具体产品1
class ConcreteProduct1 implements Product {
    @Override
    public void doSomething() {
        System.out.println("具体产品1");
    }
}
 
//具体产品2
class ConcreteProduct2 implements Product {
    @Override
    public void doSomething() {
        System.out.println("具体产品2");
    }
}
 
//工厂类
class Factory{
    public static Product createProduct(int type) {
        switch (type) {
            case 1:
                return new ConcreteProduct1();
            case 2:
                return new ConcreteProduct2();
            default:
                return null;
        }
    }
}
 
//测试类
public class Test {
    public static void main(String[] args) {
        Factory.createProduct(1).doSomething();//输出具体产品1
        Factory.createProduct(2).doSomething();//输出具体产品2
    }
}

ファクトリメソッドパターン:

//抽象产品
interface Product{
    void doSomething();
}
 
//具体产品1
class ConcreteProduct1 implements Product{
    @Override
    public void doSomething() {
        System.out.println("具体产品1");
    }
}
 
//具体产品2
class ConcreteProduct2 implements Product{
    @Override
    public void doSomething() {
        System.out.println("具体产品2");
    }
}
 
//抽象工厂
interface Factory {
    Product createProduct();
}
 
//具体工厂1
class ConcreteFactory1 implements Factory{
    @Override
    public Product createProduct() {
        return new ConcreteProduct1();
    }
}
 
//具体工厂2
class ConcreteFactory2 implements Factory{
    @Override
    public Product createProduct() {
        return new ConcreteProduct2();
    }
}
 
//测试类
public class Test {
    public static void main(String[] args) {
        Factory factory1 = new ConcreteFactory1();
        factory1.createProduct().doSomething(); //输出具体产品1
        Factory factory2 = new ConcreteFactory2();
        factory2.createProduct().doSomething(); //输出具体产品2
    }
}

抽象的な工場パターン:

//抽象产品A
interface ProductA{
    void doSomething();
}
 
//具体产品A1
class ConcreteProductA1 implements ProductA{
    @Override
    public void doSomething() {
        System.out.println("具体产品A1");
    }
}
 
//具体产品A2
class ConcreteProductA2 implements ProductA{
    @Override
    public void doSomething() {
        System.out.println("具体产品A2");
    }
}
 
//抽象产品B
interface ProductB{
    void doSomething();
}
 
//具体产品B1
class ConcreteProductB1 implements ProductB{
    @Override
    public void doSomething() {
        System.out.println("具体产品B1");
    }
}
 
//具体产品B2
class ConcreteProductB2 implements ProductB{
    @Override
    public void doSomething() {
        System.out.println("具体产品B2");
    }
}
 
//抽象工厂
interface AbstractFactory{
    ProductA createProductA();
    ProductB createProductB();
}
 
//具体工厂1
class ConcreteFactory1 implements AbstractFactory{
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}
 
//具体工厂2
class ConcreteFactory2 implements AbstractFactory{
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }
    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}
 
//测试类
public class Test {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        factory1.createProductA().doSomething(); //输出具体产品A1
        factory1.createProductB().doSomething(); //输出具体产品B1
        AbstractFactory factory2 = new ConcreteFactory2();
        factory2.createProductA().doSomething(); //输出具体产品A2
        factory2.createProductB().doSomething(); //输出具体产品B2
    }
}

2.戦略モード

戦略パターンは、アルゴリズムの動作を実行時に選択できるようにする動作設計パターンです。 Java では、インターフェイスと抽象クラスを通じて戦略パターンを実装できます。以下は、Strategy パターンを Java でどのように記述するかを示す簡単な例です。

まず、ポリシー アルゴリズムのメソッドを定義するインターフェイスを定義します。

public interface Strategy {
    int execute(int num1, int num2);
}

次に、このインターフェイスを実装するさまざまなポリシー クラスを作成します。

public class Add implements Strategy {
    public int execute(int num1, int num2) {
        return num1 + num2;
    }
}

public class Subtract implements Strategy {
    public int execute(int num1, int num2) {
        return num1 - num2;
    }
}

public class Multiply implements Strategy {
    public int execute(int num1, int num2) {
        return num1 * num2;
    }
}

次に、メイン プログラムで、指定された戦略を使用してアルゴリズムを実行する Context クラスを作成します。

public class Context {

    private Strategy strategy;

    public Context(Strategy strategy) {
        this.strategy = strategy;
    }

    public int executeStrategy(int num1, int num2) {
        return strategy.execute(num1, num2);
    }
}

最後に、さまざまな戦略をインスタンス化し、Context クラスに渡します。

public class StrategyPatternExample {

    public static void main(String[] args) {
        Context context = new Context(new Add());
        System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

        context = new Context(new Subtract());
        System.out.println("10 - 5 = " + context.executeStrategy(10, 5));

        context = new Context(new Multiply());
        System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
    }
}

出力:

10 + 5 = 15
10 - 5 = 5
10 * 5 = 50

この例では、実行時にアルゴリズムの動作を選択できるようにする Strategy パターンを実装する方法を示します。

3. ストラテジーモード + ファクトリーモードでログインを実現

ファクトリ メソッド パターンは、特定のオブジェクト インスタンスの作成を担当するファクトリ クラスにオブジェクトの作成を委任する作成パターンです。戦略パターンは、一連のアルゴリズムを定義し、相互に交換できるように各アルゴリズムをカプセル化する動作パターンです。

ファクトリ メソッド パターンを通じて、入力パラメータに基づいて対応するポリシー オブジェクトを作成し、そのポリシー オブジェクトを通じてログイン機能を実装できます。具体的な実装は以下の通りです。

1. ポリシーインターフェイスを作成し、ログイン方法を定義します。

public interface LoginStrategy {
    boolean login(String username, String password);
}

2. 特定のポリシー実装クラスを作成し、ログイン メソッドを実装します。

public class EmailLoginStrategy implements LoginStrategy {
    @Override
    public boolean login(String username, String password) {
        // 基于邮箱的登录逻辑
        return true;
    }
}

public class PhoneLoginStrategy implements LoginStrategy {
    @Override
    public boolean login(String username, String password) {
        // 基于手机号的登录逻辑
        return true;
    }
}

public class UsernameLoginStrategy implements LoginStrategy {
    @Override
    public boolean login(String username, String password) {
        // 基于用户名的登录逻辑
        return true;
    }
}

3. ファクトリ インターフェイスを作成し、ポリシー オブジェクトを作成するためのメソッドを定義します。

public interface LoginStrategyFactory {
    LoginStrategy createLoginStrategy(String type);
}

4. 特定のファクトリ実装クラスを作成し、入力パラメータに基づいて対応するストラテジ オブジェクトを作成します。

public class LoginStrategyFactoryImpl implements LoginStrategyFactory {
    @Override
    public LoginStrategy createLoginStrategy(String type) {
        switch (type) {
            case "email":
                return new EmailLoginStrategy();
            case "phone":
                return new PhoneLoginStrategy();
            case "username":
                return new UsernameLoginStrategy();
            default:
                return null;
        }
    }
}

5. 最後のログイン クラスで、ファクトリ メソッドを呼び出して対応するポリシー オブジェクトを作成し、ログイン メソッドを呼び出します。

public class Login {
    public boolean login(String type, String username, String password) {
        LoginStrategyFactory factory = new LoginStrategyFactoryImpl();
        LoginStrategy strategy = factory.createLoginStrategy(type);
        return strategy.login(username, password);
    }
}

このようにして、入力パラメータに基づいて対応するポリシー オブジェクトを動的に作成し、ログイン機能を実装できます。新しいログイン メソッドを追加する必要がある場合は、新しいポリシー クラスとファクトリ メソッドを追加するだけです。

4. 責任連鎖モデル

責任チェーン パターンを使用すると、リクエストを処理する複数のオブジェクトを接続して処理チェーンを形成し、オブジェクトがリクエストを処理できるようになるまでこのチェーンに沿ってリクエストを渡すことで、リクエストの処理と分離の目的を達成できます。以下は、Java で責任連鎖設計パターンを実装する方法を示す簡単な例です。

abstract class Handler {
     protected Handler handler;

     void setNext(Handler handler){
         this.handler = handler;

     }

    public abstract void process(OrderInfo order);


}

import java.math.BigDecimal;

public class OrderInfo {
    private String  productId;
    private String userId;
    private BigDecimal amount;


    public String getProductId() {
        return productId;
    }

    public void setProductId(String productId) {
        this.productId = productId;
    }

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public void setAmount(BigDecimal amount) {
        this.amount = amount;
    }
}
public class OrderValidition extends Handler {

    @Override
    public void process(OrderInfo order) {
        System.out.println("OrderValidition--------");
        handler.process(order);
    }
}
public class OrderFill extends Handler{
    @Override
    public void process(OrderInfo order) {
        System.out.println("OrderFill----");
        handler.process(order);
    }
}
public class OderAmountCalcuate extends Handler {
    @Override
    public void process(OrderInfo order) {
        System.out.println("OderAmountCalcuate----");
        handler.process(order);
    }
}
public class OderCreate extends Handler {

    @Override
    public void process(OrderInfo order) {
        System.out.println("OderCreate ----");

    }
}
public class Client {
    public static void main(String[] args) {

        OrderValidition orderValidition = new OrderValidition();
        OrderFill orderFill = new OrderFill();
        OderAmountCalcuate oderAmountCalcuate = new OderAmountCalcuate();
        OderCreate oderCreate = new OderCreate();
        
        orderValidition.setNext(orderFill);
        orderFill.setNext(oderAmountCalcuate);
        oderAmountCalcuate.setNext(oderCreate);

        orderValidition.process(new OrderInfo());


    }
}
OrderValidition--------
OrderFill----
OderAmountCalcuate----
OderCreate ----

5. シングルトンモード

おすすめ動画:【単発モード】単発モードを理解していなかったマッチョ男が面接官に容赦なく嘲笑される_bilibili_bilibili

シングルトン パターンは、クラスのインスタンスが 1 つだけ存在することを保証し、グローバル アクセス ポイントを提供する創造的な設計パターンです。主な考え方は、クラスは 1 つのオブジェクト (またはインスタンス) の作成のみを許可し、そのオブジェクトへのグローバル アクセス ポイントを提供するということです。

シングルトン パターンのアプリケーション シナリオには次のものが含まれます。

  1. 世界的にユニークな構成マネージャー。

  2. 世界的にユニークなステートマネージャー。

  3. データベース接続プール。

  4. マルチスレッド プール。

  5. 世界的にユニークなロガー。

  6. 特別な制限または一意性要件を持つリソース マネージャー。

シングルトン パターンを実装するには、ハングリー シングルトン、遅延シングルトン、ダブル チェック ロック シングルトン、静的内部クラス シングルトンなど、さまざまな方法があります。その中でも、ハングリーマンスタイルとレイジーマンスタイルの 2 つは、最も基本的な実装方法です。

1. ハングリースタイルのシングルトンモード

Hungry スタイルのシングルトン モードでは、クラスのロード時にインスタンスが作成されます。スレッド セーフティの問題はありませんが、インスタンスは必要ない場合でも常にメモリを占有するため、パフォーマンスに影響します。

public class Singleton {
    // 静态实例,类加载时即创建
    private static Singleton instance = new Singleton();
    // 私有构造方法,防止外部创建实例
    private Singleton() {}
    // 全局访问方法
    public static Singleton getInstance() {
        return instance;
    }
}

2. 遅延シングルトン パターン

遅延シングルトン モードは、インスタンスが初めてアクセスされたときに作成されますが、スレッド セーフティの問題があるため、ロックする必要があります。

public class Singleton {
    // 私有静态实例,延迟加载
    private static Singleton instance = null;
    // 私有构造方法,防止外部创建实例
    private Singleton() {}
    // 全局访问方法,加锁保证线程安全
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}
3. 二重認証ロックシングルトン

ダブル チェック ロック シングルトンは、一般的に使用されるシングルトン モードの実装方法であり、スレッドの安全性を確保するだけでなく、効率も向上します。以下は、Java でダブル チェック ロック シングルトンを実装するコードです。

public class Singleton {
    // volatile修饰的变量在多线程环境下保证可见性和有序性
    private volatile static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                // 双重校验锁,第一个if判断为了避免不必要的同步,第二个if保证同步情况下只有一个instance被创建
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

上記のコードでは、instance 変数が volatile キーワードで変更され、instance の読み取りが確実に行われるようにしています。スレッド A が instance 変数値を変更してもスレッド B が表示されないという状況を避けるために、書き込み操作はすべて表示されます。

getInstance() メソッドでは、複数のスレッドが コード ブロックに入るのを防ぐために、最初のif 判断が行われます。これにより、システム リソースが無駄に消費されます。 2 番目の では、スレッド セーフティの問題を回避するために、同期されたコード ブロック内に が 1 つだけ作成されるようにします。 synchronizedifinstance

つまり、ダブル チェック ロック シングルトンを使用すると、スレッドの安全性と効率性を確保でき、一般的に使用されるシングルトン モードの実装方法です。

おすすめ

転載: blog.csdn.net/Javascript_tsj/article/details/134156101