成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Strategy Pattern 教你秒變“神槍手”

原創 精選
開發
本文介紹的是 Strategy Pattern (策略模式)。干貨滿滿,希望閱讀后你能有所收獲~

作者案:本文介紹的是 Strategy Pattern (策略模式)。干貨滿滿,希望閱讀后你能有所收獲~

目的

做一件事情有不同的實現方式,可以將變化的部分和不變的部分剝離開,去除大量的 if/else,提供高擴展性。

例子代碼

比如我們想要帶妹吃雞,就要成為一個神槍手。在各種槍戰游戲中,有各種不同的槍,我們要根據射程的不同選擇不同的槍進行射擊。

如果槍的子彈數量都不富裕,我們要用最少的子彈,最合適的方法達到最強傷害,最終大吉大利。

當我們距離對手:

  • 1米以內,使用平底鍋(想我當時三級頭三級甲,手持 AKM,滿血滿狀態,三級包里藥包無數,到了決賽圈被平底鍋堵在墻角打死啦?? );
  • 100 米左右,使用沖鋒槍;
  • 超過 1000 米,使用狙擊槍(對于我這樣的小菜雞,基本流程是開一槍沒打中,暴露位置,被別人一狙打死...囧)。
/**
* 面條式代碼判斷最強武器
*/
public class NoodlesKillProcessor {


/**
* 根據距離判斷最好的武器擊殺對手
* @param distance
*/
@BadSmell
public static void killByDistance(int distance) {


if(distance < 0) {
throw new RuntimeException("距離咋還能是負數呢?");
}


if(distance >= 0 && distance < 1) {
System.out.println("發現敵人");
System.out.println("兩步快速走過去");
System.out.println("掏出平底鍋呼他");
return;
}


if(distance >= 1 && distance < 10) {
System.out.println("發現敵人");
System.out.println("快速走過去");
System.out.println("掏出手槍打他");
return;
}


if(distance >= 10 && distance < 100) {
System.out.println("發現敵人");
System.out.println("身體站直, 心態穩住");
System.out.println("掏出沖鋒槍打他");
return;
}


if(distance >= 100 && distance < 1000) {
System.out.println("發現敵人");
System.out.println("身體蹲下降低后坐力");
System.out.println("掏出步槍");
System.out.println("打開 3 倍鏡");
System.out.println("開槍射擊");
return;
}


if(distance >= 1000) {
System.out.println("發現敵人");
System.out.println("趴在草叢里茍著");
System.out.println("掏出狙擊槍");
System.out.println("打開 8 倍鏡");
System.out.println("開槍射擊");
return;
}
}
}

問題分析

我覺得這有 3 個問題,具體分析如下:

01 可讀性問題

我看這么多 if/else 語句,里面的 sout 語句目前三四行也還好,如果我們有上百行的語句,里面也有很多 if/else,這樣都不知道下個主 if 跑哪去啦 ??

02 重復性問題

全都需要發現敵人,如果發現敵人是個成百上千行代碼,就很麻煩啦。

03 可維護性問題

如果這時候我們新增了一種槍,比如是霰彈槍,適用 10 到 20 的時候使用,這時候我們就需要在加一個 if 語句如下:

/**
* 面條式代碼判斷最強武器
*/
public class NoodlesKillProcessor {


/**
* 根據距離判斷最好的武器擊殺對手
* @param distance
*/
@BadSmell
public static void killByDistance(int distance) {


if(distance < 0) {
throw new RuntimeException("距離咋還能是負數呢?");
}


if(distance >= 0 && distance < 1) {
System.out.println("發現敵人");
System.out.println("兩步快速走過去");
System.out.println("掏出平底鍋呼他");
return;
}


if(distance >= 1 && distance < 10) {
System.out.println("發現敵人");
System.out.println("快速走過去");
System.out.println("掏出手槍打他");
return;
}


if(distance >= 10 && distance < 20) {
System.out.println("發現敵人");
System.out.println("身體站直, 瞄準");
System.out.println("打一槍算一槍");
return;
}


if(distance >= 20 && distance < 100) {
System.out.println("發現敵人");
System.out.println("身體站直, 心態穩住");
System.out.println("掏出沖鋒槍打他");
return;
}


if(distance >= 100 && distance < 1000) {
System.out.println("發現敵人");
System.out.println("身體蹲下降低后坐力");
System.out.println("掏出步槍");
System.out.println("打開 3 倍鏡");
System.out.println("開槍射擊");
return;
}


if(distance >= 1000) {
System.out.println("發現敵人");
System.out.println("趴在草叢里茍著");
System.out.println("掏出狙擊槍");
System.out.println("打開 8 倍鏡");
System.out.println("開槍射擊");
return;
}
}
}

這個看著也沒啥大問題的樣子,不就是加了個 if 么,但是由于我們改動了這個文件,測試同學問我們需要測試哪些功能,說是測一種槍需要 5 天。

問題來啦,本來說是你增加一種槍, 需要測 5 天,但是現在你說改了這文件,上下可能有些局部變量共享的,或者有些方法可能改了入參的值,這些有負作用的方法被調用啦,所以可能狙擊槍也得測一測,可能手槍也得測一測。

測試同學崩了,本來 5 天的工作量,搞成了 5 * 6 天,一個月都在測槍。

初步嘗試解決

我們先定義好一個基礎類,解決一下可讀性問題和重復性問題。

定義一個基礎武器類:

/**
* 抽象的槍
*/
public abstract class Weapon {


/**
* 發現敵人
*/
protected void findEnemy() {
System.out.println("發現敵人");
}


/**
* 開槍前的動作
*/
protected abstract void preAction();


/**
* 開槍
*/
protected abstract void shoot();


/**
* 整體的動作
*/
public void kill() {
findEnemy();
preAction();
shoot();
}
}

逐個實現武器的具體類、平底鍋、沖鋒槍、步槍等類如下:

/**
* 平底鍋
*/
public class Pan extends Weapon {


@Override


protected void preAction() {
System.out.println("兩步快速走過去");
}


@Override


protected void shoot() {
System.out.println("掏出平底鍋呼他");
}
}


/**
* 手槍類
*/
public class Pistol extends Weapon {


@Override


protected void preAction() {
System.out.println("快速走過去");
}


@Override


protected void shoot() {
System.out.println("掏出手槍打他");
}
}


/**
* 霰彈槍
*/
public class Shotgun extends Weapon {


@Override


protected void preAction() {
System.out.println("身體站直, 瞄準");
}


@Override


protected void shoot() {
System.out.println("打一槍算一槍");
}
}


/**
* 狙擊槍
*/
public class SniperRifle extends Weapon {


@Override


protected void preAction() {
System.out.println("趴在草叢里茍著");
System.out.println("掏出狙擊槍");
System.out.println("打開 8 倍鏡");
}
@Override
protected void shoot() {
System.out.println("開槍射擊");
}
}


/**
* 沖鋒槍
*/
public class SubmachineGun extends Weapon {


@Override


protected void preAction() {
System.out.println("身體站直, 心態穩住");
}


@Override


protected void shoot() {
System.out.println("掏出沖鋒槍打他");
}
}

我們的方法就可以改動得更清晰啦。

/**
* 抽象出類代碼判斷最強武器
*/
public class WeaponKillProcessor {


/**
* 根據距離判斷最好的武器擊殺對手
* @param distance
*/
@BadSmell
public static void killByDistance(int distance) {


if (distance < 0) {


throw new RuntimeException


("距離咋還能是負數呢?");


}
Weapon weapon = null;


if (distance >= 0 && distance < 1) {
weapon = new Pan();
} else if (distance >= 1 && distance < 10) {
weapon = new Pistol();
} else if (distance > 10 && distance < 20) {
weapon = new Shotgun();
} else if (distance >= 20 && distance < 100) {
weapon = new SubmachineGun();
} else if (distance >= 100 && distance < 1000) {
weapon = new Rifle();
} else if (distance >= 1000) {
weapon = new SniperRifle();
}
weapon.kill();
}
}

類圖如下:

圖片

使用策略模式

上面的代碼沒有解決最根本的問題,也就是去除 if/else,所用的方法其實就是將 if else 轉換為 for,這樣的代碼后續添加槍就不需要再增加新的類型啦。

我們先定義一個通用的策略模式接口如下:

/**
* 策略模式
*/
public interface Strategy


<T extends AbstractStrategyRequest,


R extends AbstractStrategyResponse> {
/*
* 執行策略
* @param request
* @return
*/
R executeStrategy(T request);
}

入參和出參都是基本的抽象類:

/**
* 策略模式抽象入參
*/
public abstract class AbstractStrategyRequest {
}
/**
* 策略模式抽象出參
*/
public abstract class AbstractStrategyResponse {
}

實現一個武器抽象類實現接口:

public abstract class WeaponStrategy implements 


Strategy<WeaponStrategyRequest,


AbstractStrategyResponse> {


/**
* 發現敵人
*/
protected void findEnemy() {
System.out.println("發現敵人");
}


/**
* 開槍前的動作
*/
protected abstract void preAction();


/**
* 開槍
*/
protected abstract void shoot();


/**
* 獲取距離范圍
* @return
*/
protected abstract Range<Integer> queryDistanceRange();


/**
* 整體的動作
*/
public void kill() {
findEnemy();
preAction();
shoot();
}


@Override


public AbstractStrategyResponse


executeStrategy(WeaponStrategyRequest request) {


System.out.println("距離敵人 " + request.getDistance());


kill();


return null;


}
}

其中的 Range 類實現如下:

/**
* 范圍類
* @param <T>
*/
@Data
@AllArgsConstructor
public class Range<T extends Comparable<T>> {


private T start;


private T end;


public Range(T start, T end) {


this.start = start;


this.end = end;


}


private boolean isIncludeStart = true;


private boolean isIncludeEnd = false;


/**
* 判斷是否在范圍內
* @param target
* @return
*/
public boolean inRange(T target) {


if(isIncludeStart) {


if(start.compareTo(target) > 0) {


return false;


}
} else {


if(start.compareTo(target) >= 0) {


return false;


}
}


if(isIncludeEnd) {


if(end.compareTo(target) < 0) {


return false;


}
} else {


if(end.compareTo(target) <= 0) {


return false;


}
}


return true;


}
}

依次實現這個抽象武器策略類:

/**
* 平底鍋
*/
public class PanStrategy extends WeaponStrategy {
@Override


protected void preAction() {
System.out.println("二步快速走過去");
}
@Override
protected void shoot() {
System.out.println("掏出平底鍋呼他");
}
@Override
protected Range<Integer> queryDistanceRange() {
return new Range<>(0, 1);
}
}


/**
* 手槍類
*/
public class PistolStrategy extends WeaponStrategy {


@Override


protected void preAction() {
System.out.println("快速走過去");
}


@Override


protected void shoot() {
System.out.println("掏出手槍打他");
}


@Override


protected Range<Integer> queryDistanceRange() {
return new Range<>(1, 10);
}
}


/**
* 步槍
*/
public class RifleStrategy extends WeaponStrategy {


@Override


protected void preAction() {
System.out.println("身體蹲下降低后坐力");
System.out.println("掏出步槍");
System.out.println("打開 3 倍鏡");
}


@Override


protected void shoot() {
System.out.println("開槍射擊");
}


@Override


protected Range<Integer> queryDistanceRange() {
return new Range<>(100, 1000);
}
}


/**
* 霰彈槍
*/
public class ShotgunStrategy extends WeaponStrategy {


@Override


protected void preAction() {
System.out.println("身體站直, 瞄準");
}


@Override


protected void shoot() {
System.out.println("打一槍算一槍");
}


@Override


protected Range<Integer> queryDistanceRange() {
return new Range<>(10, 20);
}
}


/**
* 狙擊槍
*/
public class SniperRifleStrategy extends WeaponStrategy {


@Override


protected void preAction() {
System.out.println("趴在草叢里茍著");
System.out.println("掏出狙擊槍");
System.out.println("打開 8 倍鏡");
}


@Override


protected void shoot() {
System.out.println("開槍射擊");
}


@Override


protected Range<Integer> queryDistanceRange() {
return new Range<>(1000, Integer.MAX_VALUE);
}
}


/**
* 沖鋒槍
*/
public class SubmachineGunStrategy extends WeaponStrategy {


@Override


protected void preAction() {
System.out.println("身體站直, 心態穩住");
}


@Override


protected void shoot() {
System.out.println("掏出沖鋒槍打他");
}


@Override


protected Range<Integer> queryDistanceRange() {
return new Range<>(20, 100);
}
}

定義一個上下文類來對入參進行路由:

/**
* 策略上下文, 用來路由策略
*/
public class StrategyContext {
public static final List<WeaponStrategy>


WEAPON_STRATEGYS = new ArrayList<>();




static {
WEAPON_STRATEGYS.add(new PanStrategy());
WEAPON_STRATEGYS.add(new PistolStrategy());
WEAPON_STRATEGYS.add(new RifleStrategy());
WEAPON_STRATEGYS.add(new ShotgunStrategy());
WEAPON_STRATEGYS.add(new SniperRifleStrategy());
WEAPON_STRATEGYS.add(new SubmachineGunStrategy());
}


public static void execute(Integer distance) {
WEAPON_STRATEGYS.stream().
filter((weaponStrategy -> {
Range<Integer> integerRange =
weaponStrategy.queryDistanceRange();
return integerRange.inRange(distance);
})).
findAny().
get().
executeStrategy(
new WeaponStrategyRequest(distance));
}
}

最后在主方法里面調用就好啦:

public class App {    


public static void main(String[] args) {
StrategyContext.execute(89);
}
}

結果如下:

距離敵人 89

發現敵人

身體站直,心態穩住

掏出沖鋒槍打他

類圖如下:

圖片

責任編輯:未麗燕 來源: 字節跳動技術團隊
相關推薦

2014-02-11 15:31:33

LinuxWindows 8

2010-01-20 09:17:46

2024-01-11 08:03:52

程序圖片優化

2023-07-13 10:30:18

CIOIT組織

2025-03-06 07:44:36

2015-12-03 10:03:38

夜神

2017-12-03 21:47:07

開源工具JavaScript

2015-08-14 10:03:52

Windows 10美化工具

2010-04-02 13:54:21

無線路由器無線AP

2017-03-19 15:51:47

人工神經網絡

2021-03-29 10:37:35

開源技術 開發

2025-02-07 10:54:07

2015-12-04 10:25:50

VR拍照谷歌

2024-12-31 08:30:00

mkcertHTTPS開發

2009-08-25 17:55:52

C#實現Strateg

2009-08-31 15:55:17

C#實現Strateg

2022-07-28 11:13:08

人工智能模型

2019-05-13 09:29:55

AndroidGoogle 移動系統

2020-02-19 15:02:23

代碼開發工具
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久综合九色综合欧美狠狠 | 国产重口老太伦 | 国产福利在线免费观看 | 逼逼视频 | 二区成人| 天天躁日日躁性色aⅴ电影 免费在线观看成年人视频 国产欧美精品 | 日韩在线视频免费观看 | 九色视频网站 | 五月婷婷激情网 | 一区二区三区四区视频 | 欧美一级欧美一级在线播放 | 九七午夜剧场福利写真 | 一区二区三区四区不卡 | 天堂中文av | 欧美国产日韩一区二区三区 | 一级大片 | 欧美日韩黄色一级片 | 国产一二区免费视频 | 狠狠操你 | 五月婷婷中文 | 欧美影院 | 精品在线一区 | 亚洲成人二区 | 国产精品美女久久久久久免费 | 成年精品 | 国产精品一区二区三区在线 | 国产三级精品三级在线观看四季网 | 黄色免费看 | 日韩精品一区二区三区在线播放 | 国产精品美女久久久久久免费 | 一级a毛片 | 亚洲人成人一区二区在线观看 | 欧美日韩一区二区三区四区 | 影音先锋久久 | 91一区二区三区在线观看 | 超碰最新在线 | 亚洲第一天堂 | 亚洲国产激情 | 91麻豆精品一区二区三区 | 国产精品久久久久久久久久三级 | 国产成人在线一区二区 |