設計模式 Strategy
當面對很多不同境境時採取不同的策略,例如:根據距離決定使用何種交通工具、不同的運送快遞有不同的金額計算方式、甚至是複雜點的表單驗證器、回合制戰鬥設計等,這個時候可以使用策略模式來設計物件。
筆記學習設計模式 Strategy (策略模式)的一些想法以及簡單的 sample code 紀錄一下學習中的想法。
使用情境
當面對很多不同境境時採取不同的策略,例如:根據距離決定使用何種交通工具、不同的運送快遞有不同的金額計算方式、甚至是複雜點的表單驗證器、回合制戰鬥設計等
特點
- 封裝不同的演算法,使得關注點分離
- 容易擴展,只要寫新的 strategy 不必修改原物件
- 必須暸解各個 strategy 才會知道該使用哪個策略
範例
以下使用 JavaScript 當作範例,實作一個將物件轉換為 xml 或是 json 格式的範例 code
思考其實就是實作兩個 strategy 分別做自己該做的事情。
const data = {
name: 'rj',
msg: 'show me the money'
}
// 其實可以用迭代的方式去組會比較輕鬆點
const xmlStrategy = {
send: function (data) {
return `
<xml>
<name>${data.name}</name>
<msg>${data.msg}</msg>
</xml>
`
}
}
const jsonStrategy = {
send: function (data) {
return JSON.stringify(data)
}
}
class Sender {
constructor(strategy) {
this.strategy = strategy
}
send(data) {
return this.strategy.send(data)
}
}
const sender = new Sender(xmlStrategy) // 可以替換 strategy
console.log(sender.send(data))
上面這個範例可能沒那麼有感覺,那麼我們將情境換成 RPG 回合制戰鬥好了
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
class Hero {
constructor(name, skill) {
this.name = name;
this.hp = 100;
this.mp = 100;
this.skill = skill
}
costHp(hp) {
this.hp -= hp;
}
costMp(mp) {
this.mp -= mp;
}
attack(target) {
this.costMp(this.skill.mp);
const injury = this.skill.attack(this, target)
console.log(`${this.name} attack ${target.name} 造成了 ${injury} 點傷害`);
}
getHp() {
console.log(this.hp);
}
isAlive() {
return this.hp > 0;
}
}
class Skill {
constructor(name, costMp) {
this.name = name;
this.costMp = costMp;
}
attack(source, target) {
source.costMp(this.costMp);
target.costHp(this.attackPower);
return this.attackPower
}
}
class Fireball extends Skill {
constructor() {
super('火球術', 10);
this.attackPower = 50;
}
}
class Watergun extends Skill {
constructor() {
super('水槍術', 5);
this.attackPower = 30;
}
}
(function () {
rj = new Hero('RJ', new Fireball);
gg = new Hero('GG', new Watergun);
while (rj.isAlive() && gg.isAlive()) {
rj.attack(gg);
gg.attack(rj);
rj.getHp();
gg.getHp();
}
})()
這樣是不是有感覺了一點,像是各個 skill 都是一個 strategy 如果我今天要再新增一個 skill 那麼只要在建立一個 class 然後 extend skill 就可以了。這樣計算傷害的演算法只需要封裝起來自己維護就好。
參考資料
https://www.dofactory.com/javascript/design-patterns/strategy
https://ithelp.ithome.com.tw/articles/10202419
https://www.youtube.com/watch?v=IkG_KuMpQRM