国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【設(shè)計模式——學(xué)習(xí)筆記】23種設(shè)計模式——策略模式Strategy(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實現(xiàn))

這篇具有很好參考價值的文章主要介紹了【設(shè)計模式——學(xué)習(xí)筆記】23種設(shè)計模式——策略模式Strategy(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實現(xiàn))。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

案例引入

  • 有各種鴨子,比如野鴨、北京鴨、水鴨等。 鴨子有各種行為,比如走路、叫、飛行等。不同鴨子的行為可能略有不同。要求顯示鴨子的信息

傳統(tǒng)方案實現(xiàn)

不同的鴨子繼承一個父類Duck,如果是相同的行為就繼承,不同行為就重寫方法

實現(xiàn)

【鴨子抽象類】

package com.atguigu.strategy;

public abstract class Duck {

   public Duck() {

   }

   /**
    * 顯示鴨子信息
    */
   public abstract void display();

   /**
    * 叫法
    */
   public void quack() {
      System.out.println("鴨子嘎嘎叫~~");
   }

   /**
    * 游泳方法
    */
   public void swim() {
      System.out.println("鴨子會游泳~~");
   }

   /**
    * 飛翔方法
    */
   public void fly() {
      System.out.println("鴨子會飛翔~~~");
   }

}

【野鴨】

package com.atguigu.strategy;

public class WildDuck extends Duck {

   @Override
   public void display() {
      System.out.println(" 這是野鴨 ");
   }

}

【北京鴨】

package com.atguigu.strategy;

public class PekingDuck extends Duck {

   @Override
   public void display() {
      System.out.println("~~北京鴨~~~");
   }

   /**
    * 因為北京鴨不能飛翔,因此需要重寫fly
    */
   @Override
   public void fly() {
      System.out.println("北京鴨不能飛翔");
   }

}

【玩具鴨】

package com.atguigu.strategy;

public class ToyDuck extends Duck {
    @Override
    public void display() {
        System.out.println("玩具鴨");
    }

    //-------需要重寫父類的所有方法---------

    public void quack() {
        System.out.println("玩具鴨不能叫~~");
    }

    public void swim() {
        System.out.println("玩具鴨不會游泳~~");
    }

    public void fly() {
        System.out.println("玩具鴨不會飛翔~~~");
    }
}

分析

  • 缺點:因為繼承了Duck,所有鴨子都有了會飛的方法,雖然可以通過覆蓋fly方法來解決,但是,如果子類很多方法都不需要呢,如果每個都要去覆蓋一下就很麻煩了
  • 改進:使用策略模式

介紹

基本介紹

  • 策略模式中,定義算法族,分別封裝到不同的類中,讓他們之間可以互相替換,此模式讓算法的變化獨立于使用算法的客戶。使用策略模式可以整體地替換算法的實現(xiàn)部分,讓我們可以輕松地以不同的算法去解決同一個問題
  • 該模式體現(xiàn)了幾個設(shè)計原則:把變化的代碼從不變的代碼中分離出來;針對接口編程而不是具體類(定義了策略接口);多用組合/聚合,少用繼承(客戶通過組合方式使用策略)

登場角色

【設(shè)計模式——學(xué)習(xí)筆記】23種設(shè)計模式——策略模式Strategy(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實現(xiàn)),設(shè)計模式,設(shè)計模式,學(xué)習(xí),筆記,策略模式

【設(shè)計模式——學(xué)習(xí)筆記】23種設(shè)計模式——策略模式Strategy(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實現(xiàn)),設(shè)計模式,設(shè)計模式,學(xué)習(xí),筆記,策略模式

Context聚合了策略接口,后面需要使用到哪個具體策略的方法,就傳入該具體策略的實例作為參數(shù)即可

  • Strategy(策略):Strategy角色負(fù)責(zé)定義實現(xiàn)策略所必需的接口(API)
  • ConcreteStrategy(具體的策略):ConcreteStrategy角色負(fù)責(zé)實現(xiàn)Strategy角色的接口(API),即負(fù)責(zé)實現(xiàn)具體的策略(戰(zhàn)略、方向、方法和算法)
  • Context(上下文):負(fù)責(zé)使用Strategy角色。Context角色保存了ConcreteStrategy角色的實例,并使用ConcreteStrategy角色(即調(diào)用Strategy角色的接口)去實現(xiàn)需求

案例實現(xiàn)

案例一

類圖

【設(shè)計模式——學(xué)習(xí)筆記】23種設(shè)計模式——策略模式Strategy(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實現(xiàn)),設(shè)計模式,設(shè)計模式,學(xué)習(xí),筆記,策略模式

實現(xiàn)

【飛翔策略 FlyBehavior】

package com.atguigu.strategy.improve;

public interface FlyBehavior {

   /**
    * 讓子類具體實現(xiàn)
    */
   void fly();
}

【叫策略 QuackBehavior】

package com.atguigu.strategy.improve;

public interface QuackBehavior {
   void quack();
}

【飛翔技術(shù)高超:GoodFlyBehavior】

package com.atguigu.strategy.improve;

public class GoodFlyBehavior implements FlyBehavior {

   @Override
   public void fly() {
      System.out.println(" 飛翔技術(shù)高超 ~~~");
   }

}

【飛翔技術(shù)一般:BadFlyBehavior 】

package com.atguigu.strategy.improve;

public class BadFlyBehavior implements FlyBehavior {

   @Override
   public void fly() {
      System.out.println(" 飛翔技術(shù)一般 ");
   }

}

【不會飛翔】

package com.atguigu.strategy.improve;

public class NoFlyBehavior implements FlyBehavior{

   @Override
   public void fly() {
      System.out.println(" 不會飛翔  ");
   }

}

【鴨子抽象類】

package com.atguigu.strategy.improve;

public abstract class Duck {

   /**
    * 策略接口 飛翔
    */
   FlyBehavior flyBehavior;
   /**
    * 策略接口 叫
    */
   QuackBehavior quackBehavior;

   public Duck() {

   }

   /**
    * 顯示鴨子信息
    */
   public abstract void display();

   public void quack() {
      System.out.println("鴨子嘎嘎叫~~");
   }

   public void swim() {
      System.out.println("鴨子會游泳~~");
   }

   public void fly() {
      //改進
      if(flyBehavior != null) {
         flyBehavior.fly();
      }
   }

   public void setFlyBehavior(FlyBehavior flyBehavior) {
      this.flyBehavior = flyBehavior;
   }


   public void setQuackBehavior(QuackBehavior quackBehavior) {
      this.quackBehavior = quackBehavior;
   }



}

【野鴨】

package com.atguigu.strategy.improve;

public class WildDuck extends Duck {
   
   /**
    * 構(gòu)造器,傳入FlyBehavor 的對象
    */
   public  WildDuck() {
      // 野鴨飛翔技術(shù)較強
      flyBehavior = new GoodFlyBehavior();
   }


   @Override
   public void display() {
      System.out.println(" 這是野鴨 ");
   }

}

【北京鴨】

package com.atguigu.strategy.improve;

public class PekingDuck extends Duck {
    
    /**
     * 假如北京鴨可以飛翔,但是飛翔技術(shù)一般
     */
    public PekingDuck() {
        flyBehavior = new BadFlyBehavior();

    }

    @Override
    public void display() {
        System.out.println("~~北京鴨~~~");
    }

}

【玩具鴨】

package com.atguigu.strategy.improve;

public class ToyDuck extends Duck {
    public ToyDuck() {
        // 玩具鴨不會飛翔
        flyBehavior = new NoFlyBehavior();
    }

    @Override
    public void display() {
        System.out.println("玩具鴨");
    }

    /**
     * 需要重寫父類的所有方法
     */
    public void quack() {
        System.out.println("玩具鴨不能叫~~");
    }

    public void swim() {
        System.out.println("玩具鴨不會游泳~~");
    }

}

【主類】

package com.atguigu.strategy.improve;

public class Client {

   public static void main(String[] args) {
      WildDuck wildDuck = new WildDuck();
      wildDuck.fly();

      ToyDuck toyDuck = new ToyDuck();
      toyDuck.fly();

      PekingDuck pekingDuck = new PekingDuck();
      pekingDuck.fly();
      
      //可以動態(tài)改變某個對象的行為, 將北京鴨改成不能飛
      pekingDuck.setFlyBehavior(new NoFlyBehavior());
      System.out.println("北京鴨的實際飛翔能力");
      pekingDuck.fly();
   }

}

【輸出】

飛翔技術(shù)高超 ~~~
 不會飛翔  
 飛翔技術(shù)一般 
北京鴨的實際飛翔能力
 不會飛翔  

Process finished with exit code 0

尖叫策略和飛翔策略的實現(xiàn)方式一樣,這里就不再實現(xiàn)了

案例二

類圖

【設(shè)計模式——學(xué)習(xí)筆記】23種設(shè)計模式——策略模式Strategy(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實現(xiàn)),設(shè)計模式,設(shè)計模式,學(xué)習(xí),筆記,策略模式

實現(xiàn)

【手勢類:并不是策略模式的角色】

package com.atguigu.strategy.Sample;

/**
 * 手勢
 */
public class Hand {
    /**
     * 表示石頭的值
     */
    public static final int HANDVALUE_GUU = 0;
    /**
     * 表示剪刀的值
     */
    public static final int HANDVALUE_CHO = 1;
    /**
     * 表示布的值
     */
    public static final int HANDVALUE_PAA = 2;
    /**
     * 表示猜拳中3種手勢的實例
     */
    public static final Hand[] hand = {
            new Hand(HANDVALUE_GUU),
            new Hand(HANDVALUE_CHO),
            new Hand(HANDVALUE_PAA),
    };
    /**
     * 表示猜拳中手勢所對應(yīng)的字符串
     */
    private static final String[] name = {
            "石頭", "剪刀", "布",
    };
    /**
     * 表示猜拳中出的手勢的值
     */
    private int handvalue;

    private Hand(int handvalue) {
        this.handvalue = handvalue;
    }

    /**
     * 根據(jù)手勢的值獲取其對應(yīng)的實例,這是一種單例模式,每種手勢只有一個實例
     *
     * @param handvalue
     * @return
     */
    public static Hand getHand(int handvalue) {
        return hand[handvalue];
    }

    /**
     * 如果this勝了h則返回true
     *
     * @param h
     * @return
     */
    public boolean isStrongerThan(Hand h) {
        return fight(h) == 1;
    }

    /**
     * 如果this輸給了h則返回true
     *
     * @param h
     * @return
     */
    public boolean isWeakerThan(Hand h) {
        return fight(h) == -1;
    }

    /**
     * 計分:平0, 勝1, 負(fù)-1
     *
     * @param h
     * @return
     */
    private int fight(Hand h) {
        if (this == h) {
            return 0;
        } else if ((this.handvalue + 1) % 3 == h.handvalue) {
            // 當(dāng)(this.handvalue + 1) % 3 == h.handvalue時,可能得手勢組合如下
            // this是石頭,h是剪刀
            // this是剪刀,h是布
            // this是布,h是石頭
            return 1;
        } else {
            return -1;
        }
    }

    /**
     * 轉(zhuǎn)換為手勢值所對應(yīng)的字符串
     *
     * @return
     */
    public String toString() {
        return name[handvalue];
    }
}

【策略接口】

package com.atguigu.strategy.Sample;

public interface Strategy {
    /**
     * 獲取下一局要出的手勢
     * @return
     */
    public abstract Hand nextHand();

    /**
     * 學(xué)習(xí)上一局的手勢是否獲勝了,獲勝就傳進來true,否則返回false
     * @param win
     */
    public abstract void study(boolean win);
}

【具體策略一】

package com.atguigu.strategy.Sample;

import java.util.Random;

/**
 * 該策略是:如果上一局贏了,這局的手勢就和上一局的相同;如果上一局輸了,就隨機出
 */
public class WinningStrategy implements Strategy {
    private Random random;
    /**
     * 保存上一局是贏還是輸了
     */
    private boolean won = false;
    /**
     * 保存上一局出的手勢
     */
    private Hand prevHand;
    
    public WinningStrategy(int seed) {
        random = new Random(seed);
    }
    public Hand nextHand() {
        if (!won) {
            prevHand = Hand.getHand(random.nextInt(3));
        }
        return prevHand;
    }
    public void study(boolean win) {
        won = win;
    }
}

【具體策略二】

package com.atguigu.strategy.Sample;

import java.util.Random;

public class ProbStrategy implements Strategy {
    private Random random;
    private int prevHandValue = 0;
    private int currentHandValue = 0;
    /**
     * 過去的勝率:history[上一局出的手勢][這一局所出的手勢]
     * 假設(shè)上一局出的手勢是石頭:
     * history[0][0]:兩局分別出了石頭、石頭的獲勝次數(shù)
     * history[0][1]:兩局分別出了石頭、剪刀的獲勝次數(shù)
     * history[0][2]:兩局分別出了石頭、布的獲勝次數(shù)
     * 若history[0][0]=3;history[0][1]=5;history[0][2]=7
     * 下一把出什么?使用輪盤賭的方式,出石頭的概率是3/15;出剪刀的概率是5/15;出布的概率是7/15
     */
    private int[][] history = {
        { 1, 1, 1, },
        { 1, 1, 1, },
        { 1, 1, 1, },
    };
    public ProbStrategy(int seed) {
        random = new Random(seed);
    }

    /**
     * 學(xué)習(xí)歷史勝率,根據(jù)輪盤賭的方式來出下一個手勢
     * @return
     */
    public Hand nextHand() {
        int bet = random.nextInt(getSum(currentHandValue));
        int handvalue = 0;
        if (bet < history[currentHandValue][0]) {
            handvalue = 0;
        } else if (bet < history[currentHandValue][0] + history[currentHandValue][1]) {
            handvalue = 1;
        } else {
            handvalue = 2;
        }
        prevHandValue = currentHandValue;
        currentHandValue = handvalue;
        return Hand.getHand(handvalue);
    }

    /**
     * 獲取第一把出hv,第二把出1、2、3的總次數(shù)
     * @param hv
     * @return
     */
    private int getSum(int hv) {
        int sum = 0;
        for (int i = 0; i < 3; i++) {
            sum += history[hv][i];
        }
        return sum;
    }

    /**
     * 學(xué)習(xí)經(jīng)驗,更新 history 表格
     * @param win
     */
    public void study(boolean win) {
 
        if (win) {
            history[prevHandValue][currentHandValue]++;
        } else {
            history[prevHandValue][(currentHandValue + 1) % 3]++;
            history[prevHandValue][(currentHandValue + 2) % 3]++;
        }
    }
}

【游戲選手類】

package com.atguigu.strategy.Sample;

/**
 * 玩猜拳游戲的選手類
 */
public class Player {
    private String name;
    /**
     * 記錄選手要選用的策略
     */
    private Strategy strategy;

    /**
     * 贏的局?jǐn)?shù)
     */
    private int wincount;
    /**
     * 輸?shù)木謹(jǐn)?shù)
     */
    private int losecount;
    /**
     * 總局?jǐn)?shù)
     */
    private int gamecount;

    /**
     * 傳入選手的姓名和策略
     *
     * @param name
     * @param strategy
     */
    public Player(String name, Strategy strategy) {
        this.name = name;
        this.strategy = strategy;
    }

    /**
     * 策略決定下一局要出的手勢
     *
     * @return
     */
    public Hand nextHand() {
        return strategy.nextHand();
    }

    /**
     * 猜拳勝利
     */
    public void win() {                 
        strategy.study(true);
        wincount++;
        gamecount++;
    }

    /**
     * 猜拳失敗
     */
    public void lose() {                
        strategy.study(false);
        losecount++;
        gamecount++;
    }

    /**
     * 猜拳平局
     */
    public void even() {                
        gamecount++;
    }

    public String toString() {
        return "[" + name + ":" + gamecount + " games, " + wincount + " win, " + losecount + " lose" + "]";
    }
}

【主類】

package com.atguigu.strategy.Sample;

public class Main {
    public static void main(String[] args) {
        // 讓選手分別使用兩種策略來比試
        Player player1 = new Player("Taro", new WinningStrategy(314));
        Player player2 = new Player("Hana", new ProbStrategy(12));
        for (int i = 0; i < 10000; i++) {
            Hand nextHand1 = player1.nextHand();
            Hand nextHand2 = player2.nextHand();
            if (nextHand1.isStrongerThan(nextHand2)) {
//                System.out.println("Winner:" + player1);
                player1.win();
                player2.lose();
            } else if (nextHand2.isStrongerThan(nextHand1)) {
//                System.out.println("Winner:" + player2);
                player1.lose();
                player2.win();
            } else {
//                System.out.println("Even...");
                player1.even();
                player2.even();
            }
        }
        System.out.println("Total result:");
        System.out.println(player1.toString());
        System.out.println(player2.toString());
    }
}

【運行】

Total result:
[Taro:10000 games, 3107 win, 3617 lose]
[Hana:10000 games, 3617 win, 3107 lose]

Process finished with exit code 0

問答

如果需要增加一個隨機出手勢的策略,需要怎么實現(xiàn)

答:在nextHand方法中使用隨機數(shù)即可,因為全部都是隨機的,不需要學(xué)習(xí)之前的經(jīng)驗,因此study方法可以是空方法

在示例程序中,Hand類的fight方法負(fù)責(zé)判斷平局。在進行判斷時,它使用的表達式不是this.handValue == h.value,而是this==h,請問為什么可以這樣寫?

答:因為使用了單例模式,只有三個手勢實例,如果兩個手勢的handValue相同,說明兩個實例就是同一個實例

編寫Winningstrategy類時,won 字段的定義不是private boolean won = false; 而是寫成了如下這樣private boolean won;雖然寫法不同,但是兩者的運行結(jié)果一樣,為什么?

答:因為全局變量如果沒有被賦值就會被自動初始化:boolean類型默認(rèn)是false;數(shù)值類型默認(rèn)是0;引用類型默認(rèn)是null。注意,局部變量不會被自動初始化

策略模式在JDK源碼中的使用

簡單來說,就是在排序的時候,可以指定不同的排序策略

package com.atguigu.jdk;

import java.util.Arrays;
import java.util.Comparator;


public class Strategy {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //數(shù)組
        Integer[] data = {9, 1, 2, 8, 4, 3};
        // 實現(xiàn)降序排序,返回-1放左邊,1放右邊,0保持不變

        // 說明
        // 1. 實現(xiàn)了 Comparator 接口(策略接口) , 匿名類對象:new Comparator<Integer>(){..}
        // 2. 對象 new Comparator<Integer>(){..} 就是實現(xiàn)了 策略接口 的對象
        // 3. public int compare(Integer o1, Integer o2){} 指定具體的處理策略
        Comparator<Integer> comparator = new Comparator<Integer>() {
            public int compare(Integer o1, Integer o2) {
                if (o1 > o2) {
                    return -1;
                } else {
                    return 1;
                }
            }
        };

        // sort源碼說明 傳入數(shù)字和一個排序策略
      /*
       * public static <T> void sort(T[] a, Comparator<? super T> c) {
              if (c == null) {
                  sort(a); //默認(rèn)方法
              } else {
                  if (LegacyMergeSort.userRequested)
                      legacyMergeSort(a, c); //使用策略對象c
                  else
                     // 使用策略對象c
                      TimSort.sort(a, 0, a.length, c, null, 0, 0);
              }
          }
       */
        // 方式1
        Arrays.sort(data, comparator);
      // 降序排序
        System.out.println(Arrays.toString(data));

        //方式2- 同時lambda 表達式實現(xiàn) 策略模式
        Integer[] data2 = {19, 11, 12, 18, 14, 13};

        // 換一個排序策略
        Arrays.sort(data2, (var1, var2) -> {
            if (var1.compareTo(var2) > 0) {
                return -1;
            } else {
                return 1;
            }
        });

        System.out.println("data2=" + Arrays.toString(data2));

    }

}

總結(jié)

【說明】

  • 策略模式的關(guān)鍵是分析項目中變化部分與不變部分

【優(yōu)點】

  • 策略模式的核心思想是:多用組合/聚合,少用繼承;用行為類來組合,而不是行為的繼承
  • 體現(xiàn)了“對修改關(guān)閉,對擴展開放”原則,客戶端增加行為不用修改原有代碼,只要添加一種策略 (或者行為)即可,避免了使用多重判斷語句 (if…else if…else)
  • 提供了可以替換繼承關(guān)系的辦法: 策略模式將算法封裝在獨立的Strategy類中使得你可以獨立于其他Context改變它,使它易于切換、易于理解、易于擴展
  • 程序運行過程中也可以切換策略:如果使用Strategy模式,在程序運行中也可以切換ConcreteStrategy角色。如在內(nèi)存較少的環(huán)境使用一種算法,內(nèi)存較多的環(huán)境使用另外一種算法

【缺點】

  • 每添加一個策略就要增加一個類,當(dāng)策略過多是會導(dǎo)致類數(shù)目龐大

【問答】

為什么需要特意編寫Strategy角色

答:當(dāng)我們想要通過改善算法來提高算法的處理速度時,如果使用了Strategy模式,就不必修改Strategy角色的接口(API)了,僅僅修改ConcreteStrategy角色即可。而且,使用委托這種弱關(guān)聯(lián)關(guān)系可以很方便地整體替換算法,這樣也更加方便算法的比較文章來源地址http://www.zghlxwxcb.cn/news/detail-662925.html

文章說明

  • 本文章為本人學(xué)習(xí)尚硅谷的學(xué)習(xí)筆記,文章中大部分內(nèi)容來源于尚硅谷視頻(點擊學(xué)習(xí)尚硅谷相關(guān)課程),也有部分內(nèi)容來自于自己的思考,發(fā)布文章是想幫助其他學(xué)習(xí)的人更方便地整理自己的筆記或者直接通過文章學(xué)習(xí)相關(guān)知識,如有侵權(quán)請聯(lián)系刪除,最后對尚硅谷的優(yōu)質(zhì)課程表示感謝。
  • 本人還同步閱讀《圖解設(shè)計模式》書籍(圖解設(shè)計模式/(日)結(jié)城浩著;楊文軒譯–北京:人民郵電出版社,2017.1),進而綜合兩者的內(nèi)容,讓知識點更加全面

到了這里,關(guān)于【設(shè)計模式——學(xué)習(xí)筆記】23種設(shè)計模式——策略模式Strategy(原理講解+應(yīng)用場景介紹+案例介紹+Java代碼實現(xiàn))的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包