前言
前排提示:這是一個學(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é)果:


5.3 總結(jié)
當(dāng)一個類有多種行為時,后期可能還會增加行為時,我們可以將每一種行為封裝起來使其能夠相互替換。如我們要出么去一個目的地,可使用的工具有自駕汽車、打車、公交、騎車,未來可能還有地鐵等方式,這時每一種出行方式就是一種我們出門的行為,將每種行為封裝起來,我們想使用什么方式時就可以調(diào)出對應(yīng)的方式。
優(yōu)點:
- 可以隨意切換行為
- 拓展性強(qiáng),如有新的行為很好添加
- 省去一些不必要重復(fù)的判斷
缺點:
- 如果策略非常多時,暴露出來的類也會非常多