設(shè)計模式(二)——策略模式

前言

前排提示:這是一個學(xué)習(xí)筆記,參照馬士兵老師和韓順平老師設(shè)計模式的視頻學(xué)習(xí)的筆記。記錄下來純?yōu)殪柟毯头奖闳蘸蟮膹?fù)習(xí)!
參考:
韓順平老師:https://www.bilibili.com/video/BV1G4411c7N4?from=search&seid=15531256878937056259
馬士兵老師:https://www.bilibili.com/video/BV1tK411W7xx?from=search&seid=15531256878937056259

設(shè)計模式(序)——設(shè)計模式初識和原則
設(shè)計模式(一)——單例模式
設(shè)計模式(二)——策略模式
設(shè)計模式(三)——簡單工廠和抽象工廠

五、策略模式

5.1初識

思考一

首先寫一個能夠?qū)nt數(shù)組進(jìn)行排序的排序類和一個主類。在排序類中實現(xiàn)排序方法,在主類中初始化數(shù)組并將調(diào)用排序方法給數(shù)組排序。
主類:

public class Main {
    public static void main(String[] args) {
        int[] a = {9,2,3,5,7,1,4};
        Sorter sorter = new Sorter();
        sorter.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

排序類:

public class Sorter {
    public void sort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int min = i;
            for (int j = i+1; j < arr.length; j++) {
                min = arr[j]<arr[min]?j:min;
            }
            swap(arr,i,min);
        }
    }
    static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

問題:如果還要對double類型的數(shù)組、float類型的數(shù)組進(jìn)行排序,該如何做?

思考二

再編寫一個cat類用于比較兩只貓的大小。
Cat類:

public class Cat {
    int weight,height;

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

    /**
     * 定義比較兩只貓大小的方法
     */
    public int compareTo(Cat cat){
        if (this.weight<cat.weight){
            return -1;
        }else if (this.weight> cat.weight){
            return -1;
        }else {
            return 0;
        }
    }
    
        @Override
        public String toString() {
            return "Cat{" +
                    "weight=" + weight +
                    ", height=" + height +
                    '}';
        }
}

排序類的改造:

public class Sorter {
    public void sort(Cat[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int min = i;
            for (int j = i+1; j < arr.length; j++) {
                min = arr[j].compareTo(arr[min])==-1 ? j:min;
            }
            swap(arr,i,min);

        }
    }
    static void swap(Cat[] arr, int i, int j)
    {
        Cat temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

問題:如果還需要對Dog、Snake進(jìn)行排序,該如何做?如果要對各種類型的數(shù)據(jù)或?qū)ο笈判蛴衷撛趺醋觯?/p>

解決問題

首先,既然要對多個對象進(jìn)行比較,那么排序類中傳入的對象不能為指定好的對象,必須改為Object類。

其次,如果傳入的類為Object類,但是Object類中并沒有compareTo()方法。因此我們這里寫一個接口,接口中有compareTo()方法;或者使用Java自帶的Comparable接口

為了復(fù)習(xí)一下泛型,我們還是自己寫一個Comparable接口,在接口中寫一個compareTo()方法。在對象類中實現(xiàn)Comparable接口,并實現(xiàn)其compareTo()方法。

//修改后的排序類
public class Sorter {
    public void sort(Comparable[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int min = i;
            for (int j = i + 1; j < arr.length; j++) {
                min = arr[j].compareTo(arr[min]) == -1 ? j : min;
            }
            swap(arr, i, min);

        }
    }

    static void swap(Comparable[] arr, int i, int j) {
        Comparable temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}
//Comparable接口
public interface Comparable {
    int compareTo(Object o);
}
//修改需要排序的類
public class Cat implements Comparable{
    int weight,height;

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

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

    @Override
    public int compareTo(Object o) {
        Cat cat = (Cat) o;
        if (this.weight<cat.weight){
            return -1;
        }else if (this.weight> cat.weight){
            return -1;
        }else {
            return 0;
        }
    }
}
public class Dog implements Comparable{

    private int food;

    public Dog(int food){
        this.food = food;
    }

    @Override
    public int compareTo(Object o) {
        Dog dog = (Dog) o;
        if (this.food<dog.food) {
            return -1;
        }else if (this.food> dog.food){
            return 1;
        }else {
            return 0;
        }
    }

    @Override
    public String toString() {
        return "Dog{" +
                "food=" + food +
                '}';
    }
}

在主類中測試,對Dog類和Cat類進(jìn)行排序

public class Main {
    public static void main(String[] args) {
//        int[] a = {9,2,3,5,7,1,4};
//        Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
        Dog[] a = {new Dog(1),new Dog(3),new Dog(2)};
        Sorter sorter = new Sorter();
        sorter.sort(a);
        System.out.println(Arrays.toString(a));
    }
}

運(yùn)行結(jié)果:

#Cat
[Cat{weight=1, height=1}, Cat{weight=3, height=3}, Cat{weight=5, height=5}]

Process finished with exit code 0
#Dog
[Dog{food=1}, Dog{food=2}, Dog{food=3}]

Process finished with exit code 0

至此排序類就可以對Cat類和Dog類進(jìn)行排序了。但是由于每次在Cat類和Dog類中的compareTo()方法中都需要進(jìn)行強(qiáng)制轉(zhuǎn)換,在強(qiáng)制轉(zhuǎn)換中可能會出現(xiàn)類的錯誤異常,因此可以引入泛型的概念。
修改comparable接口

public interface Comparable<T> {
    int compareTo(T o);
}

這樣就可以在Cat類和Dog類實現(xiàn)Comparable接口時指定T。

//重新修改Dog類
public class Dog implements Comparable<Dog>{

    private int food;

    public Dog(int food){
        this.food = food;
    }

    @Override
    public int compareTo(Dog o) {
        if (this.food<o.food) {
            return -1;
        }else if (this.food> o.food){
            return 1;
        }else {
            return 0;
        }
    }

    @Override
    public String toString() {
        return "Dog{" +
                "food=" + food +
                '}';
    }
}

Cat類同理,在此省略。

總結(jié)
通過這個例子我們了解到了如何Comparable接口和泛型的使用,但是這個還不算策略模式。下面我們再繼續(xù)思考一下,在Cat類中我們定義了weight和height兩種屬性,而做比較的時候只用到了weight作為比較的基準(zhǔn),如果比較兩只貓的大小還需要從height上進(jìn)行比較呢?又或者需要綜合weight和height一起比較呢?

5.2 Comparator比較器

為了解決上述問題,編寫一個比較器接口

public interface Comparator<T> {
    int compare(T o1,T o2);
}

編寫兩個類來實現(xiàn)這個比較器接口,分別實現(xiàn)按Cat的weight來比較大小和Cat的height來比較大小。

public class CatWeightComparator implements Comparator<Cat>{
    @Override
    public int compare(Cat o1, Cat o2) {
        if (o1.weight<o2.weight){
            return -1;
        }else if (o1.weight> o2.weight){
            return 1;
        }else {
            return 0;
        }
    }
}
public class CatheightComparator implements Comparator<Cat>{
    @Override
    public int compare(Cat o1, Cat o2) {
        if (o1.height<o2.height){
            return 1;
        }else if (o1.height> o2.height){
            return -1;
        }else {
            return 0;
        }
    }
}

最后改造排序類

public class Sorter<T> {
    public void sort(T[] arr,Comparator<T> comparator) {
        for (int i = 0; i < arr.length; i++) {
            int min = i;
            for (int j = i + 1; j < arr.length; j++) {
                min = comparator.compare(arr[j],arr[min]) == -1 ? j : min;
            }
            swap(arr, i, min);

        }
    }

    public void swap(T[] arr, int i, int j) {
        T temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

在主類測試

public class Main {
    public static void main(String[] args) {
//        int[] a = {9,2,3,5,7,1,4};
        Cat[] a = {new Cat(3, 3), new Cat(5, 5), new Cat(1, 1)};
//        Dog[] a = {new Dog(1),new Dog(3),new Dog(2)};
        Sorter<Cat> sorter = new Sorter<>();
//        sorter.sort(a,new CatWeightComparator());
        sorter.sort(a,new CatheightComparator());
        System.out.println(Arrays.toString(a));
    }
}

測試結(jié)果:


2-1 按Cat的height比較.png
2-2 按Cat的weight比較.png

5.3 總結(jié)

當(dāng)一個類有多種行為時,后期可能還會增加行為時,我們可以將每一種行為封裝起來使其能夠相互替換。如我們要出么去一個目的地,可使用的工具有自駕汽車、打車、公交、騎車,未來可能還有地鐵等方式,這時每一種出行方式就是一種我們出門的行為,將每種行為封裝起來,我們想使用什么方式時就可以調(diào)出對應(yīng)的方式。

優(yōu)點:

  • 可以隨意切換行為
  • 拓展性強(qiáng),如有新的行為很好添加
  • 省去一些不必要重復(fù)的判斷

缺點:

  • 如果策略非常多時,暴露出來的類也會非常多
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容