Javaの設計モードをマスターします--策略のモード

28230 ワード

単純なソートを実現することからポリシーモードを学習する
ポリシーモードはアルゴリズムのカプセル化であり,一連のアルゴリズムをそれぞれ対応するクラスにカプセル化し,これらのクラスは同じインタフェースを実現し,互いに置き換えることができる.オブジェクトに動作があるが、異なるシーンで動作が異なる実装アルゴリズムがある場合、ポリシーモードという設計モードを使用することができます.
1、問題導入
簡単な挿入ソートを使用してintタイプの配列をソートするソート器があるとします.コードは次のようになります.
package com.rul.designpattern.strategy;

import java.util.Arrays;

/**
 *          
 *
 * @author LuoRu
 */
public class Sorter01 {

    public void sort(int[] array) {

        for (int i = 1; i < array.length; i++) {
            int temp = array[i];
            int j = i;
            while (j > 0 && temp < array[j - 1]) {
                //      
                array[j] = array[j - 1];
                j--;
            }
            //    
            array[j] = temp;
        }
    }

    public static void main(String[] args) {
        int[] array = new int[]{2, 1, 5, 3, 4};

        Sorter01 sorter = new Sorter01();
        sorter.sort(array);

        System.out.println(Arrays.toString(array));
    }
}

ある日doubleタイプ配列をソートしたい場合はどうしますか?カスタムタイプ配列をソートしたい場合はどうしますか?直接ソート器にsort方法を加えて、多くの重荷重方法を実現しますか?このように、新しいタイプをソートするたびに、リロード方法を新しく書く必要があり、最終的にはコードが特に肥大化します.私たちはこのように実現することができます.
package com.rul.designpattern.strategy;

/**
 *         Sorter02          Comparable  
 *
 * @param       
 * @author LuoRu
 */
@FunctionalInterface
public interface Comparable<T> {
    int compareTo(T o);
}

2つのオブジェクトの比較サイズのポリシーを実現するためのcomparableインタフェースを設計した.また、ソート器を使用してソートするタイプは、インタフェースを実装する必要があります.以下に,Catタイプを定義し,Comparableインタフェースを実現し,実現したcomparareToメソッドはageの小さいCatの小さいことを表す.
package com.rul.designpattern.strategy;

/**
 *      ,                    
 *
 * @author LuoRu
 */
public class Cat implements Comparable<Cat> {
    int age;
    int weight;

    public Cat(int age, int weight) {
        this.age = age;
        this.weight = weight;
    }

    @Override
    public int compareTo(Cat o) {
        return this.age - o.age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "age=" + age +
                ", weight=" + weight +
                '}';
    }
}

次に、並べ替え器のコードを以下に変更することで、Comparableインタフェースを実装したすべてのタイプの配列を並べ替えることができます.
package com.rul.designpattern.strategy;

import java.util.Arrays;

/**
 *     Comparable         
 *
 * @author LuoRu
 */
public class Sorter02 {
    public void sort(Comparable[] array) {

        for (int i = 1; i < array.length; i++) {
            Comparable temp = array[i];
            int j = i;
            while (j > 0 && temp.compareTo(array[j - 1]) < 0) {
                //      
                array[j] = array[j - 1];
                j--;
            }
            //    
            array[j] = temp;
        }
    }

    public static void main(String[] args) {
        Cat[] cats = new Cat[]{new Cat(3, 3), new Cat(1, 1),
                new Cat(4, 4), new Cat(5, 5), new Cat(2, 2)};

        Sorter02 sorter = new Sorter02();
        sorter.sort(cats);

        System.out.println(Arrays.toString(cats));
    }
}

しかしある日、私たちはまた突然Catタイプの配列をageではなくweightで並べ替えたいと思っていました.どうすればいいですか.最も考えやすい方法はCatのcompareToメソッドの実装を修正することであるが,これはソフトウェア設計における「開閉原則–拡張開放,修正閉鎖」に違反し,また2つのソートポリシーをプログラム中に同時に存在させることはできない,すなわち同じプログラムのどこかでageに従ってソートすることはできず,別の場所でweightソートを使用することはできない.
2、戦略モード登場
ポリシー・モデルにより、前のニーズを簡単に実現できます.まず、2つのオブジェクトの比較サイズを規定する汎用インタフェースを定義します.
package com.rul.designpattern.strategy;

/**
 *       
 *
 * @param             
 * @author LuoRu
 */
@FunctionalInterface
public interface Comparator<T> {
    int compare(T t1, T t2);
}

Comparator実装クラスをパラメータとしてsortメソッドに転送し,新しいソートルールに従ってソートしようとするたびに,Comparatorインタフェースの実装クラスを新規に作成するだけでよい.
package com.rul.designpattern.strategy;

import java.util.Arrays;

/**
 *  Comparator        sort     
 *
 * @param            
 * @author LuoRu
 */
public class Sorter03<T> {

    public void sort(T[] array, Comparator<T> comparator) {

        for (int i = 1; i < array.length; i++) {
            T temp = array[i];
            int j = i;
            while (j > 0 && comparator.compare(temp, array[j - 1]) < 0) {
                //      
                array[j] = array[j - 1];
                j--;
            }

            //    
            array[j] = temp;
        }
    }

    public static void main(String[] args) {
        Cat[] cats = new Cat[]{new Cat(3, 3), new Cat(1, 1),
                new Cat(4, 4), new Cat(5, 5), new Cat(2, 2)};

        Sorter03<Cat> sorter = new Sorter03<>();

        sorter.sort(cats, ((t1, t2) -> t1.age - t2.age));
        System.out.println("  age      :" + Arrays.toString(cats));

        sorter.sort(cats, ((t1, t2) -> t2.weight - t1.weight));
        System.out.println("  weight      :" + Arrays.toString(cats));
    }
}

3、策略モードの構造
①Contextコンテキスト:
Contextコンテキストロールは、Contextパッケージロールとも呼ばれ、上から下への役割を果たし、上位モジュールのポリシー、アルゴリズムへの直接アクセスを遮断し、パッケージに存在する可能性のある変化をブロックします.上記の例のSorter 03に対応します.
②抽象戦略の役割:
抽象ポリシーロールは、ポリシー、アルゴリズムの抽象であり、通常はインタフェースであり、各ポリシーまたはアルゴリズムが持つべきメソッドと属性を定義します.上記の例のComparatorインタフェースに対応します.
③具体的な戦略役割:
特定のポリシーロールは、通常、必要に応じて自由に置き換えることができるアルゴリズムをカプセル化したクラスのセットで担当されます.上記の例のSorter 03のmainメソッドのLambda式に対応します.