国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Jadual Kandungan
" >Tentukan siri algoritma, rangkumkan satu demi satu. satu, dan menjadikannya boleh ditukar ganti.
" > menyediakan pengganti atau pemegang tempat untuk objek. supaya Kawal akses kepadanya
" >Corak lelaran merujuk kepada menyediakan kaedah untuk mengakses setiap satu secara berurutan. elemen dalam objek agregat tanpa mendedahkannya Perwakilan dalaman objek ini.
五、發(fā)布-訂閱模式" >五、發(fā)布-訂閱模式
六、命令模式" >六、命令模式
七、組合模式" >七、組合模式
八、模板方法模式" >八、模板方法模式
九、享元模式" >九、享元模式
十、職責(zé)鏈模式" >十、職責(zé)鏈模式
十一、中介者模式" >十一、中介者模式
十二、裝飾者模式" >十二、裝飾者模式
十三、狀態(tài)模式" >十三、狀態(tài)模式
十四、適配器模式" >十四、適配器模式
十五、外觀模式" >十五、外觀模式
Rumah hujung hadapan web Soal Jawab bahagian hadapan Apakah corak reka bentuk dalam javascript

Apakah corak reka bentuk dalam javascript

Jan 26, 2022 pm 04:49 PM
javascript corak reka bentuk

Corak reka bentuk dalam JavaScript termasuk: mod tunggal, mod strategi, mod proksi, mod lelaran, mod "terbit-langgan", mod arahan, mod gabungan, mod kaedah templat, mod flyweight, Corak rantai tanggungjawab, corak pengantara, corak penghias, corak keadaan, corak penyesuai, corak penampilan, dsb.

Apakah corak reka bentuk dalam javascript

Persekitaran pengendalian tutorial ini: sistem Windows 7, versi JavaScript 1.8.5, komputer Dell G3.

Lima belas corak reka bentuk biasa dalam JavaScript

1 . Definisi

Memastikan kelas hanya mempunyai satu tika dan menyediakan pusat akses global untuk mengaksesnya

2 hanya terdapat satu contoh dan menyediakan akses global

3 Pelaksanaan

Dengan mengandaikan bahawa kami ingin menyediakan pentadbir dan hanya menetapkannya sekali untuk berbilang panggilan, kami boleh. Gunakan penutupan untuk cache pembolehubah dalaman untuk melaksanakan tunggal ini

Ini adalah pendekatan yang agak mudah, tetapi bagaimana jika kita juga mahu menyediakan HR? Anda perlu menyalin kod Oleh itu, anda boleh menulis semula bahagian dalam singleton untuk menjadikannya lebih umum

dan memanggilnya semula, hasilnya masih sama
function SetManager(name) {
    this.manager = name;
}

SetManager.prototype.getName = function() {
    console.log(this.manager);
};

var SingletonSetManager = (function() {
    var manager = null;

    return function(name) {
        if (!manager) {
            manager = new SetManager(name);
        }

        return manager;
    } 
})();

SingletonSetManager('a').getName(); // a
SingletonSetManager('b').getName(); // a
SingletonSetManager('c').getName(); // a

Pada masa ini, apabila kita menambah HR, kita tidak perlu mengubah pelaksanaan di dalam tunggal Kita hanya perlu melaksanakan apa yang diperlukan untuk menambah HR, dan kemudian memanggilnya

// 提取出通用的單例
function getSingleton(fn) {
    var instance = null;

    return function() {
        if (!instance) {
            instance = fn.apply(this, arguments);
        }

        return instance;
    }
}
Atau, hanya ingin mencipta lapisan p, tidak perlu membuat instantiat objek, dan fungsi

dipanggil terus Hasilnya hanya terdapat p
// 獲取單例
var managerSingleton = getSingleton(function(name) {
    var manager = new SetManager(name);
    return manager;
});

managerSingleton('a').getName(); // a
managerSingleton('b').getName(); // a
managerSingleton('c').getName(); // a
< yang pertama ??>

pada halaman 2. Mod strategi
function SetHr(name) {
    this.hr = name;
}

SetHr.prototype.getName = function() {
    console.log(this.hr);
};

var hrSingleton = getSingleton(function(name) {
    var hr = new SetHr(name);
    return hr;
});

hrSingleton(&#39;aa&#39;).getName(); // aa
hrSingleton(&#39;bb&#39;).getName(); // aa
hrSingleton(&#39;cc&#39;).getName(); // aa

1 Definisi

function createPopup(html) {
    var div = document.createElement(&#39;div&#39;);
    div.innerHTML = html;
    document.body.append(div);

    return div;
}

var popupSingleton = getSingleton(function() {
    var div = createPopup.apply(this, arguments);
    return div;
});

console.log(
    popupSingleton(&#39;aaa&#39;).innerHTML,
    popupSingleton(&#39;bbb&#39;).innerHTML,
    popupSingleton(&#39;bbb&#39;).innerHTML
); // aaa  aaa  aaa

Tentukan siri algoritma, rangkumkan satu demi satu. satu, dan menjadikannya boleh ditukar ganti.

2. Teras

memisahkan penggunaan algoritma daripada pelaksanaan algoritma.

Atur cara berdasarkan corak strategi terdiri daripada sekurang-kurangnya dua bahagian:

Bahagian pertama ialah satu set kelas strategi Kelas strategi merangkum algoritma tertentu dan bertanggungjawab untuk proses pengiraan tertentu . Bahagian kedua ialah Konteks kelas persekitaran menerima permintaan pelanggan dan kemudian mewakilkan permintaan itu kepada kelas strategi tertentu. Untuk melakukan ini, adalah perlu untuk mengekalkan rujukan kepada objek strategi dalam Konteks

3 Pelaksanaan

Corak strategi boleh digunakan untuk menggabungkan satu siri. algoritma, dan Boleh digunakan untuk menggabungkan satu siri peraturan perniagaan

Katakan adalah perlu untuk mengira markah akhir pelajar mengikut gred, dan setiap gred mempunyai nilai wajaran yang sepadan. Kami boleh mentakrifkan secara langsung dasar kumpulan ini dalam bentuk literal objek

Dari segi menggabungkan peraturan perniagaan, yang lebih klasik ialah kaedah pengesahan bentuk. Berikut adalah bahagian yang lebih kritikal

4. Kebaikan dan keburukan

// 加權(quán)映射關(guān)系
var levelMap = {
    S: 10,
    A: 8,
    B: 6,
    C: 4
};

// 組策略
var scoreLevel = {
    basicScore: 80,

    S: function() {
        return this.basicScore + levelMap[&#39;S&#39;]; 
    },

    A: function() {
        return this.basicScore + levelMap[&#39;A&#39;]; 
    },

    B: function() {
        return this.basicScore + levelMap[&#39;B&#39;]; 
    },

    C: function() {
        return this.basicScore + levelMap[&#39;C&#39;]; 
    }
}

// 調(diào)用
function getScore(level) {
    return scoreLevel[level] ? scoreLevel[level]() : 0;
}

console.log(
    getScore(&#39;S&#39;),
    getScore(&#39;A&#39;),
    getScore(&#39;B&#39;),
    getScore(&#39;C&#39;),
    getScore(&#39;D&#39;)
); // 90 88 86 84 0

Kelebihan

// 錯(cuò)誤提示
var errorMsgs = {
    default: &#39;輸入數(shù)據(jù)格式不正確&#39;,
    minLength: &#39;輸入數(shù)據(jù)長(zhǎng)度不足&#39;,
    isNumber: &#39;請(qǐng)輸入數(shù)字&#39;,
    required: &#39;內(nèi)容不為空&#39;
};

// 規(guī)則集
var rules = {
    minLength: function(value, length, errorMsg) {
        if (value.length < length) {
            return errorMsg || errorMsgs[&#39;minLength&#39;]
        }
    },
    isNumber: function(value, errorMsg) {
        if (!/\d+/.test(value)) {
            return errorMsg || errorMsgs[&#39;isNumber&#39;];
        }
    },
    required: function(value, errorMsg) {
        if (value === &#39;&#39;) {
            return errorMsg || errorMsgs[&#39;required&#39;];
        }
    }
};

// 校驗(yàn)器
function Validator() {
    this.items = [];
};

Validator.prototype = {
    constructor: Validator,
    
    // 添加校驗(yàn)規(guī)則
    add: function(value, rule, errorMsg) {
        var arg = [value];

        if (rule.indexOf(&#39;minLength&#39;) !== -1) {
            var temp = rule.split(&#39;:&#39;);
            arg.push(temp[1]);
            rule = temp[0];
        }

        arg.push(errorMsg);

        this.items.push(function() {
            // 進(jìn)行校驗(yàn)
            return rules[rule].apply(this, arg);
        });
    },
    
    // 開始校驗(yàn)
    start: function() {
        for (var i = 0; i < this.items.length; ++i) {
            var ret = this.items[i]();
            
            if (ret) {
                console.log(ret);
                // return ret;
            }
        }
    }
};

// 測(cè)試數(shù)據(jù)
function testTel(val) {
    return val;
}

var validate = new Validator();

validate.add(testTel(&#39;ccc&#39;), &#39;isNumber&#39;, &#39;只能為數(shù)字&#39;); // 只能為數(shù)字
validate.add(testTel(&#39;&#39;), &#39;required&#39;); // 內(nèi)容不為空
validate.add(testTel(&#39;123&#39;), &#39;minLength:5&#39;, &#39;最少5位&#39;); // 最少5位
validate.add(testTel(&#39;12345&#39;), &#39;minLength:5&#39;, &#39;最少5位&#39;);

var ret = validate.start();

console.log(ret);

Dapat mengelakkan berbilang Bersyarat dengan berkesan kenyataan merangkumi satu siri kaedah dan lebih intuitif, yang lebih mudah untuk dikekalkan

Kelemahan

Selalunya terdapat banyak set dasar, dan kita perlu memahami dan menentukan. semua situasi lebih awal

3. Corak proksi

1. Definisi

menyediakan pengganti atau pemegang tempat untuk objek. supaya Kawal akses kepadanya

2. Teras

Apabila menyusahkan pelanggan untuk mengakses objek secara langsung atau tidak memenuhi keperluan mereka, sediakan objek pengganti kepada mengawal akses kepada akses objek, pelanggan sebenarnya mengakses objek berdiri.

Selepas objek stand-in melakukan beberapa pemprosesan pada permintaan, ia kemudian memindahkan permintaan ke objek ontologi

Antara muka ejen dan ontologi adalah konsisten fungsi, dan ejen menyediakan atau menolak Aksesnya, atau lakukan beberapa perkara tambahan sebelum mengakses ontologi

3 Pelaksanaan

Terdapat tiga mod proksi utama: proksi perlindungan. , proksi maya, proksi caching

Agen perlindungan terutamanya melaksanakan tingkah laku menyekat subjek akses, mengambil aksara penapisan sebagai contoh mudah

Niatnya adalah jelas, untuk mengawal sebelum mengakses subjek, apabila tiada mesej Ia dikembalikan secara langsung dalam proksi dan akses kepada subjek ditolak. Bentuk proksi perlindungan data ini

memproses aksara sensitif apabila terdapat mesej ini proksi maya

Proksi maya berada dalam kawalan Apabila mengakses badan utama, beberapa operasi tambahan ditambahkan

Apabila acara tatal dicetuskan, ia mungkin tidak perlu dicetuskan dengan kerap pendikitan fungsi, yang merupakan pelaksanaan ejen maya
// 主體,發(fā)送消息
function sendMsg(msg) {
    console.log(msg);
}

// 代理,對(duì)消息進(jìn)行過濾
function proxySendMsg(msg) {
    // 無消息則直接返回
    if (typeof msg === &#39;undefined&#39;) {
        console.log(&#39;deny&#39;);
        return;
    }
    
    // 有消息則進(jìn)行過濾
    msg = (&#39;&#39; + msg).replace(/泥\s*煤/g, &#39;&#39;);

    sendMsg(msg);
}


sendMsg(&#39;泥煤呀泥 煤呀&#39;); // 泥煤呀泥 煤呀
proxySendMsg(&#39;泥煤呀泥 煤&#39;); // 呀
proxySendMsg(); // deny

Ejen cache boleh menyediakan caching sementara untuk beberapa hasil operasi yang mahal untuk meningkatkan kecekapan

Sebagai contoh, operasi penambahan cache

4. Corak Iterasi Lelaran
// 函數(shù)防抖,頻繁操作中不處理,直到操作完成之后(再過 delay 的時(shí)間)才一次性處理
function debounce(fn, delay) {
    delay = delay || 200;
    
    var timer = null;

    return function() {
        var arg = arguments;
          
        // 每次操作時(shí),清除上次的定時(shí)器
        clearTimeout(timer);
        timer = null;
        
        // 定義新的定時(shí)器,一段時(shí)間后進(jìn)行操作
        timer = setTimeout(function() {
            fn.apply(this, arg);
        }, delay);
    }
};

var count = 0;

// 主體
function scrollHandle(e) {
    console.log(e.type, ++count); // scroll
}

// 代理
var proxyScrollHandle = (function() {
    return debounce(scrollHandle, 500);
})();

window.onscroll = proxyScrollHandle;

1 Definisi

// 主體
function add() {
    var arg = [].slice.call(arguments);

    return arg.reduce(function(a, b) {
        return a + b;
    });
}

// 代理
var proxyAdd = (function() {
    var cache = [];

    return function() {
        var arg = [].slice.call(arguments).join(&#39;,&#39;);
        
        // 如果有,則直接從緩存返回
        if (cache[arg]) {
            return cache[arg];
        } else {
            var ret = add.apply(this, arguments);
            return ret;
        }
    };
})();

console.log(
    add(1, 2, 3, 4),
    add(1, 2, 3, 4),

    proxyAdd(10, 20, 30, 40),
    proxyAdd(10, 20, 30, 40)
); // 10 10 100 100

Corak lelaran merujuk kepada menyediakan kaedah untuk mengakses setiap satu secara berurutan. elemen dalam objek agregat tanpa mendedahkannya Perwakilan dalaman objek ini.

2. Teras

Selepas menggunakan corak lelaran, walaupun anda tidak mengambil berat tentang struktur dalaman objek, anda boleh mengakses setiap elemen di dalamnya secara berurutan

3. Pelaksanaan

JS中數(shù)組的map forEach 已經(jīng)內(nèi)置了迭代器

[1, 2, 3].forEach(function(item, index, arr) {
    console.log(item, index, arr);
});

不過對(duì)于對(duì)象的遍歷,往往不能與數(shù)組一樣使用同一的遍歷代碼

我們可以封裝一下

function each(obj, cb) {
    var value;

    if (Array.isArray(obj)) {
        for (var i = 0; i < obj.length; ++i) {
            value = cb.call(obj[i], i, obj[i]);

            if (value === false) {
                break;
            }
        }
    } else {
        for (var i in obj) {
            value = cb.call(obj[i], i, obj[i]);

            if (value === false) {
                break;
            }
        }
    }
}

each([1, 2, 3], function(index, value) {
    console.log(index, value);
});

each({a: 1, b: 2}, function(index, value) {
    console.log(index, value);
});

// 0 1
// 1 2
// 2 3

// a 1
// b 2

再來看一個(gè)例子,強(qiáng)行地使用迭代器,來了解一下迭代器也可以替換頻繁的條件語(yǔ)句

雖然例子不太好,但在其他負(fù)責(zé)的分支判斷情況下,也是值得考慮的

function getManager() {
    var year = new Date().getFullYear();

    if (year <= 2000) {
        console.log(&#39;A&#39;);
    } else if (year >= 2100) {
        console.log(&#39;C&#39;);
    } else {
        console.log(&#39;B&#39;);
    }
}

getManager(); // B

將每個(gè)條件語(yǔ)句拆分出邏輯函數(shù),放入迭代器中迭代

function year2000() {
    var year = new Date().getFullYear();

    if (year <= 2000) {
        console.log(&#39;A&#39;);
    }

    return false;
}

function year2100() {
    var year = new Date().getFullYear();

    if (year >= 2100) {
        console.log(&#39;C&#39;);
    }

    return false;
}

function year() {
    var year = new Date().getFullYear();

    if (year > 2000 && year < 2100) {
        console.log(&#39;B&#39;);
    }

    return false;
}

function iteratorYear() {
    for (var i = 0; i < arguments.length; ++i) {
        var ret = arguments[i]();

        if (ret !== false) {
            return ret;
        }
    }
}

var manager = iteratorYear(year2000, year2100, year); // B

五、發(fā)布-訂閱模式

1. 定義

也稱作觀察者模式,定義了對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā) 生改變時(shí),所有依賴于它的對(duì)象都將得到通知

2. 核心

取代對(duì)象之間硬編碼的通知機(jī)制,一個(gè)對(duì)象不用再顯式地調(diào)用另外一個(gè)對(duì)象的某個(gè)接口。

與傳統(tǒng)的發(fā)布-訂閱模式實(shí)現(xiàn)方式(將訂閱者自身當(dāng)成引用傳入發(fā)布者)不同,在JS中通常使用注冊(cè)回調(diào)函數(shù)的形式來訂閱

3. 實(shí)現(xiàn)

JS中的事件就是經(jīng)典的發(fā)布-訂閱模式的實(shí)現(xiàn)

// 訂閱
document.body.addEventListener(&#39;click&#39;, function() {
    console.log(&#39;click1&#39;);
}, false);

document.body.addEventListener(&#39;click&#39;, function() {
    console.log(&#39;click2&#39;);
}, false);

// 發(fā)布
document.body.click(); // click1  click2

自己實(shí)現(xiàn)一下

小A在公司C完成了筆試及面試,小B也在公司C完成了筆試。他們焦急地等待結(jié)果,每隔半天就電話詢問公司C,導(dǎo)致公司C很不耐煩。

一種解決辦法是 AB直接把聯(lián)系方式留給C,有結(jié)果的話C自然會(huì)通知AB

這里的“詢問”屬于顯示調(diào)用,“留給”屬于訂閱,“通知”屬于發(fā)布

// 觀察者
var observer = {
    // 訂閱集合
    subscribes: [],

    // 訂閱
    subscribe: function(type, fn) {
        if (!this.subscribes[type]) {
            this.subscribes[type] = [];
        }
        
        // 收集訂閱者的處理
        typeof fn === &#39;function&#39; && this.subscribes[type].push(fn);
    },

    // 發(fā)布  可能會(huì)攜帶一些信息發(fā)布出去
    publish: function() {
        var type = [].shift.call(arguments),
            fns = this.subscribes[type];
        
        // 不存在的訂閱類型,以及訂閱時(shí)未傳入處理回調(diào)的
        if (!fns || !fns.length) {
            return;
        }
        
        // 挨個(gè)處理調(diào)用
        for (var i = 0; i < fns.length; ++i) {
            fns[i].apply(this, arguments);
        }
    },
    
    // 刪除訂閱
    remove: function(type, fn) {
        // 刪除全部
        if (typeof type === &#39;undefined&#39;) {
            this.subscribes = [];
            return;
        }

        var fns = this.subscribes[type];

        // 不存在的訂閱類型,以及訂閱時(shí)未傳入處理回調(diào)的
        if (!fns || !fns.length) {
            return;
        }

        if (typeof fn === &#39;undefined&#39;) {
            fns.length = 0;
            return;
        }

        // 挨個(gè)處理刪除
        for (var i = 0; i < fns.length; ++i) {
            if (fns[i] === fn) {
                fns.splice(i, 1);
            }
        }
    }
};

// 訂閱崗位列表
function jobListForA(jobs) {
    console.log(&#39;A&#39;, jobs);
}

function jobListForB(jobs) {
    console.log(&#39;B&#39;, jobs);
}

// A訂閱了筆試成績(jī)
observer.subscribe(&#39;job&#39;, jobListForA);
// B訂閱了筆試成績(jī)
observer.subscribe(&#39;job&#39;, jobListForB);


// A訂閱了筆試成績(jī)
observer.subscribe(&#39;examinationA&#39;, function(score) {
    console.log(score);
});

// B訂閱了筆試成績(jī)
observer.subscribe(&#39;examinationB&#39;, function(score) {
    console.log(score);
});

// A訂閱了面試結(jié)果
observer.subscribe(&#39;interviewA&#39;, function(result) {
    console.log(result);
});

observer.publish(&#39;examinationA&#39;, 100); // 100
observer.publish(&#39;examinationB&#39;, 80); // 80
observer.publish(&#39;interviewA&#39;, &#39;備用&#39;); // 備用

observer.publish(&#39;job&#39;, [&#39;前端&#39;, &#39;后端&#39;, &#39;測(cè)試&#39;]); // 輸出A和B的崗位


// B取消訂閱了筆試成績(jī)
observer.remove(&#39;examinationB&#39;);
// A都取消訂閱了崗位
observer.remove(&#39;job&#39;, jobListForA);

observer.publish(&#39;examinationB&#39;, 80); // 沒有可匹配的訂閱,無輸出
observer.publish(&#39;job&#39;, [&#39;前端&#39;, &#39;后端&#39;, &#39;測(cè)試&#39;]); // 輸出B的崗位

4. 優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

一為時(shí)間上的解耦,二為對(duì)象之間的解耦??梢杂迷诋惒骄幊讨信cMV*框架中

缺點(diǎn)

創(chuàng)建訂閱者本身要消耗一定的時(shí)間和內(nèi)存,訂閱的處理函數(shù)不一定會(huì)被執(zhí)行,駐留內(nèi)存有性能開銷

弱化了對(duì)象之間的聯(lián)系,復(fù)雜的情況下可能會(huì)導(dǎo)致程序難以跟蹤維護(hù)和理解

六、命令模式

1. 定義

用一種松耦合的方式來設(shè)計(jì)程序,使得請(qǐng)求發(fā)送者和請(qǐng)求接收者能夠消除彼此之間的耦合關(guān)系

命令(command)指的是一個(gè)執(zhí)行某些特定事情的指令

2. 核心

命令中帶有execute執(zhí)行、undo撤銷、redo重做等相關(guān)命令方法,建議顯示地指示這些方法名

3. 實(shí)現(xiàn)

簡(jiǎn)單的命令模式實(shí)現(xiàn)可以直接使用對(duì)象字面量的形式定義一個(gè)命令

var incrementCommand = {
    execute: function() {
        // something
    }
};

不過接下來的例子是一個(gè)自增命令,提供執(zhí)行、撤銷、重做功能

采用對(duì)象創(chuàng)建處理的方式,定義這個(gè)自增

// 自增
function IncrementCommand() {
    // 當(dāng)前值
    this.val = 0;
    // 命令棧
    this.stack = [];
    // 棧指針位置
    this.stackPosition = -1;
};

IncrementCommand.prototype = {
    constructor: IncrementCommand,

    // 執(zhí)行
    execute: function() {
        this._clearRedo();
        
        // 定義執(zhí)行的處理
        var command = function() {
            this.val += 2;
        }.bind(this);
        
        // 執(zhí)行并緩存起來
        command();
        
        this.stack.push(command);

        this.stackPosition++;

        this.getValue();
    },
    
    canUndo: function() {
        return this.stackPosition >= 0;
    },
    
    canRedo: function() {
        return this.stackPosition < this.stack.length - 1;
    },

    // 撤銷
    undo: function() {
        if (!this.canUndo()) {
            return;
        }
        
        this.stackPosition--;

        // 命令的撤銷,與執(zhí)行的處理相反
        var command = function() {
            this.val -= 2;
        }.bind(this);
        
        // 撤銷后不需要緩存
        command();

        this.getValue();
    },
    
    // 重做
    redo: function() {
        if (!this.canRedo()) {
            return;
        }
        
        // 執(zhí)行棧頂?shù)拿?        this.stack[++this.stackPosition]();

        this.getValue();
    },
    
    // 在執(zhí)行時(shí),已經(jīng)撤銷的部分不能再重做
    _clearRedo: function() {
        this.stack = this.stack.slice(0, this.stackPosition + 1);
    },
    
    // 獲取當(dāng)前值
    getValue: function() {
        console.log(this.val);
    }
};

再實(shí)例化進(jìn)行測(cè)試,模擬執(zhí)行、撤銷、重做的操作

var incrementCommand = new IncrementCommand();

// 模擬事件觸發(fā),執(zhí)行命令
var eventTrigger = {
    // 某個(gè)事件的處理中,直接調(diào)用命令的處理方法
    increment: function() {
        incrementCommand.execute();
    },

    incrementUndo: function() {
        incrementCommand.undo();
    },

    incrementRedo: function() {
        incrementCommand.redo();
    }
};


eventTrigger[&#39;increment&#39;](); // 2
eventTrigger[&#39;increment&#39;](); // 4

eventTrigger[&#39;incrementUndo&#39;](); // 2

eventTrigger[&#39;increment&#39;](); // 4

eventTrigger[&#39;incrementUndo&#39;](); // 2
eventTrigger[&#39;incrementUndo&#39;](); // 0
eventTrigger[&#39;incrementUndo&#39;](); // 無輸出

eventTrigger[&#39;incrementRedo&#39;](); // 2
eventTrigger[&#39;incrementRedo&#39;](); // 4
eventTrigger[&#39;incrementRedo&#39;](); // 無輸出

eventTrigger[&#39;increment&#39;](); // 6

此外,還可以實(shí)現(xiàn)簡(jiǎn)單的宏命令(一系列命令的集合)

var MacroCommand = {
    commands: [],

    add: function(command) {
        this.commands.push(command);

        return this;
    },

    remove: function(command) {
        if (!command) {
            this.commands = [];
            return;
        }

        for (var i = 0; i < this.commands.length; ++i) {
            if (this.commands[i] === command) {
                this.commands.splice(i, 1);
            }
        }
    },

    execute: function() {
        for (var i = 0; i < this.commands.length; ++i) {
            this.commands[i].execute();
        }
    }
};

var showTime = {
    execute: function() {
        console.log(&#39;time&#39;);
    }
};

var showName = {
    execute: function() {
        console.log(&#39;name&#39;);
    }
};

var showAge = {
    execute: function() {
        console.log(&#39;age&#39;);
    }
};

MacroCommand.add(showTime).add(showName).add(showAge);

MacroCommand.remove(showName);

MacroCommand.execute(); // time age

七、組合模式

1. 定義

是用小的子對(duì)象來構(gòu)建更大的 對(duì)象,而這些小的子對(duì)象本身也許是由更小 的“孫對(duì)象”構(gòu)成的。

2. 核心

可以用樹形結(jié)構(gòu)來表示這種“部分- 整體”的層次結(jié)構(gòu)。

調(diào)用組合對(duì)象 的execute方法,程序會(huì)遞歸調(diào)用組合對(duì)象 下面的葉對(duì)象的execute方法

但要注意的是,組合模式不是父子關(guān)系,它是一種HAS-A(聚合)的關(guān)系,將請(qǐng)求委托給 它所包含的所有葉對(duì)象?;谶@種委托,就需要保證組合對(duì)象和葉對(duì)象擁有相同的 接口

此外,也要保證用一致的方式對(duì)待 列表中的每個(gè)葉對(duì)象,即葉對(duì)象屬于同一類,不需要過多特殊的額外操作

3. 實(shí)現(xiàn)

使用組合模式來實(shí)現(xiàn)掃描文件夾中的文件

// 文件夾 組合對(duì)象
function Folder(name) {
    this.name = name;
    this.parent = null;
    this.files = [];
}

Folder.prototype = {
    constructor: Folder,

    add: function(file) {
        file.parent = this;
        this.files.push(file);

        return this;
    },

    scan: function() {
        // 委托給葉對(duì)象處理
        for (var i = 0; i < this.files.length; ++i) {
            this.files[i].scan();
        }
    },

    remove: function(file) {
        if (typeof file === &#39;undefined&#39;) {
            this.files = [];
            return;
        }

        for (var i = 0; i < this.files.length; ++i) {
            if (this.files[i] === file) {
                this.files.splice(i, 1);
            }
        }
    }
};

// 文件 葉對(duì)象
function File(name) {
    this.name = name;
    this.parent = null;
}

File.prototype = {
    constructor: File,

    add: function() {
        console.log(&#39;文件里面不能添加文件&#39;);
    },

    scan: function() {
        var name = [this.name];
        var parent = this.parent;

        while (parent) {
            name.unshift(parent.name);
            parent = parent.parent;
        }

        console.log(name.join(&#39; / &#39;));
    }
};

構(gòu)造好組合對(duì)象與葉對(duì)象的關(guān)系后,實(shí)例化,在組合對(duì)象中插入組合或葉對(duì)象

var web = new Folder(&#39;Web&#39;);
var fe = new Folder(&#39;前端&#39;);
var css = new Folder(&#39;CSS&#39;);
var js = new Folder(&#39;js&#39;);
var rd = new Folder(&#39;后端&#39;);

web.add(fe).add(rd);

var file1 = new File(&#39;HTML權(quán)威指南.pdf&#39;);
var file2 = new File(&#39;CSS權(quán)威指南.pdf&#39;);
var file3 = new File(&#39;JavaScript權(quán)威指南.pdf&#39;);
var file4 = new File(&#39;MySQL基礎(chǔ).pdf&#39;);
var file5 = new File(&#39;Web安全.pdf&#39;);
var file6 = new File(&#39;Linux菜鳥.pdf&#39;);

css.add(file2);
fe.add(file1).add(file3).add(css).add(js);
rd.add(file4).add(file5);
web.add(file6);

rd.remove(file4);

// 掃描
web.scan();

掃描結(jié)果為

4. 優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

可 以方便地構(gòu)造一棵樹來表示對(duì)象的部分-整體 結(jié)構(gòu)。在樹的構(gòu)造最終 完成之后,只需要通過請(qǐng)求樹的最頂層對(duì) 象,便能對(duì)整棵樹做統(tǒng)一一致的操作。

缺點(diǎn)

創(chuàng)建出來的對(duì)象長(zhǎng)得都差不多,可能會(huì)使代碼不好理解,創(chuàng)建太多的對(duì)象對(duì)性能也會(huì)有一些影響

八、模板方法模式

1. 定義

模板方法模式由兩部分結(jié)構(gòu)組成,第一部分是抽象父類,第二部分是具體的實(shí)現(xiàn)子類。

2. 核心

在抽象父類中封裝子類的算法框架,它的 init方法可作為一個(gè)算法的模板,指導(dǎo)子類以何種順序去執(zhí)行哪些方法。

由父類分離出公共部分,要求子類重寫某些父類的(易變化的)抽象方法

3. 實(shí)現(xiàn)

模板方法模式一般的實(shí)現(xiàn)方式為繼承

以運(yùn)動(dòng)作為例子,運(yùn)動(dòng)有比較通用的一些處理,這部分可以抽離開來,在父類中實(shí)現(xiàn)。具體某項(xiàng)運(yùn)動(dòng)的特殊性則有自類來重寫實(shí)現(xiàn)。

最終子類直接調(diào)用父類的模板函數(shù)來執(zhí)行

// 體育運(yùn)動(dòng)
function Sport() {

}

Sport.prototype = {
    constructor: Sport,
    
    // 模板,按順序執(zhí)行
    init: function() {
        this.stretch();
        this.jog();
        this.deepBreath();
        this.start();

        var free = this.end();
        
        // 運(yùn)動(dòng)后還有空的話,就拉伸一下
        if (free !== false) {
            this.stretch();
        }
        
    },
    
    // 拉伸
    stretch: function() {
        console.log(&#39;拉伸&#39;);
    },
    
    // 慢跑
    jog: function() {
        console.log(&#39;慢跑&#39;);
    },
    
    // 深呼吸
    deepBreath: function() {
        console.log(&#39;深呼吸&#39;);
    },

    // 開始運(yùn)動(dòng)
    start: function() {
        throw new Error(&#39;子類必須重寫此方法&#39;);
    },

    // 結(jié)束運(yùn)動(dòng)
    end: function() {
        console.log(&#39;運(yùn)動(dòng)結(jié)束&#39;);
    }
};

// 籃球
function Basketball() {

}

Basketball.prototype = new Sport();

// 重寫相關(guān)的方法
Basketball.prototype.start = function() {
    console.log(&#39;先投上幾個(gè)三分&#39;);
};

Basketball.prototype.end = function() {
    console.log(&#39;運(yùn)動(dòng)結(jié)束了,有事先走一步&#39;);
    return false;
};


// 馬拉松
function Marathon() {

}

Marathon.prototype = new Sport();

var basketball = new Basketball();
var marathon = new Marathon();

// 子類調(diào)用,最終會(huì)按照父類定義的順序執(zhí)行
basketball.init();
marathon.init();

九、享元模式

1. 定義

享元(flyweight)模式是一種用于性能優(yōu)化的模式,它的目標(biāo)是盡量減少共享對(duì)象的數(shù)量

2. 核心

運(yùn)用共享技術(shù)來有效支持大量細(xì)粒度的對(duì)象。

強(qiáng)調(diào)將對(duì)象的屬性劃分為內(nèi)部狀態(tài)(屬性)與外部狀態(tài)(屬性)。內(nèi)部狀態(tài)用于對(duì)象的共享,通常不變;而外部狀態(tài)則剝離開來,由具體的場(chǎng)景決定。

3. 實(shí)現(xiàn)

在程序中使用了大量的相似對(duì)象時(shí),可以利用享元模式來優(yōu)化,減少對(duì)象的數(shù)量

舉個(gè)栗子,要對(duì)某個(gè)班進(jìn)行身體素質(zhì)測(cè)量,僅測(cè)量身高體重來評(píng)判

// 健康測(cè)量
function Fitness(name, sex, age, height, weight) {
    this.name = name;
    this.sex = sex;
    this.age = age;
    this.height = height;
    this.weight = weight;
}

// 開始評(píng)判
Fitness.prototype.judge = function() {
    var ret = this.name + &#39;: &#39;;

    if (this.sex === &#39;male&#39;) {
        ret += this.judgeMale();
    } else {
        ret += this.judgeFemale();
    }

    console.log(ret);
};

// 男性評(píng)判規(guī)則
Fitness.prototype.judgeMale = function() {
    var ratio = this.height / this.weight;

    return this.age > 20 ? (ratio > 3.5) : (ratio > 2.8);
};

// 女性評(píng)判規(guī)則
Fitness.prototype.judgeFemale = function() {
    var ratio = this.height / this.weight;
    
    return this.age > 20 ? (ratio > 4) : (ratio > 3);
};


var a = new Fitness(&#39;A&#39;, &#39;male&#39;, 18, 160, 80);
var b = new Fitness(&#39;B&#39;, &#39;male&#39;, 21, 180, 70);
var c = new Fitness(&#39;C&#39;, &#39;female&#39;, 28, 160, 80);
var d = new Fitness(&#39;D&#39;, &#39;male&#39;, 18, 170, 60);
var e = new Fitness(&#39;E&#39;, &#39;female&#39;, 18, 160, 40);

// 開始評(píng)判
a.judge(); // A: false
b.judge(); // B: false
c.judge(); // C: false
d.judge(); // D: true
e.judge(); // E: true

評(píng)判五個(gè)人就需要?jiǎng)?chuàng)建五個(gè)對(duì)象,一個(gè)班就幾十個(gè)對(duì)象

可以將對(duì)象的公共部分(內(nèi)部狀態(tài))抽離出來,與外部狀態(tài)獨(dú)立。將性別看做內(nèi)部狀態(tài)即可,其他屬性都屬于外部狀態(tài)。

這么一來我們只需要維護(hù)男和女兩個(gè)對(duì)象(使用factory對(duì)象),而其他變化的部分則在外部維護(hù)(使用manager對(duì)象)

// 健康測(cè)量
function Fitness(sex) {
    this.sex = sex;
}

// 工廠,創(chuàng)建可共享的對(duì)象
var FitnessFactory = {
    objs: [],

    create: function(sex) {
        if (!this.objs[sex]) {
            this.objs[sex] = new Fitness(sex);
        }

        return this.objs[sex];
    }
};

// 管理器,管理非共享的部分
var FitnessManager = {
    fitnessData: {},
    
    // 添加一項(xiàng)
    add: function(name, sex, age, height, weight) {
        var fitness = FitnessFactory.create(sex);
        
        // 存儲(chǔ)變化的數(shù)據(jù)
        this.fitnessData[name] = {
            age: age,
            height: height,
            weight: weight
        };

        return fitness;
    },
    
    // 從存儲(chǔ)的數(shù)據(jù)中獲取,更新至當(dāng)前正在使用的對(duì)象
    updateFitnessData: function(name, obj) {
        var fitnessData = this.fitnessData[name];

        for (var item in fitnessData) {
            if (fitnessData.hasOwnProperty(item)) {
                obj[item] = fitnessData[item];
            }
        }
    }
};

// 開始評(píng)判
Fitness.prototype.judge = function(name) {
    // 操作前先更新當(dāng)前狀態(tài)(從外部狀態(tài)管理器中獲?。?    FitnessManager.updateFitnessData(name, this);

    var ret = name + &#39;: &#39;;

    if (this.sex === &#39;male&#39;) {
        ret += this.judgeMale();
    } else {
        ret += this.judgeFemale();
    }

    console.log(ret);
};

// 男性評(píng)判規(guī)則
Fitness.prototype.judgeMale = function() {
    var ratio = this.height / this.weight;

    return this.age > 20 ? (ratio > 3.5) : (ratio > 2.8);
};

// 女性評(píng)判規(guī)則
Fitness.prototype.judgeFemale = function() {
    var ratio = this.height / this.weight;
    
    return this.age > 20 ? (ratio > 4) : (ratio > 3);
};


var a = FitnessManager.add(&#39;A&#39;, &#39;male&#39;, 18, 160, 80);
var b = FitnessManager.add(&#39;B&#39;, &#39;male&#39;, 21, 180, 70);
var c = FitnessManager.add(&#39;C&#39;, &#39;female&#39;, 28, 160, 80);
var d = FitnessManager.add(&#39;D&#39;, &#39;male&#39;, 18, 170, 60);
var e = FitnessManager.add(&#39;E&#39;, &#39;female&#39;, 18, 160, 40);

// 開始評(píng)判
a.judge(&#39;A&#39;); // A: false
b.judge(&#39;B&#39;); // B: false
c.judge(&#39;C&#39;); // C: false
d.judge(&#39;D&#39;); // D: true
e.judge(&#39;E&#39;); // E: true

不過代碼可能更復(fù)雜了,這個(gè)例子可能還不夠充分,只是展示了享元模式如何實(shí)現(xiàn),它節(jié)省了多個(gè)相似的對(duì)象,但多了一些操作。

factory對(duì)象有點(diǎn)像單例模式,只是多了一個(gè)sex的參數(shù),如果沒有內(nèi)部狀態(tài),則沒有參數(shù)的factory對(duì)象就更接近單例模式了

十、職責(zé)鏈模式

1. 定義

使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系,將這些對(duì)象連成一條鏈,并沿著這條鏈 傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理它為止

2. 核心

請(qǐng)求發(fā)送者只需要知道鏈中的第一個(gè)節(jié)點(diǎn),弱化發(fā)送者和一組接收者之間的強(qiáng)聯(lián)系,可以便捷地在職責(zé)鏈中增加或刪除一個(gè)節(jié)點(diǎn),同樣地,指定誰(shuí)是第一個(gè)節(jié)點(diǎn)也很便捷

3. 實(shí)現(xiàn)

以展示不同類型的變量為例,設(shè)置一條職責(zé)鏈,可以免去多重if條件分支

// 定義鏈的某一項(xiàng)
function ChainItem(fn) {
    this.fn = fn;
    this.next = null;
}

ChainItem.prototype = {
    constructor: ChainItem,
    
    // 設(shè)置下一項(xiàng)
    setNext: function(next) {
        this.next = next;
        return next;
    },
    
    // 開始執(zhí)行
    start: function() {
        this.fn.apply(this, arguments);
    },
    
    // 轉(zhuǎn)到鏈的下一項(xiàng)執(zhí)行
    toNext: function() {
        if (this.next) {
            this.start.apply(this.next, arguments);
        } else {
            console.log(&#39;無匹配的執(zhí)行項(xiàng)目&#39;);
        }
    }
};

// 展示數(shù)字
function showNumber(num) {
    if (typeof num === &#39;number&#39;) {
        console.log(&#39;number&#39;, num);
    } else {
        // 轉(zhuǎn)移到下一項(xiàng)
        this.toNext(num);
    }
}

// 展示字符串
function showString(str) {
    if (typeof str === &#39;string&#39;) {
        console.log(&#39;string&#39;, str);
    } else {
        this.toNext(str);
    }
}

// 展示對(duì)象
function showObject(obj) {
    if (typeof obj === &#39;object&#39;) {
        console.log(&#39;object&#39;, obj);
    } else {
        this.toNext(obj);
    }
}

var chainNumber = new ChainItem(showNumber);
var chainString = new ChainItem(showString);
var chainObject = new ChainItem(showObject);

// 設(shè)置鏈條
chainObject.setNext(chainNumber).setNext(chainString);

chainString.start(&#39;12&#39;); // string 12
chainNumber.start({}); // 無匹配的執(zhí)行項(xiàng)目
chainObject.start({}); // object {}
chainObject.start(123); // number 123

這時(shí)想判斷未定義的時(shí)候呢,直接加到鏈中即可


// 展示未定義
function showUndefined(obj) {
    if (typeof obj === &#39;undefined&#39;) {
        console.log(&#39;undefined&#39;);
    } else {
        this.toNext(obj);
    }
}

var chainUndefined = new ChainItem(showUndefined);
chainString.setNext(chainUndefined);

chainNumber.start(); // undefined

由例子可以看到,使用了職責(zé)鏈后,由原本的條件分支換成了很多對(duì)象,雖然結(jié)構(gòu)更加清晰了,但在一定程度上可能會(huì)影響到性能,所以要注意避免過長(zhǎng)的職責(zé)鏈。

十一、中介者模式

1. 定義

所有的相關(guān) 對(duì)象都通過中介者對(duì)象來通信,而不是互相引用,所以當(dāng)一個(gè)對(duì)象發(fā)生改變時(shí),只需要通知中介者對(duì)象即可

2. 核心

使網(wǎng)狀的多對(duì)多關(guān)系變成了相對(duì)簡(jiǎn)單的一對(duì)多關(guān)系(復(fù)雜的調(diào)度處理都交給中介者)

使用中介者后

3. 實(shí)現(xiàn)

多個(gè)對(duì)象,指的不一定得是實(shí)例化的對(duì)象,也可以將其理解成互為獨(dú)立的多個(gè)項(xiàng)。當(dāng)這些項(xiàng)在處理時(shí),需要知曉并通過其他項(xiàng)的數(shù)據(jù)來處理。

如果每個(gè)項(xiàng)都直接處理,程序會(huì)非常復(fù)雜,修改某個(gè)地方就得在多個(gè)項(xiàng)內(nèi)部修改

我們將這個(gè)處理過程抽離出來,封裝成中介者來處理,各項(xiàng)需要處理時(shí),通知中介者即可。

var A = {
    score: 10,

    changeTo: function(score) {
        this.score = score;

        // 自己獲取
        this.getRank();
    },
    
    // 直接獲取
    getRank: function() {
        var scores = [this.score, B.score, C.score].sort(function(a, b) {
            return a < b;
        });

        console.log(scores.indexOf(this.score) + 1);
    }
};

var B = {
    score: 20,

    changeTo: function(score) {
        this.score = score;

        // 通過中介者獲取
        rankMediator(B);
    }
};

var C = {
    score: 30,

    changeTo: function(score) {
        this.score = score;

        rankMediator(C);
    }
};

// 中介者,計(jì)算排名
function rankMediator(person) {
    var scores = [A.score, B.score, C.score].sort(function(a, b) {
        return a < b;
    });

    console.log(scores.indexOf(person.score) + 1);
}

// A通過自身來處理
A.changeTo(100); // 1

// B和C交由中介者處理
B.changeTo(200); // 1
C.changeTo(50); // 3

ABC三個(gè)人分?jǐn)?shù)改變后想要知道自己的排名,在A中自己處理,而B和C使用了中介者。B和C將更為輕松,整體代碼也更簡(jiǎn)潔

最后,雖然中介者做到了對(duì)模塊和對(duì)象的解耦,但有時(shí)對(duì)象之間的關(guān)系并非一定要解耦,強(qiáng)行使用中介者來整合,可能會(huì)使代碼更為繁瑣,需要注意。

十二、裝飾者模式

1. 定義

以動(dòng)態(tài)地給某個(gè)對(duì)象添加一些額外的職責(zé),而不會(huì)影響從這個(gè)類中派生的其他對(duì)象。

是一種“即用即付”的方式,能夠在不改變對(duì) 象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)地 添加職責(zé)

2. 核心

是為對(duì)象動(dòng)態(tài)加入行為,經(jīng)過多重包裝,可以形成一條裝飾鏈

3. 實(shí)現(xiàn)

最簡(jiǎn)單的裝飾者,就是重寫對(duì)象的屬性

var A = {
    score: 10
};

A.score = &#39;分?jǐn)?shù):&#39; + A.score;

可以使用傳統(tǒng)面向?qū)ο蟮姆椒▉韺?shí)現(xiàn)裝飾,添加技能

function Person() {}

Person.prototype.skill = function() {
    console.log(&#39;數(shù)學(xué)&#39;);
};

// 裝飾器,還會(huì)音樂
function MusicDecorator(person) {
    this.person = person;
}

MusicDecorator.prototype.skill = function() {
    this.person.skill();
    console.log(&#39;音樂&#39;);
};

// 裝飾器,還會(huì)跑步
function RunDecorator(person) {
    this.person = person;
}

RunDecorator.prototype.skill = function() {
    this.person.skill();
    console.log(&#39;跑步&#39;);
};

var person = new Person();

// 裝飾一下
var person1 = new MusicDecorator(person);
person1 = new RunDecorator(person1);

person.skill(); // 數(shù)學(xué)
person1.skill(); // 數(shù)學(xué) 音樂 跑步

在JS中,函數(shù)為一等對(duì)象,所以我們也可以使用更通用的裝飾函數(shù)

// 裝飾器,在當(dāng)前函數(shù)執(zhí)行前先執(zhí)行另一個(gè)函數(shù)
function decoratorBefore(fn, beforeFn) {
    return function() {
        var ret = beforeFn.apply(this, arguments);
        
        // 在前一個(gè)函數(shù)中判斷,不需要執(zhí)行當(dāng)前函數(shù)
        if (ret !== false) {
            fn.apply(this, arguments);
        }
    };
}


function skill() {
    console.log(&#39;數(shù)學(xué)&#39;);
}

function skillMusic() {
    console.log(&#39;音樂&#39;);
}

function skillRun() {
    console.log(&#39;跑步&#39;);
}

var skillDecorator = decoratorBefore(skill, skillMusic);
skillDecorator = decoratorBefore(skillDecorator, skillRun);

skillDecorator(); // 跑步 音樂 數(shù)學(xué)

十三、狀態(tài)模式

1. 定義

事物內(nèi)部狀態(tài)的改變往往會(huì)帶來事物的行為改變。在處理的時(shí)候,將這個(gè)處理委托給當(dāng)前的狀態(tài)對(duì)象即可,該狀態(tài)對(duì)象會(huì)負(fù)責(zé)渲染它自身的行為

2. 核心

區(qū)分事物內(nèi)部的狀態(tài),把事物的每種狀態(tài)都封裝成單獨(dú)的類,跟此種狀態(tài)有關(guān)的行為都被封裝在這個(gè)類的內(nèi)部

3. 實(shí)現(xiàn)

以一個(gè)人的工作狀態(tài)作為例子,在剛醒、精神、疲倦幾個(gè)狀態(tài)中切換著

// 工作狀態(tài)
function Work(name) {
    this.name = name;
    this.currentState = null;

    // 工作狀態(tài),保存為對(duì)應(yīng)狀態(tài)對(duì)象
    this.wakeUpState = new WakeUpState(this);
    // 精神飽滿
    this.energeticState = new EnergeticState(this);
    // 疲倦
    this.tiredState = new TiredState(this);

    this.init();
}

Work.prototype.init = function() {
    this.currentState = this.wakeUpState;
    
    // 點(diǎn)擊事件,用于觸發(fā)更新狀態(tài)
    document.body.onclick = () => {
        this.currentState.behaviour();
    };
};

// 更新工作狀態(tài)
Work.prototype.setState = function(state) {
    this.currentState = state;
}

// 剛醒
function WakeUpState(work) {
    this.work = work;
}

// 剛醒的行為
WakeUpState.prototype.behaviour = function() {
    console.log(this.work.name, &#39;:&#39;, &#39;剛醒呢,睡個(gè)懶覺先&#39;);
    
    // 只睡了2秒鐘懶覺就精神了..
    setTimeout(() => {
        this.work.setState(this.work.energeticState);
    }, 2 * 1000);
}

// 精神飽滿
function EnergeticState(work) {
    this.work = work;
}

EnergeticState.prototype.behaviour = function() {
    console.log(this.work.name, &#39;:&#39;, &#39;超級(jí)精神的&#39;);
    
    // 才精神1秒鐘就發(fā)困了
    setTimeout(() => {
        this.work.setState(this.work.tiredState);
    }, 1000);
};

// 疲倦
function TiredState(work) {
    this.work = work;
}

TiredState.prototype.behaviour = function() {
    console.log(this.work.name, &#39;:&#39;, &#39;怎么肥事,好困&#39;);
    
    // 不知不覺,又變成了剛醒著的狀態(tài)... 不斷循環(huán)呀
    setTimeout(() => {
        this.work.setState(this.work.wakeUpState);
    }, 1000);
};


var work = new Work(&#39;曹操&#39;);

點(diǎn)擊一下頁(yè)面,觸發(fā)更新狀態(tài)的操作

4. 優(yōu)缺點(diǎn)

優(yōu)點(diǎn)

狀態(tài)切換的邏輯分布在狀態(tài)類中,易于維護(hù)

缺點(diǎn)

多個(gè)狀態(tài)類,對(duì)于性能來說,也是一個(gè)缺點(diǎn),這個(gè)缺點(diǎn)可以使用享元模式來做進(jìn)一步優(yōu)化

將邏輯分散在狀態(tài)類中,可能不會(huì)很輕易就能看出狀態(tài)機(jī)的變化邏輯

十四、適配器模式

1. 定義

是解決兩個(gè)軟件實(shí)體間的接口不兼容的問題,對(duì)不兼容的部分進(jìn)行適配

2. 核心

解決兩個(gè)已有接口之間不匹配的問題

3. 實(shí)現(xiàn)

比如一個(gè)簡(jiǎn)單的數(shù)據(jù)格式轉(zhuǎn)換的適配器

// 渲染數(shù)據(jù),格式限制為數(shù)組了
function renderData(data) {
    data.forEach(function(item) {
        console.log(item);
    });
}

// 對(duì)非數(shù)組的進(jìn)行轉(zhuǎn)換適配
function arrayAdapter(data) {
    if (typeof data !== &#39;object&#39;) {
        return [];
    }

    if (Object.prototype.toString.call(data) === &#39;[object Array]&#39;) {
        return data;
    }

    var temp = [];

    for (var item in data) {
        if (data.hasOwnProperty(item)) {
            temp.push(data[item]);
        }
    }

    return temp;
}

var data = {
    0: &#39;A&#39;,
    1: &#39;B&#39;,
    2: &#39;C&#39;
};

renderData(arrayAdapter(data)); // A B C

十五、外觀模式

1. 定義

為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,定義一個(gè)高層接口,這個(gè)接口使子系統(tǒng)更加容易使用

2. 核心

可以通過請(qǐng)求外觀接口來達(dá)到訪問子系統(tǒng),也可以選擇越過外觀來直接訪問子系統(tǒng)

3. 實(shí)現(xiàn)

外觀模式在JS中,可以認(rèn)為是一組函數(shù)的集合

// 三個(gè)處理函數(shù)
function start() {
    console.log(&#39;start&#39;);
}

function doing() {
    console.log(&#39;doing&#39;);
}

function end() {
    console.log(&#39;end&#39;);
}

// 外觀函數(shù),將一些處理統(tǒng)一起來,方便調(diào)用
function execute() {
    start();
    doing();
    end();
}


// 調(diào)用init開始執(zhí)行
function init() {
    // 此處直接調(diào)用了高層函數(shù),也可以選擇越過它直接調(diào)用相關(guān)的函數(shù)
    execute();
}

init(); // start doing end

【相關(guān)推薦:javascript學(xué)習(xí)教程

Atas ialah kandungan terperinci Apakah corak reka bentuk dalam javascript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas

Tutorial PHP
1502
276
Perbezaan antara corak reka bentuk dan corak seni bina dalam rangka kerja Java Perbezaan antara corak reka bentuk dan corak seni bina dalam rangka kerja Java Jun 02, 2024 pm 12:59 PM

Dalam rangka kerja Java, perbezaan antara corak reka bentuk dan corak seni bina ialah corak reka bentuk mentakrifkan penyelesaian abstrak kepada masalah biasa dalam reka bentuk perisian, memfokuskan pada interaksi antara kelas dan objek, seperti corak kilang. Corak seni bina mentakrifkan hubungan antara struktur sistem dan modul, memfokuskan pada organisasi dan interaksi komponen sistem, seperti seni bina berlapis.

Corak Reka Bentuk PHP: Pembangunan Dipacu Ujian dalam Amalan Corak Reka Bentuk PHP: Pembangunan Dipacu Ujian dalam Amalan Jun 03, 2024 pm 02:14 PM

TDD digunakan untuk menulis kod PHP berkualiti tinggi Langkah-langkahnya termasuk: menulis kes ujian, menerangkan fungsi yang diharapkan dan menjadikannya gagal. Tulis kod supaya hanya kes ujian lulus tanpa pengoptimuman yang berlebihan atau reka bentuk terperinci. Selepas kes ujian lulus, optimumkan dan faktorkan semula kod untuk meningkatkan kebolehbacaan, kebolehselenggaraan dan kebolehskalaan.

Aplikasi corak reka bentuk dalam rangka kerja Guice Aplikasi corak reka bentuk dalam rangka kerja Guice Jun 02, 2024 pm 10:49 PM

Rangka kerja Guice menggunakan beberapa corak reka bentuk, termasuk: Corak Singleton: memastikan kelas hanya mempunyai satu tika melalui anotasi @Singleton. Corak kaedah kilang: Cipta kaedah kilang melalui anotasi @Provides dan dapatkan contoh objek semasa suntikan pergantungan. Mod strategi: Bungkus algoritma ke dalam kelas strategi yang berbeza dan nyatakan strategi khusus melalui anotasi @Named.

Aplikasi corak reka bentuk dalam rangka kerja Spring MVC Aplikasi corak reka bentuk dalam rangka kerja Spring MVC Jun 02, 2024 am 10:35 AM

Rangka kerja SpringMVC menggunakan corak reka bentuk berikut: 1. Mod Singleton: mengurus bekas Spring 2. Mod fasad: koordinat pengawal, paparan dan interaksi model 3. Mod strategi: memilih pengendali permintaan berdasarkan permintaan; : menerbitkan dan mendengar acara aplikasi. Corak reka bentuk ini meningkatkan fungsi dan fleksibiliti SpringMVC, membolehkan pembangun mencipta aplikasi yang cekap dan boleh diselenggara.

Apakah kelebihan dan kekurangan menggunakan corak reka bentuk dalam rangka kerja java? Apakah kelebihan dan kekurangan menggunakan corak reka bentuk dalam rangka kerja java? Jun 01, 2024 pm 02:13 PM

Kelebihan menggunakan corak reka bentuk dalam rangka kerja Java termasuk: kebolehbacaan kod yang dipertingkatkan, kebolehselenggaraan dan kebolehskalaan. Kelemahan termasuk kerumitan, overhed prestasi dan keluk pembelajaran yang curam akibat penggunaan berlebihan. Kes praktikal: Mod proksi digunakan untuk malas memuatkan objek. Gunakan corak reka bentuk dengan bijak untuk memanfaatkan kelebihannya dan meminimumkan kelemahannya.

Corak Reka Bentuk PHP: Corak yang digunakan untuk menyelesaikan masalah perisian tertentu Corak Reka Bentuk PHP: Corak yang digunakan untuk menyelesaikan masalah perisian tertentu Jun 01, 2024 am 11:07 AM

Corak reka bentuk PHP menyediakan penyelesaian yang diketahui kepada masalah biasa dalam pembangunan perisian. Jenis corak biasa termasuk ciptaan (seperti corak kaedah kilang), struktur (seperti corak penghias) dan tingkah laku (seperti corak pemerhati). Corak reka bentuk amat berguna apabila menyelesaikan masalah berulang, meningkatkan kebolehselenggaraan dan mempromosikan kerja berpasukan. Dalam sistem e-dagang, corak pemerhati boleh merealisasikan kemas kini automatik antara troli beli-belah dan status pesanan. Secara keseluruhan, corak reka bentuk PHP ialah alat penting untuk mencipta aplikasi yang teguh, berskala dan boleh diselenggara.

Hubungan antara corak reka bentuk dan pembangunan dipacu ujian Hubungan antara corak reka bentuk dan pembangunan dipacu ujian May 09, 2024 pm 04:03 PM

TDD dan corak reka bentuk meningkatkan kualiti dan kebolehselenggaraan kod. TDD memastikan liputan ujian, meningkatkan kebolehselenggaraan dan meningkatkan kualiti kod. Corak reka bentuk membantu TDD melalui prinsip seperti gandingan longgar dan kohesi tinggi, memastikan ujian merangkumi semua aspek tingkah laku aplikasi. Ia juga meningkatkan kebolehselenggaraan dan kualiti kod melalui kebolehgunaan semula, kebolehselenggaraan dan kod yang lebih mantap.

Apakah beberapa corak reka bentuk yang biasa (mis., Singleton, kilang, pemerhati) dan bagaimanakah ia dapat dilaksanakan di Python? Apakah beberapa corak reka bentuk yang biasa (mis., Singleton, kilang, pemerhati) dan bagaimanakah ia dapat dilaksanakan di Python? Jun 06, 2025 am 12:06 AM

Singleton, kilang dan pemerhati adalah tiga corak reka bentuk yang biasa digunakan di Python, yang digunakan untuk menyelesaikan masalah instantiasi objek, penciptaan pemberitahuan abstraksi dan ketergantungan. 1. Singleton menyelaraskan operasi sistem dengan memastikan kelas hanya mempunyai satu contoh dan menyediakan titik akses global, seperti pengurusan konfigurasi; 2. Kilang menjadikan kod lebih fleksibel dengan merangkumi logik penciptaan objek, yang memudahkan pengembangan pelbagai jenis penciptaan objek; 3. Observer membolehkan objek untuk memberitahu objek bergantung secara automatik apabila keadaan berubah, dan sesuai untuk sistem yang didorong oleh peristiwa seperti kemas kini GUI atau sistem pembalakan. Corak ini membantu meningkatkan kebolehkerjaan dan skalabiliti kod anda.

See all articles