最近学习设计模式和TypeScript,发现网上的资料略显硬核,不太容易理解记忆,常常看完就忘。做为一名游戏玩家,发现游戏中的不少场景都能和相应的设计模式相关联,不只便于理解,更利于合理地运用设计模式。因为我的水平有限,只整理我的以为比较有趣的设计模式,每一个模式采用哲学三问进行讲解。若是对你有帮助的话,欢迎点赞和收藏💖,图片源自网络,侵删。node
单例模式git
Whatgithub
Game:在DNF一块儿组团刷本的日子中,副本BOSS看做为一个单例,玩家能够经过各类技能或者平A去消耗BOSS。算法
而且该本中的全部玩家都是对同一个BOSS形成伤害设计模式
How网络
TS版本dom
class Boss{ private static instance: Boss = null; private hp: number = 1000; getInjured(harm: number){ this.hp -= harm; } getHp(): number{ return this.hp; } static getInstance(): Boss{ // 若是已经实例化了那么直接返回 if(!this.instance){ this.instance = new Boss(); } return this.instance; } } class Player{ constructor(private name: string){} attack(harm: number,boss: Boss): void{ boss.getInjured(harm); console.log(`我是一名${this.name},打出了${harm}伤害,BOSS还剩${boss.getHp()}血`) } } let p1: Player = new Player('鬼泣'); let p2: Player = new Player('街霸'); let p3: Player = new Player('阿修罗'); // 对同一个boss疯狂输出 p1.attack(100,Boss.getInstance()); p2.attack(80,Boss.getInstance()); p3.attack(120,Boss.getInstance()); // 我是一名鬼泣,打出了100伤害,BOSS还剩900血 // 我是一名街霸,打出了80伤害,BOSS还剩820血 // 我是一名阿修罗,打出了120伤害,BOSS还剩700血
JS版本性能
var Boss = /** @class */ (function () { function Boss() { this.hp = 1000; } Boss.prototype.getInjured = function (harm) { this.hp -= harm; }; Boss.prototype.getHp = function () { return this.hp; }; Boss.getInstance = function () { // 若是已经实例化了那么直接返回 if (!this.instance) { this.instance = new Boss(); } return this.instance; }; Boss.instance = null; return Boss; }()); var Player = /** @class */ (function () { function Player(name) { this.name = name; } Player.prototype.attack = function (harm, boss) { boss.getInjured(harm); console.log("我是一名" + this.name + ",打出了" + harm + "伤害,BOSS还剩" + boss.getHp() + "血"); }; return Player; }()); var p1 = new Player('鬼泣'); var p2 = new Player('街霸'); var p3 = new Player('阿修罗'); // 对同一个boss疯狂输出 p1.attack(100, Boss.getInstance()); p2.attack(80, Boss.getInstance()); p3.attack(120, Boss.getInstance()); // 我是一名鬼泣,打出了100伤害,BOSS还剩900血 // 我是一名街霸,打出了80伤害,BOSS还剩820血 // 我是一名阿修罗,打出了120伤害,BOSS还剩700血
Why单元测试
优势学习
单例模式提供了对共享资源访问的惟一接口,避免了对共享资源的多重占用
单例模式只会实例化一次对象,节约内存开销
缺点
GC
自动回收应用场景:针对一些静态的共享资源,能够采用单例模式对其进行访问。今后处能够看出举的游戏例子自己不太适合用单例模式(由于它是一个频繁变更的对象)
策略模式
What
Game:在炉石传说游戏中,盗贼的两套经典卡牌奇迹贼和爆牌贼,虽然都是盗贼玩家取胜的法宝,但这两套牌的取胜之道却大相径庭。奇迹贼依靠一回合的极限操做每每能转危为安,让对面忽然去世;而爆牌贼则是以疲劳和爆对面key牌的运营方式取胜。
How
TS版本
interface Deck{ name: string; kill(): void; } class MiracleDeck implements Deck{ name: string = '奇迹贼'; kill(){ console.log(`${this.name}:十七张牌就是能秒你`); } } class ExplosiveDeck implements Deck{ name: string = '爆牌贼'; kill(){ console.log(`${this.name}:我要爆光你的牌库!`) } } class Robber{ private deck: Deck; setDeck(deck: Deck){ this.deck = deck; } winTheGame(): void{ this.deck.kill(); }; } let rb = new Robber(); rb.setDeck(new MiracleDeck()); rb.winTheGame(); rb.setDeck(new ExplosiveDeck()); rb.winTheGame(); // 奇迹贼:十七张牌就是能秒你 // 爆牌贼:我要爆光你的牌库!
JS版本
var MiracleDeck = /** @class */ (function () { function MiracleDeck() { this.name = '奇迹贼'; } MiracleDeck.prototype.kill = function () { console.log(this.name + "十七张牌就是能秒你"); }; return MiracleDeck; }()); var ExplosiveDeck = /** @class */ (function () { function ExplosiveDeck() { this.name = '爆牌贼'; } ExplosiveDeck.prototype.kill = function () { console.log(this.name + "我要爆光你的牌库!"); }; return ExplosiveDeck; }()); var Robber = /** @class */ (function () { function Robber() { } Robber.prototype.setDeck = function (deck) { this.deck = deck; }; Robber.prototype.winTheGame = function () { this.deck.kill(); }; ; return Robber; }()); var rb = new Robber(); rb.setDeck(new MiracleDeck()); rb.winTheGame(); rb.setDeck(new ExplosiveDeck()); rb.winTheGame(); // 奇迹贼:十七张牌就是能秒你 // 爆牌贼:我要爆光你的牌库!
Why
优势
算法能够自由切换,可扩展性好
缺点
策略类会增多而且每一个策略类都须要向外暴露
应用场景:多态场景,如分享功能,分享到不一样平台的内部实现是不相同的
代理模式
What
定义:为一个对象提供一个代理者,以便控制对它的访问
解释:好比明星和经纪人的关系,经纪人会帮助明星处理商演赞助等细节问题,明星负责签字就好
Game:做为一个FM
懒人玩家,只想把时间花在看模拟比赛上,其余不想作的事就很开心地甩给助理教练啦
How
TS版本
interface Match{ play(): void; } class Manager implements Match{ play(): void{ console.log('比赛开始了,是由皇家马德里对阵拜仁慕尼黑。。。') } } class Cotch implements Match{ private manager: Manager = new Manager(); beforePlay(): void{ console.log('布置战术'); console.log('球队训话'); } afterPlay(): void{ console.log('赛后采访'); } play(): void{ this.beforePlay(); this.manager.play(); this.afterPlay(); } } let proxy: Cotch = new Cotch(); proxy.play(); // 布置战术 // 球队训话 // 比赛开始了,是由皇家马德里对阵拜仁慕尼黑。。。 // 赛后采访
JS版本
var Manager = /** @class */ (function () { function Manager() { } Manager.prototype.play = function () { console.log('比赛开始了,是由皇家马德里对阵拜仁慕尼黑。。。'); }; return Manager; }()); var Cotch = /** @class */ (function () { function Cotch() { this.manager = new Manager(); } Cotch.prototype.beforePlay = function () { console.log('布置战术'); console.log('球队训话'); }; Cotch.prototype.afterPlay = function () { console.log('赛后采访'); }; Cotch.prototype.play = function () { this.beforePlay(); this.manager.play(); this.afterPlay(); }; return Cotch; }()); var proxy = new Cotch(); proxy.play(); // 布置战术 // 球队训话 // 比赛开始了,是由皇家马德里对阵拜仁慕尼黑。。。 // 赛后采访
Why
优势
缺点
发布-订阅模式
What
定义:对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,全部依赖于它的对象都将获得通知
解释:好比JS中的addEventListener
Game:进游戏后你会订阅队友和敌人的生存状态,当生存状态发生变化时,系统会及时通知你
How
TS版本
class EventEmitter{ private events: Object = {}; // 存储事件 private key: number = 0; // 事件的惟一标识key on(name: string,event: any): number{ event.key = ++this.key; this.events[name] ? this.events[name].push(event) : (this.events[name] = []) && this.events[name].push(event); return this.key; } off(name: string,key: number){ if(this.events[name]){ this.events[name] = this.events[name].filter(x => x.key !== key); }else{ this.events[name] = []; } } emit(name: string,key?: number){ if(this.events[name].length === 0 ) throw Error(`抱歉,你没有定义 ${name}监听器`) if(key){ this.events[name].forEach(x => x.key === key && x()); }else { this.events[name].forEach(x => x()); } } } let player: EventEmitter = new EventEmitter(); player.on('friendDied',function(): void{ console.log('你可爱的队友已被击杀'); }) player.on('enemyDied',function(): void{ console.log('打的好呀,小帅哥') }) // 模拟战况 let rand: number; let k: number = 1; while(k < 10){ rand = Math.floor(Math.random() * 10); if(rand % 2 === 0){ player.emit('friendDied'); }else{ player.emit('enemyDied'); } k++; } // 你可爱的队友已被击杀 // 打的好呀,小帅哥 // 你可爱的队友已被击杀 // 你可爱的队友已被击杀 // 打的好呀,小帅哥 // 你可爱的队友已被击杀 // 你可爱的队友已被击杀 // 打的好呀,小帅哥 // 打的好呀,小帅哥
JS版本
var EventEmitter = /** @class */ (function () { function EventEmitter() { this.events = {}; // 存储事件 this.key = 0; // 事件的惟一标识key } EventEmitter.prototype.on = function (name, event) { event.key = ++this.key; this.events[name] ? this.events[name].push(event) : (this.events[name] = []) && this.events[name].push(event); return this.key; }; EventEmitter.prototype.off = function (name, key) { if (this.events[name]) { this.events[name] = this.events[name].filter(function (x) { return x.key !== key; }); } else { this.events[name] = []; } }; EventEmitter.prototype.emit = function (name, key) { if (this.events[name].length === 0) throw Error("\u62B1\u6B49\uFF0C\u4F60\u6CA1\u6709\u5B9A\u4E49 " + name + "\u76D1\u542C\u5668"); if (key) { this.events[name].forEach(function (x) { return x.key === key && x(); }); } else { this.events[name].forEach(function (x) { return x(); }); } }; return EventEmitter; }()); var player = new EventEmitter(); player.on('friendDied', function () { console.log('你可爱的队友已被击杀'); }); player.on('enemyDied', function () { console.log('打的好呀,小帅哥'); }); // 模拟战况 var rand; var k = 1; while (k < 10) { rand = Math.floor(Math.random() * 10); if (rand % 2 === 0) { player.emit('friendDied'); } else { player.emit('enemyDied'); } k++; } // 你可爱的队友已被击杀 // 打的好呀,小帅哥 // 你可爱的队友已被击杀 // 你可爱的队友已被击杀 // 打的好呀,小帅哥 // 你可爱的队友已被击杀 // 你可爱的队友已被击杀 // 打的好呀,小帅哥 // 打的好呀,小帅哥
Why
优势
很好的实现事件推送,创建一套完备的触发机制
缺点
应用场景:JS中的addEventListener和Redux中的数据流模型
中介者模式
What
定义:一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且能够独立地改变它们之间的交互。
解释:简单来讲就是模块之间通讯的中间商
Game:FIFA Online中,你能够在交易系统上上架球员卡,而后该商品会被交易系统转发给其余玩家
How
TS版本
abstract class Shop { //存储 public fifaers: Object = {} //注册 public register(name: string, fifaer: Fifaer): void { if (this.fifaers[name]) { console.error(`${name}名称已存在`); } else { this.fifaers[name] = fifaer; fifaer.setMedium(this); } } //转发 public relay(fifaer: Fifaer, message?: any): void { Object.keys(this.fifaers).forEach((name: string) => { if (this.fifaers[name] !== fifaer) { this.fifaers[name].receive(message); } }) } } //抽象玩家类 abstract class Fifaer { protected mediator: Shop; public setMedium(mediator: Shop): void { this.mediator = mediator; } public receive(message?: any): void { console.log(this.constructor.name + "收到请求:", message); } public send(message?: any): void { console.log(this.constructor.name + "上架新卡:", message); this.mediator.relay(this, message); //请中介者转发 } } //具体中介者 class ConcreteShop extends Shop { constructor() { super() } } //具体玩家1 class Fifaer1 extends Fifaer { constructor() { super() } public receive(message?: any): void { console.log(`${message} 对于我来讲太贵了`) } } //具体玩家2 class Fifaer2 extends Fifaer { constructor() { super() } public receive(message?: any): void { console.log(`${this.constructor.name}: ${message} 对于我来讲刚恰好`) } } //具体玩家3 class Fifaer3 extends Fifaer { constructor() { super() } public receive(message?: any): void { console.log(`${this.constructor.name}: ${message} 对于我来讲太便宜了`) } } let shop: Shop = new ConcreteShop(); let f1: Fifaer = new Fifaer1(); let f2: Fifaer = new Fifaer2(); let f3: Fifaer = new Fifaer3(); shop.register('Ronaldo',f1); shop.register('Messi',f2); shop.register('Torres',f3); f1.send('托雷斯的巅峰卡: 1E ep'); // Fifaer1上架新卡: 托雷斯的巅峰卡: 1E ep // Fifaer2: 托雷斯的巅峰卡: 1E ep 对于我来讲刚恰好 // Fifaer3: 托雷斯的巅峰卡: 1E ep 对于我来讲太便宜了
JS版本
var Shop = /** @class */ (function () { function Shop() { //存储 this.fifaers = {}; } //注册 Shop.prototype.register = function (name, fifaer) { if (this.fifaers[name]) { console.error(name + "\u540D\u79F0\u5DF2\u5B58\u5728"); } else { this.fifaers[name] = fifaer; fifaer.setMedium(this); } }; //转发 Shop.prototype.relay = function (fifaer, message) { var _this = this; Object.keys(this.fifaers).forEach(function (name) { if (_this.fifaers[name] !== fifaer) { _this.fifaers[name].receive(message); } }); }; return Shop; }()); //抽象玩家类 var Fifaer = /** @class */ (function () { function Fifaer() { } Fifaer.prototype.setMedium = function (mediator) { this.mediator = mediator; }; Fifaer.prototype.receive = function (message) { console.log(this.constructor.name + "收到请求:", message); }; Fifaer.prototype.send = function (message) { console.log(this.constructor.name + "上架新卡:", message); this.mediator.relay(this, message); //请中介者转发 }; return Fifaer; }()); //具体中介者 var ConcreteShop = /** @class */ (function (_super) { __extends(ConcreteShop, _super); function ConcreteShop() { return _super.call(this) || this; } return ConcreteShop; }(Shop)); //具体玩家1 var Fifaer1 = /** @class */ (function (_super) { __extends(Fifaer1, _super); function Fifaer1() { return _super.call(this) || this; } Fifaer1.prototype.receive = function (message) { console.log(message + " \u5BF9\u4E8E\u6211\u6765\u8BF4\u592A\u8D35\u4E86"); }; return Fifaer1; }(Fifaer)); //具体玩家2 var Fifaer2 = /** @class */ (function (_super) { __extends(Fifaer2, _super); function Fifaer2() { return _super.call(this) || this; } Fifaer2.prototype.receive = function (message) { console.log(this.constructor.name + ": " + message + " \u5BF9\u4E8E\u6211\u6765\u8BF4\u521A\u521A\u597D"); }; return Fifaer2; }(Fifaer)); //具体玩家3 var Fifaer3 = /** @class */ (function (_super) { __extends(Fifaer3, _super); function Fifaer3() { return _super.call(this) || this; } Fifaer3.prototype.receive = function (message) { console.log(this.constructor.name + ": " + message + " \u5BF9\u4E8E\u6211\u6765\u8BF4\u592A\u4FBF\u5B9C\u4E86"); }; return Fifaer3; }(Fifaer)); var shop = new ConcreteShop(); var f1 = new Fifaer1(); var f2 = new Fifaer2(); var f3 = new Fifaer3(); shop.register('Ronaldo', f1); shop.register('Messi', f2); shop.register('Torres', f3); f1.send('托雷斯的巅峰卡: 1E ep'); // Fifaer1上架新卡: 托雷斯的巅峰卡: 1E ep // Fifaer2: 托雷斯的巅峰卡: 1E ep 对于我来讲刚恰好 // Fifaer3: 托雷斯的巅峰卡: 1E ep 对于我来讲太便宜了
Why
优势
减小类之间的依赖,将本来一对多的依赖变成一对一的依赖(即单个玩家买东西只需去交易市场而不须要去找持有该物品的玩家)
缺点
中介者可能会变得很大,逻辑复杂
应用场景:多个对象解耦合,判断标准是类图中是否存在了网状结构
装饰器模式
What
定义:不改变现有对象结构的状况下,动态地给该对象增长一些职责(即增长其额外功能)的模式
解释:使用装饰器模式能在不改变源代码的基础上,对源代码的功能进行拓展
Game:鬼泣4中,但丁在暴揍各大领主得到许多道具,所以解锁几种战斗模式,如枪神模式
How
TS版本
@blademasterDecoration @gunslingerDecoration @tricksterDecoration @royalGuardDecoration class Dante { sayHi() { console.log(`My name is: Dante`) } } // 剑圣模式 function blademasterDecoration(target: any){ target.prototype.blademaster = function(){console.log('I am blademaster!')} } // 枪神模式 function gunslingerDecoration(target){ target.prototype.gunslinger = function(){console.log('I am gunslinger!')} } // 骗术师模式 function tricksterDecoration(target){ target.prototype.trickster = function(){console.log('I am trickster!')} } // 皇家守卫模式 function royalGuardDecoration(target){ target.prototype.royalGuard = function(){console.log('I am royalGuard!')} } let dante: Dante = new Dante(); dante.blademaster(); dante.gunslinger(); dante.trickster(); dante.royalGuard(); // I am blademaster! // I am gunslinger! // I am trickster! // I am royalGuard!
JS版本
var Dante = /** @class */ (function () { function Dante() { } Dante.prototype.sayHi = function () { console.log("My name is: Dante"); }; Dante = __decorate([ blademasterDecoration, gunslingerDecoration, tricksterDecoration, royalGuardDecoration ], Dante); return Dante; }()); // 剑圣模式 function blademasterDecoration(target) { target.prototype.blademaster = function () { console.log('I am blademaster!'); }; } // 枪神模式 function gunslingerDecoration(target) { target.prototype.gunslinger = function () { console.log('I am gunslinger!'); }; } // 骗术师模式 function tricksterDecoration(target) { target.prototype.trickster = function () { console.log('I am trickster!'); }; } // 皇家守卫模式 function royalGuardDecoration(target) { target.prototype.royalGuard = function () { console.log('I am royalGuard!'); }; } var dante = new Dante(); dante.blademaster(); dante.gunslinger(); dante.trickster(); dante.royalGuard(); // I am blademaster! // I am gunslinger! // I am trickster! // I am royalGuard!
Why
优势
可以更加灵活地扩展类的功能
缺点
多层次的装饰嵌套,增大了代码的理解难度
应用场景:想要添加新的功能同时不修改原生的代码
适配器模式
What
定义:将一个类的接口转换成客户但愿的另一个接口,使得本来因为接口不兼容而不能一块儿工做的那些类能一块儿工做
解释:简单来讲就是打补丁,兼容一些旧的接口
Game:LOL中卡兹克登场时,空中能够释放w秒人,号称飞天螳螂。由于过于变态与英雄平衡机制不兼容,因而给他打了个补丁,W自己改动不大只是不容许在空中释放了。
How
TS版本
interface TargetW{ request(): void; } // 源接口 class OriginW{ normalRequest(): void{ console.log('个人w可以治疗、减速'); } flyRequest(): void{ console.log('个人w能在空中释放'); } } class AdapterW extends OriginW implements TargetW{ constructor(){ super(); } request(): void{ console.log('取消了w在空中释放的机制'); this.normalRequest(); } } let target: TargetW = new AdapterW(); target.request(); // 取消了w在空中释放的机制 // 个人w可以治疗、减速
JS版本
var OriginW = /** @class */ (function () { function OriginW() { } OriginW.prototype.normalRequest = function () { console.log('个人w可以治疗、减速'); }; OriginW.prototype.flyRequest = function () { console.log('个人w能在空中释放'); }; return OriginW; }()); var AdapterW = /** @class */ (function (_super) { __extends(AdapterW, _super); function AdapterW() { return _super.call(this) || this; } AdapterW.prototype.request = function () { console.log('取消了w在空中释放的机制'); this.normalRequest(); }; return AdapterW; }(OriginW)); var target = new AdapterW(); target.request(); // 取消了w在空中释放的机制 // 个人w可以治疗、减速
Why
优势
将目标类和源接口解耦,有不错的灵活性和可扩展性
缺点
做为补丁,出现过多增大系统的复杂度。
应用场景:兼容旧的接口时
组合模式
What
定义:有时又叫做部分-总体模式,它是一种将对象组合成树状的层次结构的模式,用来表示“部分-总体”的关系,使用户对单个对象和组合对象具备一致的访问性。
解释:将对象之间的关系以🌲的形式进行表现
Game:最终幻想13中技能树的结构,每一个加点方向为树干,每一个技能点为树叶
How
TS版本
interface SkillTree{ add(st: SkillTree): void; operation(): void; } class SkillDirection implements SkillTree{ private children: SkillTree[] = []; constructor(private name: string){} add(node: SkillTree): void{ this.children.push(node); } operation(): void{ console.log(`你选择${this.name}方向的技能树`) this.children.forEach((x: SkillTree) => x.operation()) } } class SkillPoint implements SkillTree{ constructor(private name: string){} add(node: SkillTree): void{}; operation(): void{ console.log(`你已学习技能点 ${this.name}`) } } let tree1: SkillTree = new SkillDirection('治疗'); let tree2: SkillTree = new SkillDirection('伤害'); let leaf1: SkillTree = new SkillPoint('全体加血'); let leaf2: SkillTree = new SkillPoint('单体攻击'); tree2.add(leaf2); tree1.add(tree2); tree1.add(leaf1); tree1.operation(); // 你选择治疗方向的技能树 // 你选择伤害方向的技能树 // 你已学习技能点 单体攻击 // 你已学习技能点 全体加血
JS版本
var SkillDirection = /** @class */ (function () { function SkillDirection(name) { this.name = name; this.children = []; } SkillDirection.prototype.add = function (node) { this.children.push(node); }; SkillDirection.prototype.operation = function () { console.log("\u4F60\u9009\u62E9" + this.name + "\u65B9\u5411\u7684\u6280\u80FD\u6811"); this.children.forEach(function (x) { return x.operation(); }); }; return SkillDirection; }()); var SkillPoint = /** @class */ (function () { function SkillPoint(name) { this.name = name; } SkillPoint.prototype.add = function (node) { }; ; SkillPoint.prototype.operation = function () { console.log("\u4F60\u5DF2\u5B66\u4E60\u6280\u80FD\u70B9 " + this.name); }; return SkillPoint; }()); var tree1 = new SkillDirection('治疗'); var tree2 = new SkillDirection('伤害'); var leaf1 = new SkillPoint('全体加血'); var leaf2 = new SkillPoint('单体攻击'); tree2.add(leaf2); tree1.add(tree2); tree1.add(leaf1); tree1.operation(); // 你选择治疗方向的技能树 // 你选择伤害方向的技能树 // 你已学习技能点 单体攻击 // 你已学习技能点 全体加血
Why
优势
局部调用和总体调用区别不大,换言之调用者没必要担忧调用对象是一个简单的仍是一个复杂的结构
缺点
使得设计更加复杂。客户端须要花更多时间理清类之间的层次关系树干直接使用了实现类,限制了接口
应用场景:所描述的对象符合树的结构,如文件管理系统
状态模式
What
定义:对有状态的对象,把复杂的“判断逻辑”提取到不一样的状态对象中,容许状态对象在其内部状态发生改变时改变其行为
解释:不使用if-else | switch-case
进行判断,而是经过传入状态对象进行状态切换
Game:只狼中苇名一心的三个状态,完美虐杀玩家
How
每打过一个阶段,苇名就切换状态
TS版本
interface State{ change(context: WeiMingYiXin): void; } class StateOne implements State{ change(context: WeiMingYiXin): void{ console.log('苇名弦一郎阶段'); } } class StateTwo implements State{ change(context: WeiMingYiXin): void{ console.log('剑圣苇名一心阶段'); } } class StateThree implements State{ change(context: WeiMingYiXin): void{ console.log('雷电法王苇名一心阶段'); } } class WeiMingYiXin{ constructor(private state: State){}; setState(state: State): void{ this.state = state; } request(): void{ this.state.change(this); } } let ctx: WeiMingYiXin = new WeiMingYiXin(new StateOne()); ctx.request(); ctx.setState(new StateTwo()); ctx.request(); ctx.setState(new StateThree()); ctx.request(); // 苇名弦一郎阶段 // 剑圣苇名一心阶段 // 雷电法王苇名一心阶段
JS版本
var StateOne = /** @class */ (function () { function StateOne() { } StateOne.prototype.change = function (context) { console.log('苇名弦一郎阶段'); }; return StateOne; }()); var StateTwo = /** @class */ (function () { function StateTwo() { } StateTwo.prototype.change = function (context) { console.log('剑圣苇名一心阶段'); }; return StateTwo; }()); var StateThree = /** @class */ (function () { function StateThree() { } StateThree.prototype.change = function (context) { console.log('雷电法王苇名一心阶段'); }; return StateThree; }()); var WeiMingYiXin = /** @class */ (function () { function WeiMingYiXin(state) { this.state = state; } ; WeiMingYiXin.prototype.setState = function (state) { this.state = state; }; WeiMingYiXin.prototype.request = function () { this.state.change(this); }; return WeiMingYiXin; }()); var ctx = new WeiMingYiXin(new StateOne()); ctx.request(); ctx.setState(new StateTwo()); ctx.request(); ctx.setState(new StateThree()); ctx.request(); // 苇名弦一郎阶段 // 剑圣苇名一心阶段 // 雷电法王苇名一心阶段
Why
优势
能够很方便新增和切换状态
缺点
增长了不少的类,结构和实现较为复杂
应用场景:对象的行为依赖于它的某些属性值,状态的改变将致使行为的变化
抽象工厂模式
What
定义:是一种为访问类提供一个建立一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能获得同族的不一样等级的产品的模式结构
解释:类比于现实中的工厂,抽象工厂能够生产多个品类的产品
Game:红色警惕中,盟军和苏军的空军工厂和陆军工厂分别能产出不一样的军备和士兵
How
TS版本
interface AbstractAirForce{ create(): void; } interface AbstractGroundForce{ create(): void; } interface AbstractGroup{ createAirForce(): AbstractAirForce; createGroundForce(): AbstractGroundForce; } class MAirForce implements AbstractAirForce{ create(): void{ console.log('战斗机已创立') } } class MGroundForce implements AbstractGroundForce{ create(): void{ console.log('幻影坦克已创立') } } class SAirForce implements AbstractAirForce{ create(): void{ console.log('飞艇已创立') } } class SGroundForce implements AbstractGroundForce{ create(): void{ console.log('犀牛坦克已创立') } } class MGroup implements AbstractGroup{ createAirForce(): AbstractAirForce{ return new MAirForce(); } createGroundForce(): AbstractGroundForce{ return new MGroundForce(); } } class SGroup implements AbstractGroup{ createAirForce(): AbstractAirForce{ return new SAirForce(); } createGroundForce(): AbstractGroundForce{ return new SGroundForce(); } } let mGroup: AbstractGroup = new MGroup(); let sGroup: AbstractGroup = new SGroup(); mGroup.createAirForce().create(); mGroup.createGroundForce().create(); sGroup.createGroundForce().create() sGroup.createGroundForce().create(); // 战斗机已创立 // 幻影坦克已创立 // 犀牛坦克已创立 // 犀牛坦克已创立
JS版本
var MAirForce = /** @class */ (function () { function MAirForce() { } MAirForce.prototype.create = function () { console.log('战斗机已创立'); }; return MAirForce; }()); var MGroundForce = /** @class */ (function () { function MGroundForce() { } MGroundForce.prototype.create = function () { console.log('幻影坦克已创立'); }; return MGroundForce; }()); var SAirForce = /** @class */ (function () { function SAirForce() { } SAirForce.prototype.create = function () { console.log('飞艇已创立'); }; return SAirForce; }()); var SGroundForce = /** @class */ (function () { function SGroundForce() { } SGroundForce.prototype.create = function () { console.log('犀牛坦克已创立'); }; return SGroundForce; }()); var MGroup = /** @class */ (function () { function MGroup() { } MGroup.prototype.createAirForce = function () { return new MAirForce(); }; MGroup.prototype.createGroundForce = function () { return new MGroundForce(); }; return MGroup; }()); var SGroup = /** @class */ (function () { function SGroup() { } SGroup.prototype.createAirForce = function () { return new SAirForce(); }; SGroup.prototype.createGroundForce = function () { return new SGroundForce(); }; return SGroup; }()); var mGroup = new MGroup(); var sGroup = new SGroup(); mGroup.createAirForce().create(); mGroup.createGroundForce().create(); sGroup.createGroundForce().create(); sGroup.createGroundForce().create(); // 战斗机已创立 // 幻影坦克已创立 // 犀牛坦克已创立 // 犀牛坦克已创立
Why
优势
增长新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”
缺点
增长新的产品等级结构很复杂,须要修改抽象工厂和全部的具体工厂类
应用场景:当须要建立的对象是一系列相互关联或相互依赖的产品族时,即可以使用抽象工厂模式
单一职责原则(SRP)
What
一个对象(方法)只作一件事情。
How
Why
最小知识原则(LKP)
What
设计程序时,应当减小对象之间的交互,避免出现a.foo1(b).foo2(c).foo3(d)
的状况出现
若是两个对象之间没必要直接通讯,那么这两个对象就不要发生直接联系,而是引入一个第三方对象,来承担这些对象之间的通讯做用
How
例如使用中介者模式时,两个对象并不直接联系,而是经过中介者的接口进行联系。就像电商网站,消费者和商家经过平台进行交易而不是直接交易
Why
开放-封闭原则(OCP)
What
添加新功能的时候,可使用增长代码的方式,可是不容许改动程序的源代码
How
if-else | switch-case
等大量条件分支语句Why
bug
而引入更多的bug
,而新增代码是一种更加明智的选择《JS设计模式与开发实践》