很多人在初入行業(yè)的時候,喜歡走到哪寫到哪,隨手一時爽,一直隨手一直爽,重構(gòu)直接火葬場。很多人會搬出來單一職責(zé)或者其他設(shè)計原理或者設(shè)計模式來給你解釋,當(dāng)然,本期不講這些。我們來聊一聊:展示組件和容器組件。
又是一個晴朗的周末,爬起來已經(jīng)中午了,突然發(fā)現(xiàn)身邊亂糟糟的,書啊,衣服啊,電腦啊丟的到處都是。今天還有人來家里進(jìn)行友好訪問(俗稱過來白嫖一頓飯),這么亂可不行,那么稍微起來收拾收拾吧。
// example .01 code
const clean = good => {
if (good === 'clothes') {
return 'My clothes are in the closet';
} else if (good === 'book') {
return 'My book is in the bookcase';
} else if (good === 'laptop') {
return 'My laptop is on the desk';
} else {
return false;
}
};
const goodsInRoom = ['clothes', 'book', 'laptop'];
(() => {
goodsInRoom.forEach(good => {
const result = clean(good);
console.log(result ? result : `${good} is not clean`);
});
console.log('My room is clean');
})();
看起來這樣就可以輕松的收拾房間了呢,但是,好像地面需要打掃,我還需要掃地、拖地。
突然,我放佛覺得哪里不對勁,什么都要我干,老子那個破掃地機(jī)器人,買了當(dāng)大爺嗎?不行,我需要讓他也干活。
class SweepingRobot {
#range = [];
constructor(name) {
this.name = name;
}
setRange(range) {
this.#range = range;
}
clean() {
this.#range.forEach(range => {
console.log(`${this.name} -> ${range}: start to clean`);
);
}
}
const robotClean = range => {
const sweepingRobot = new SweepingRobot('斯沃特機(jī)器人');
sweepingRobot.setRange(range);
sweepingRobot.clean();
};
// ... example .01 code here ...
(() => {
goodsInRoom.forEach(good => {
const result = clean(good);
console.log(result ? result : `${good} is not clean`);
});
robotClean(['廚房', '臥室', '洗手間', '陽臺']);
console.log('My room is clean');
})();
看起來真不錯,回過頭,我們看看整個過程,我們在主入口首先把物品整理了,然后調(diào)用robotClean方法清理了廚房、臥室、洗手間、陽臺四個地方,我的房間終于干凈了。
看起來,這很符合邏輯,先收拾房間嘛,收拾完之后,發(fā)現(xiàn)房間太臟了,要掃地拖地,我就創(chuàng)建一個掃地機(jī)器人,替我干活就好了。
回歸引言:隨手一時爽,一直隨手一直爽,重構(gòu)直接火葬場。
很奇怪,我們按照正常的邏輯,哪里不對呢?不對,不對大發(fā)了。
看似都狠符合邏輯,但是這是人的邏輯,不是機(jī)器的邏輯,在機(jī)器的世界里,他需要一個抽象的,秩序凌然的世界。房間就是用來展示,房間不會自己打掃自己,打掃的只能是工具人。工具人要分開,比如我就可以收拾衣服、收拾書、收拾電腦,而我的掃地機(jī)器人就會打掃指定區(qū)域。
那么這樣做還有其他好處嗎?有,當(dāng)有人接手你的代碼的時候,你希望別人上來就是一句“f**k”嗎?混亂的代碼,會意味著你的邏輯也是混亂的,也就是你在寫這塊的時候,并沒有想好要怎么做要做什么。通往高級的一個重要點(diǎn)就是需要有代碼設(shè)計能力,這個設(shè)計可以通俗的理解成抽象能力。
那么讓我們,提升抽象能力,開啟新的篇章,向高級邁進(jìn)!
按例:(先來介紹展示組件和容器組件)
Presentational components are concerned with how things look.展示組件關(guān)注事物的外觀
Container components are concerned with how things work.容器組件關(guān)注事物如何工作
很多人會好奇,這不是 React 老生常談的,拆分組件要注意展示組件和容器組件嘛?關(guān)我們寫函數(shù)有啥關(guān)系。其實不然,展示和容器其實追溯應(yīng)該回歸到mvc體系,我們應(yīng)該活用這樣的思想去整理自己的代碼,分析一下我們打掃房間這個過程。
- 房間僅做展示效果,無論是臟亂,還是干凈整潔。
- 我可以收拾衣服、書、電腦,講他們放到原位。
- 斯沃特機(jī)器人可以幫我打掃房間。
抽象出三個模塊,我、機(jī)器人、房間,我和機(jī)器人注重的是工作,房間注重的展示,畢竟她還不是一個成熟的房間,不會自己打掃。
首先創(chuàng)建一個PersonClass這個類是抽象類,包含基本功能,clean方法,用來收拾指定的事件。
// PersonClass
class PersonClass {
#name = '';
constructor(name) {
this.#name = name;
}
getName() {
return this.#name;
}
clean(event) {
console.log(`${this.#name} packed up ${event}`);
}
}
在確認(rèn)了本寶寶雖然是個寶寶但是還是個人這個事實,我決定,需要實現(xiàn)一個PersonClass類,然后我去繼承一下,但是我這個人比較厲害,我不是只能干一件事,我可以按照隊列執(zhí)行任務(wù)。
// IhapMrFatClass
class IhapMrFatClass extends PersonClass {
#room = '';
#packedEventQueue = [];
constructor(name, room) {
super(name);
this.#room = room;
this.#packedEventQueue = room.getPackedEventQueue();
}
clean() {
let event = '';
while ((event = this.#packedEventQueue.shift())) {
super.clean(event);
}
this.#room.setPackedEventQueue(this.#packedEventQueue);
}
}
繼續(xù)我們搞一個機(jī)器人類,機(jī)器人類也是一個抽象類,當(dāng)然和我們?nèi)祟愐膊畈欢?,也有一個clean方法。
// RobotClass
class RobotClass {
#name = '機(jī)器人';
constructor(name) {
this.#name = name;
}
getName() {
return this.#name;
}
clean(range) {
console.log(`${this.#name} -> ${range}: cleaned`);
}
}
接下來創(chuàng)建一個掃地機(jī)器人類來繼承機(jī)器人類,掃地機(jī)器人就是需要一個區(qū)域范圍,然后在區(qū)域范圍內(nèi)打掃。
// SweepRobotClass
class SweepRobotClass extends RobotClass {
#room = '';
#cleanedRange = [];
constructor(name, room) {
super(name);
this.#room = room;
this.#cleanedRange = room.getCleanedRange();
}
clean() {
let range = '';
while ((range = this.#cleanedRange.shift())) {
super.clean(range);
}
this.#room.setCleanedRange(this.#cleanedRange);
}
}
好了,既然兩個“工具人”都搞定了,我們就來搞一搞我們的展示組件,展示組件需要的就是進(jìn)行房間初始化,當(dāng)房間在創(chuàng)建的時候,就有一個待打掃隊列,比如packedEventQueue待收拾事件隊列以及cleanedRange待清潔區(qū)域,在渲染render的時候,首先檢查一下頁面清理狀態(tài),然后根據(jù)狀態(tài)告訴大家,是否干凈。本身是不會與外界有任何交互,僅會提供一些方法出去,交給外部去處理。換句話就是,作為一個不成熟的RoomClass,她是不會自己打掃自己的,她也不管到底是誰打掃,總之,她里面就是包含待收拾事件隊列以及待清潔區(qū)域,只要打掃干凈了,她就認(rèn)為干凈了。
// RoomClass
class RoomClass {
#packedEventQueue = [];
#cleanedRange = [];
#clearStatus = false;
constructor(initStatus) {
const { packedEventQueue, cleanedRange } = initStatus;
this.#packedEventQueue = packedEventQueue;
this.#cleanedRange = cleanedRange;
}
setPackedEventQueue(packedEventQueue) {
this.#packedEventQueue = packedEventQueue;
}
getPackedEventQueue() {
return this.#packedEventQueue;
}
setCleanedRange(cleanedRange) {
this.#cleanedRange = cleanedRange;
}
getCleanedRange() {
return this.#cleanedRange;
}
_checkClearStatus() {
this.#clearStatus = !(this.#packedEventQueue.length || this.#cleanedRange.length);
}
render() {
this._checkClearStatus();
console.log(this.#clearStatus ? '干凈的房間' : '臟亂的房間');
}
}
好了,讓我們用起來吧
const packedEventQueue = ['clothes', 'book', 'laptop'];
const cleanedRange = ['廚房', '洗手間', '客廳', '陽臺'];
const ihapMrFatRoom = new RoomClass({ packedEventQueue, cleanedRange });
ihapMrFatRoom.render();
// 臟亂的房間
const ihapMrFat = new IhapMrFatClass('ihap 肥少', ihapMrFatRoom);
ihapMrFat.clean();
const sweepRobot = new SweepRobotClass('掃地機(jī)器人', ihapMrFatRoom);
sweepRobot.clean();
ihapMrFatRoom.render();
// 干凈的房間
這樣,主函數(shù)是不是很清晰明了了呢,不光我們的主函數(shù)清晰明了,我們的各大工具人也分工明確,做著他們工具人的本分,而我們的展示組件,也在盡心盡力的展示著我房間從臟亂到干凈的過程。
請注意,不是任何情況都要有展示組件,展示組件也不是一定不能做任何的邏輯,只是展示組件不對外做任何處理。
打掃完了房間,朋友們也差不多到了,我們 high 了一晚,結(jié)果,第二天我醒來之后,又是臟亂的房間。
啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊
我是 ihap 肥少,喜歡我的文章,請關(guān)注喲。我們是 ihap 技術(shù)黑洞,更多咨詢、擼貓一手資料,快關(guān)注吧!
參考文獻(xiàn):