最近學習設計模式和TypeScript
,發現網上的資料略顯硬核,不太容易理解記憶,常常看完就忘。做爲一名遊戲玩家,發現遊戲中的不少場景都能和相應的設計模式相關聯,不只便於理解,更利於合理地運用設計模式。因爲我的水平有限,只整理我的以爲比較有趣的設計模式,每一個模式採用哲學三問進行講解。若是對你有幫助的話,歡迎點贊和收藏💖,圖片源自網絡,侵刪。node
What
定義:一個類僅有一個實例,並提供一個訪問它的全局訪問點git
解釋:實質上就是起到一個存儲全局變量的做用,其餘的類和模塊只能經過該類提供的接口修改其惟一實例github
Game:在DNF
一塊兒組團刷本的日子中,副本BOSS
看做爲一個單例,玩家能夠經過各類技能或者平A去消耗BOSS
。算法
而且該本中的全部玩家都是對同一個BOSS
形成傷害設計模式
How
BOSS
爲單例,只會被實例化一次BOSS
形成傷害BOSS
受到的傷害爲玩家們形成傷害的總和TS版本網絡
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版本dom
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
ES6
中的Proxy
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
W
能夠空中釋放,而且有治療和減速的效果W
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
What
一個對象(方法)只作一件事情。
How
Why
What
設計程序時,應當減小對象之間的交互,避免出現a.foo1(b).foo2(c).foo3(d)
的狀況出現
若是兩個對象之間沒必要直接通訊,那麼這兩個對象就不要發生直接聯繫,而是引入一個第三方對象,來承擔這些對象之間的通訊做用
How
Why
What
添加新功能的時候,可使用增長代碼的方式,可是不容許改動程序的源代碼
How
if-else | switch-case
等大量條件分支語句Why
bug
而引入更多的bug
,而新增代碼是一種更加明智的選擇《JS設計模式與開發實踐》