JavaScript設(shè)計模式(組合模式)

1. 組合模式的定義

組合模式,將對象組合成 樹形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu),組合模式使得用戶對單個對象和組合對象的使用具有一致性。

image.png

2. 場景

2.1 宏命令

<html>

<body>
    <button id="button">按我</button></body>

<script>

    const MacroCommand = function () {
        return {
            commandsList: [],
            add: function (command) {
                this.commandsList.push(command);
            },
            execute: function () {
                for (let i = 0, command; command = this.commandsList[i++];) {
                    command.execute();
                }
            }
        }
    };

    const openAcCommand = {
        execute: function () {
            console.log('打開空調(diào)');
        }
    };

    /**********家里的電視和音響是連接在一起的,所以可以用一個宏命令來組合打開電視和打開音響的命令 *********/

    const openTvCommand = {
        execute: function () {
            console.log('打開電視');
        }
    };

    const openSoundCommand = {
        execute: function () {
            console.log('打開音響');
        }
    };

    const macroCommand1 = MacroCommand();
    macroCommand1.add(openTvCommand);
    macroCommand1.add(openSoundCommand);

    /*********關(guān)門、打開電腦和打登錄 QQ的命令****************/

    const closeDoorCommand = {
        execute: function () {
            console.log('關(guān)門');
        }
    };

    const openPcCommand = {
        execute: function () {
            console.log('開電腦');
        }
    };

    const openQQCommand = {
        execute: function () {
            console.log('登錄 QQ');
        }
    };

    const macroCommand2 = MacroCommand();
    macroCommand2.add(closeDoorCommand);
    macroCommand2.add(openPcCommand);
    macroCommand2.add(openQQCommand);

    /*********現(xiàn)在把所有的命令組合成一個“超級命令”**********/

    const macroCommand = MacroCommand();
    macroCommand.add(openAcCommand);
    macroCommand.add(macroCommand1);
    macroCommand.add(macroCommand2);

    /*********最后給遙控器綁定“超級命令”**********/

    const setCommand = (function (command) {
        document.getElementById('button').onclick = function () {
            command.execute();
        }
    })(macroCommand);

</script>

</html>

2.2 掃描文件夾

/******************************* Folder ******************************/ 
const Folder = function( name ){
    this.name = name;
    this.files = [];
};

Folder.prototype.add = function( file ){ 
    this.files.push( file );
};

Folder.prototype.scan = function(){
    console.log( '開始掃描文件夾: ' + this.name );
    for ( let i = 0, file, files = this.files; file = files[ i++ ]; ){ 
        file.scan();
    }
};

/******************************* File ******************************/ 
const File = function( name ){
    this.name = name;
};

File.prototype.add = function(){
    throw new Error( '文件下面不能再添加文件' ); 
};
File.prototype.scan = function(){
    console.log( '開始掃描文件: ' + this.name ); 
};
const folder = new Folder( '學(xué)習(xí)資料' );
const folder1 = new Folder( 'JavaScript' ); 
const folder2 = new Folder ( 'jQuery' );

const file1 = new File( 'JavaScript設(shè)計模式與開發(fā)實踐' ); 
const file2 = new File( '精通 jQuery' );
const file3 = new File( '重構(gòu)與模式' )


folder1.add( file1 ); folder2.add( file2 );

folder.add( folder1 ); folder.add( folder2 ); folder.add( file3 );

const folder3 = new Folder( 'Nodejs' );
const file4 = new File( '深入淺出 Node.js' ); 
folder3.add( file4 );

const file5 = new File( 'JavaScript語言精髓與編程實踐' );

folder.add( folder3 ); 
folder.add( file5 );

folder.scan(); 

2.3 react

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title></title>
    <style>
        .red {
            color: red;
        }
    </style>
</head>

<body>
    <div id="root"></div>
    <script>
        function ReactElement(type, props) {
            this.type = type;
            this.props = props;
        }
        let React = {
            createElement(type, props = {}, ...childrens) {
                childrens.length === 1 ? childrens = childrens[0] : void 0
                return new ReactElement(type, { ...props, children: childrens })
            }
        };
        let render = (eleObj, container) => {
            // 先取出第一層 進(jìn)行創(chuàng)建真實dom
            let { type, props } = eleObj;
            let elementNode = document.createElement(type); // 創(chuàng)建第一個元素
            for (let attr in props) { // 循環(huán)所有屬性
                if (attr === 'children') { // 如果是children表示有嵌套關(guān)系
                    if (typeof props[attr] == 'object') { // 看是否是只有一個文本節(jié)點
                        props[attr].forEach(item => { // 多個的話循環(huán)判斷 如果是對象再次調(diào)用render方法
                            if (typeof item === 'object') {
                                render(item, elementNode)
                            } else { //是文本節(jié)點 直接創(chuàng)建即可
                                elementNode.appendChild(document.createTextNode(item));
                            }
                        })
                    } else { // 只有一個文本節(jié)點直接創(chuàng)建即可
                        elementNode.appendChild(document.createTextNode(props[attr]));
                    }
                } else if (attr === 'className') { // 是不是class屬性 class 屬性特殊處理
                    elementNode.setAttribute('class', props[attr]);
                } else {
                    elementNode.setAttribute(attr, props[attr]);
                }
            }
            container.appendChild(elementNode)
        };
        //ReactDOM.render(<div>hello<span>world</span></div>);
        //ReactDOM.render(React.createElement("div",null,"hello,",React.createElement("span",null,"world")));
        render(React.createElement("div", null, "hello,", React.createElement("span", { class: "red" }, "world")), document.getElementById('root'));

    </script>
</body>

</html>

3. 總結(jié)

  • 組合模式可以讓我們使用樹形方式創(chuàng) 建對象的結(jié)構(gòu)。我們可以把相同的操作應(yīng)用在組合對象和單個對象上。在大多數(shù)情況下,我們都 可以忽略掉組合對象和單個對象之間的差別,從而用一致的方式來處理它們。

  • 然而,組合模式并不是完美的,它可能會產(chǎn)生一個這樣的系統(tǒng):系統(tǒng)中的每個對象看起來都 與其他對象差不多。它們的區(qū)別只有在運行的時候會才會顯現(xiàn)出來,這會使代碼難以理解。此外,
    如果通過組合模式創(chuàng)建了太多的對象,那么這些對象可能會讓系統(tǒng)負(fù)擔(dān)不起。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容