摘要:當我們想要擴展一個對象的能力時,通常可以通過添加原型方法,修改構造函數,繼承等方式。構造函數繼承戰士戰士的移動血條戰士的移動速度原型的繼承戰士的奔跑動作戰士的基礎攻擊接下來我們要創建裝飾類。
當我們想要擴展一個對象的能力時,通常可以通過添加原型方法,修改構造函數,繼承等方式。除此之外,我們還可以通過妝飾者模式來達到目的。
例如一個游戲角色,我們在不改變這個角色對象的條件下,給角色穿一件裝備(武器),那么角色的屬性(攻擊力)就會增加。這個過程,就可以由妝飾者模式來完成。
我們通過一個例子來演示。
首先我們有幾件裝備,他們的信息保存在config.js中,如下:
// config.js export const cloth = { name: "七彩炫光衣", hp: 1000 } export const weapon = { name: "青龍偃月刀", attack: 2000 } export const shoes = { name: "神行疾步靴", speed: 300 } export const defaultRole = { hp: 100, atk: 50, speed: 125, cloth: null, weapon: null, shoes: null, career: null, gender: null }
然后創建一個基礎的角色對象。
// 基礎角色 // 有血條,攻擊力,速度三個基礎屬性 // 以及衣服,武器,鞋子三個裝備插槽 var Role = function(role) { this.hp = role.hp; this.atk = role.atk; this.speed = role.speed; this.cloth = role.cloth; this.weapon = role.weapon; this.shoes = role.shoes; }
在原型上添加奔跑和攻擊兩個共有方法。
Role.prototype = { constructor: Role, run: function() {}, attack: function() {} // ... }
引入配置文件中的準備與默認角色
import { cloth, weapon, shoes, defaultRole } from "./config";
創建職業為戰士的角色對象。
var Soldier = function(role) { var o = Object.assign({}, defaultRole, role); Role.call(this, o); // 構造函數繼承 this.nickname = o.nickname; this.gender = o.gender; this.career = "戰士"; if (role.hp == defaultRole.hp) { this.hp = defaultRole.hp + 20; } // 戰士的移動血條 + 20 if (role.speed == defaultRole.speed) { this.speed = defaultRole.speed + 5; } // 戰士的移動速度 + 5 } // 原型的繼承 Soldier.prototype = Object.create(Role.prototype, { constructor: { value: Soldier, }, run: { value: function() { console.log("戰士的奔跑動作"); }, }, attack: { value: function() { console.log("戰士的基礎攻擊"); } } // ... })
接下來我們要創建裝飾類。
因為裝飾類可能會有很多,衣服鞋子武器都肯定各有一個裝飾類來分別負責不同的行為與變化,所以我們需要幾個基礎裝飾類。通常情況下,裝飾類與被裝飾的類有一些相似的地方,大家可以自行體會其中的差異,如下:
// 基礎裝飾類 var Decorator = function(role) { this.role = role; this.hp = role.hp; this.atk = role.atk; this.speed = role.speed; this.cloth = role.cloth; this.weapon = role.weapon; this.shoes = role.shoes; this.career = role.career; this.gender = role.gender; this.nickname = role.nickname; } Decorator.prototype = { constructor: Decorator, run: function() { this.role.run(); }, attack: function() { this.role.attack(); } // ... }
我們可以看到,基礎裝飾類以一個角色對象作為構建基礎,并沒有對角色對象做進一步改變。因此,具體的改變肯定是在具體的裝飾類中進行的。
接來下創建一個衣服的裝飾類,ClothDectorator,我們的例子中,裝備一件衣服并不會修改其行為,只是增加屬性,代碼如下:
var ClothDecorator = function(role, cloth) { Decorator.call(this, role); this.cloth = cloth.name; this.hp += cloth.hp; }
衣服裝飾類繼承基礎裝飾類,并增加一個裝備對象作為構建基礎,在構造函數內部,新增了衣服插槽this.cloth與增加了血條。
我們在具體使用中感受一下具體變化:
var base = { ...defaultRole, nickname: "alex", gender: "man" } var alex = new Soldier(base); // 新建一個戰士角色 alex.run(); // 跑一跑 alex.attack(); // 攻擊一下 console.log(alex); // 查看alex對象 alex = new ClothDecorator(alex, cloth); // 裝備衣服 console.log(alex); // 查看變化
從下圖我們可以看到具體的變化,說明裝飾成功了。
除此之外,我們還需要創建武器裝飾類與鞋子裝飾類,武器與鞋子的穿戴會改變角色的攻擊動作與奔跑動作,因此需要多行為進行更改,如下:
// 武器裝飾類 var WeaponDecorator = function(role, weapon) { Decorator.call(this, role); this.weapon = weapon.name; this.atk += weapon.attack; } WeaponDecorator.prototype = Object.create(Decorator.prototype, { constructor: { value: WeaponDecorator }, attack: { // 修改攻擊方法 value: function() { console.log("裝備了武器,攻擊變得更強了"); } } }) // 鞋子裝飾類 var ShoesDecorator = function(role, shoes) { Decorator.call(this, role); this.shoes = shoes.name; this.speed += shoes.speed; } ShoesDecorator.prototype = Object.create(Decorator.prototype, { constructor: { value: ShoesDecorator }, run: { // 修改奔跑方法 value: function() { console.log("穿上了鞋子,奔跑速度更快了"); } } })
角色alex穿了衣服之后,我們還可以繼續為他穿上鞋子與武器。代碼如下:
console.log(" "); console.log("------裝備武器-----"); alex = new WeaponDecorator(alex, weapon); // 裝備武器 alex.attack(); console.log(alex); console.log(" "); console.log("------裝備鞋子-----"); alex = new ShoesDecorator(alex, shoes); // 裝備鞋子 alex.run(); console.log(alex);
OK,這就是整個裝飾者模式的思路與具體實現,
用ES6的class實現,源代碼如下:
import { cloth, weapon, shoes, defaultRole } from "./config"; // 基礎角色 class Role { constructor(role) { this.hp = role.hp; this.atk = role.atk; this.speed = role.speed; this.cloth = role.cloth; this.weapon = role.weapon; this.shoes = role.shoes; } run() {} attack() {} } class Soldier extends Role { constructor(roleInfo) { const o = Object.assign({}, defaultRole, roleInfo); super(o); this.nickname = o.nickname; this.gender = o.gender; this.career = "戰士"; if (roleInfo.hp == defaultRole.hp) { this.hp = defaultRole.hp + 20; } if (roleInfo.speed == defaultRole.speed) { this.speed = defaultRole.speed + 5; } } run() { console.log("戰士的奔跑動作"); } attack() { console.log("戰士的基礎攻擊"); } } // class Mage extends Role {} class Decorator { constructor(role) { this.role = role; this.hp = role.hp; this.atk = role.atk; this.speed = role.speed; this.cloth = role.cloth; this.weapon = role.weapon; this.shoes = role.shoes; this.career = role.career; this.gender = role.gender; this.nickname = role.nickname; } run() { this.role.run(); } attack() { this.role.attack() } } class ClothDecorator extends Decorator { constructor(role, cloth) { super(role); this.cloth = cloth.name; this.hp += cloth.hp; } } class WeaponDecorator extends Decorator { constructor(role, weapon) { super(role); this.weapon = weapon.name; this.atk += weapon.attack; } attack() { console.log("裝備了武器,攻擊變得更強了"); } } class ShoesDecorator extends Decorator { constructor(role, shoes) { super(role); this.shoes = shoes.name; this.speed += shoes.speed; } run() { console.log("穿上了鞋子,奔跑速度更快了"); } } const baseInfo = { ...defaultRole, nickname: "alex", gender: "man" } let alex = new Soldier(baseInfo); alex.run(); alex.attack(); console.log(alex); console.log(" "); console.log("------裝備衣服-----"); alex = new ClothDecorator(alex, cloth); console.log(alex); console.log(" "); console.log("------裝備武器-----"); alex = new WeaponDecorator(alex, weapon); alex.attack(); console.log(alex); console.log(" "); console.log("------裝備鞋子-----"); alex = new ShoesDecorator(alex, shoes); alex.run(); console.log(alex);
除了角色與裝備之間的關系可以用裝飾者模式來搞定之外,我們在玩游戲的時候,還知道每個角色都會在某些情況下獲得不同的buff,例如大龍buf,小龍buf,紅buff,藍buff等,這些buff有的會更改角色屬性,例如cd更短,攻擊更高,有的會更改攻擊特性,例如紅buff會持續掉血,減速等,這些buff還有持續時間,大家可以思考一下,如何使用裝飾者模式來完成這些buff的實現。歡迎大家留言提供思路。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107070.html
摘要:在學習裝飾器語法之前,需要先溫習一下的一些基礎知識。函數最后必須返回。使用時也很簡單,如下在方法前面加上,就是裝飾器語法。裝備了,攻擊更強了。職業的基本攻擊穿上了,移動速度更快了。 在學習ES7裝飾器語法之前,需要先溫習一下ES5的一些基礎知識。 假設有對象如下:(便于理解) var person = { name: TOM } 在ES5中,對象中的每個屬性都有一個特性值來描述...
摘要:所以這是一篇插隊的文章,用于去理解中的裝飾器和概念。因此,該的作用就是根據入參返回具體的描述符。其次局部來看,裝飾器具體應用表達式是,其函數簽名和是一模一樣。等裝飾器語法,是和直接使用是等效等價的。 ================前言=================== 初衷:以系列故事的方式展現 MobX 源碼邏輯,盡可能以易懂的方式講解源碼; 本系列文章: 《【用故事解...
摘要:裝飾者模式是動態地將責任附加到對象上。然后我們在子類計算價格的時候加上父類中計算好的配料的價格。結果可樂加冰可樂加冰加糖在的類庫中就有很多實際應用到了裝飾模式,比如就可以用來裝飾,提供更加強大的功能。 裝飾者模式是動態地將責任附加到對象上。若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。 假設我們有一個需求,是給一家飲料店做一個計算各種飲料價格的功能。聽起來很簡單,我們創建一個抽象...
摘要:中用到了很多設計模式,實現這些設計模式時也用到了不少新特性。學會之后可以把設計模式的思想應用在我們的程序中。實際上是服務容器中那些底層類的靜態代理,相比于傳統的靜態方法,在提供了簡潔且豐富的語法同時,還帶來了更好的可測試性和擴展性。 laravel中用到了很多設計模式,實現這些設計模式時也用到了不少php新特性。學習這些設計模式,可以幫助我們: 學習php新特性,知道如何用新特性,寫...
摘要:異步剪貼板操作過去的數年中,各瀏覽器基本上都在使用來進行剪貼板交互。而提供了新的,則為我們提供了另一種異步式的剪貼板操作方式,本文即是對該機制與接口規范的詳細介紹。 showImg(https://segmentfault.com/img/remote/1460000013854167); 前端每周清單第 55 期: MobX 4 特性概覽,iOS Hacks 分享, 分布式事務詳解 ...
閱讀 1170·2021-11-22 15:24
閱讀 4447·2021-09-23 11:51
閱讀 2307·2021-09-08 09:36
閱讀 3522·2019-08-30 15:43
閱讀 1301·2019-08-30 13:01
閱讀 1122·2019-08-30 12:48
閱讀 545·2019-08-29 12:52
閱讀 3373·2019-08-29 12:41