設計模式 - 策略模式

沒有戰略的企業就像一艘沒有舵的船,只會在原地轉圈。

Without a strategy, an organization is like a ship without a rudder, going around in circles.

– Joel Ross

設計模式是解決開發時遇到普遍存在(反覆出現)的問題的各種解法。但並不是絕對的,遇到問題才使用解法而不是為了使用而使用

切記: 不要拿了錘子,看什麼都是釘子

介紹

策略模式屬於行為模式,依照不同的情境制定不同的策略(行為),策略(行為)之間可以互相替換而不受影響。像是行軍打仗時將軍的戰爭策略、不同節日時商家的銷售策略等…

  • 目的: 將各種不同的**演算法(策略)**封裝成類別,執行何種策略是由客戶端決定。

情境

巫師們需要根據不同情況施展魔法(策略),保護隊友使用疾疾,護法現身(Expecto Patronum),救火用水水噴(Aquamenti)而卸除對方武器可以使用去去,武器走(Expelliarmus)

策略模式中會規範魔法使用的規章(策略介面),魔法的實際應用則是實體策略。使用何種魔法(策略)的依據則是巫師面對的不同景靚。

範例

咒語規章(介面)與咒語(實作)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* 咒語介面
*/
interface Magic {
public function spell();
}

/**
* 疾疾,護法現身
*/
class ExpectoPatronum implements Magic {

public function spell()
{
return '疾疾,護法現身!';
}
}

/**
* 水水噴
*/
class Aquamenti implements Magic {

public function spell()
{
return '水水噴!';
}
}

/**
* 去去,武器走
*/
class Expelliarmus implements Magic {

public function spell()
{
return '去去,武器走!';
}
}

巫師

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* 巫師
*/
class Wizard {
/**
* 使用的魔法(策略)
* @var
*/
protected $_magic;

/**
* 切換魔法(策略)
* @param Magic $magic
*/
public function choiceMagic(Magic $magic)
{
$this->_magic = $magic;
}

/**
* 施咒
* @return string
*/
public function spell()
{
if ($this->_magic == null) {
return '完蛋,忘記要用什麼咒語了!';
}

return $this->_magic->spell();
}
}

使用場景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 巫師走在路上
$wizard = new Wizard();

echo '巫師走在路上。';

echo '</br>';
echo '</br>';
# 遇到有人被攻擊了,保護他
echo '遇到路人被催狂魔攻擊!' . '</br>';
$wizard->choiceMagic(new ExpectoPatronum());
echo '念咒: ' . $wizard->spell();


echo '</br>';
echo '</br>';
# 遇到屋子燒起來了,滅火
echo '遇到路邊的房子燒起來了!' . '</br>';
$wizard->choiceMagic(new Aquamenti());
echo '念咒: ' . $wizard->spell();

echo '</br>';
echo '</br>';
# 遇到別的巫師拿著魔杖指著你,搶法杖
echo '遇到有人拿著法杖指著你!' . '</br>';
$wizard->choiceMagic(new Expelliarmus());
echo '念咒: ' . $wizard->spell();

執行結果

1
2
3
4
5
6
7
8
9
10
巫師走在路上。

遇到路人被催狂魔攻擊!
念咒: 疾疾,護法現身!

遇到路邊的房子燒起來了!
念咒: 水水噴!

遇到有人拿著法杖指著你!
念咒: 去去,武器走!

討論

由於介面規範的關係,各種策略間互相切換是不會出問題的,因此策略的使用上非常的靈活且易於擴充。

但若策略數量過多的話會讓維護端帶來額外的開銷。由於策略的實作是在客戶端,因此客戶端應該知道有什麼策略,並且瞭解各種策略之間的區別。

策略模式 VS 工廠模式

若對工廠模式不熟悉的朋友,可到此大概了解一下。

單看類別圖或是描述及用法看起來根本一模一樣,但兩種模式各自著重的點如下:

  • 簡單工廠模式是用來建立物件的模式,關注物件如何被產生。
  • 策略模式是一種行為模式,關注的是行為的封裝。

簡單的來說,工廠模式著重的是產出類別(巫師),至於類別(巫師)後續做了何種行為則跟他沒關係了。
策略模式著重的是在策略本身,依照情況使用什麼策略,至於策略怎麼來的。就不是重點了。

Author

LinYoYo

Posted on

2021-10-18

Updated on

2021-10-18

Licensed under