成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

javascript 觀察者(發(fā)布訂閱)模式詳解

anonymoussf / 1965人閱讀

摘要:寫給讀者的話本人是千千萬(wàn)萬(wàn)前端小白中的一員,所以對(duì)前端小白的痛苦感同身受,面對(duì)一個(gè)新的知識(shí)點(diǎn),很多時(shí)候感到束手無(wú)策。

寫給讀者的話

本人是千千萬(wàn)萬(wàn)前端小白中的一員,所以對(duì)前端小白的痛苦感同身受,面對(duì)一個(gè)新的知識(shí)點(diǎn),很多時(shí)候感到束手無(wú)策。網(wǎng)上搜資料,有的不全,有的看不懂,所以本人作為小白,很有義務(wù)將自己覺得理解了的知識(shí)點(diǎn)盡可能的解釋的通熟易懂,恨不得一個(gè)字一個(gè)字的解釋。但是別人的終究是別人的,把它變成自己的才是正道,希望此文能幫助像我一樣的人更好的理解mvc,一起加油吧

先上demo代碼,下面有詳盡分析

index.js

function Event(sender) {
    this._sender = sender;
    this._listeners = [];
}

Event.prototype = {
    constructor : Event,
    attach: function (listener) {
        this._listeners.push(listener);
    },
    notify: function (args) {
        var index;

        for (index = 0; index < this._listeners.length; index += 1) {
            this._listeners[index](this._sender, args);
        }
    }
};

function ListModel(items) {
    this._items = items;
    this._selectedIndex = -1;

    this.itemAdded = new Event(this);
    this.itemRemoved = new Event(this);
    this.selectedIndexChanged = new Event(this);
}

ListModel.prototype = {
    constructor : ListModel,
    getItems: function () {
        return [].concat(this._items);
    },

    addItem: function (item) {
        this._items.push(item);
        this.itemAdded.notify({
            item: item
        });
    },

    removeItemAt: function (index) {
        var item;

        item = this._items[index];
        this._items.splice(index, 1);
        this.itemRemoved.notify({
            item: item
        });
        if (index === this._selectedIndex) {
            this.setSelectedIndex(-1);
        }
    },

    getSelectedIndex: function () {
        return this._selectedIndex;
    },

    setSelectedIndex: function (index) {
        var previousIndex;

        previousIndex = this._selectedIndex;
        this._selectedIndex = index;
        this.selectedIndexChanged.notify({
            previous: previousIndex
        });
    }
};

function ListView(model, elements) {
    this._model = model;
    this._elements = elements;

    this.listModified = new Event(this);
    this.addButtonClicked = new Event(this);
    this.delButtonClicked = new Event(this);

    var _this = this;

    // attach model listeners
    this._model.itemAdded.attach(function () {
        _this.rebuildList();
    });
    this._model.itemRemoved.attach(function () {
        _this.rebuildList();
    });

    // attach listeners to HTML controls
    this._elements.list.change(function (e) {
        _this.listModified.notify({
            index: e.target.selectedIndex
        });
    });
    this._elements.addButton.click(function () {
        _this.addButtonClicked.notify();
    });
    this._elements.delButton.click(function () {
        _this.delButtonClicked.notify();
    });
}

ListView.prototype = {
    constructor : ListView,
    show: function () {
        this.rebuildList();
    },

    rebuildList: function () {
        var list, items, key;

        list = this._elements.list;
        list.html("");

        items = this._model.getItems();
        for (key in items) {
            if (items.hasOwnProperty(key)) {
                list.append($(""));
            }
        }
        this._model.setSelectedIndex(-1);
    }
};

function ListController(model, view) {
    this._model = model;
    this._view = view;

    var _this = this;

    this._view.listModified.attach(function (sender, args) {
        _this.updateSelected(args.index);
    });

    this._view.addButtonClicked.attach(function () {
        _this.addItem();
    });

    this._view.delButtonClicked.attach(function () {
        _this.delItem();
    });
}

ListController.prototype = {
    constructor : ListController,
    addItem: function () {
        var item = window.prompt("Add item:", "");
        if (item) {
            this._model.addItem(item);
        }
    },

    delItem: function () {
        var index;

        index = this._model.getSelectedIndex();
        if (index !== -1) {
            this._model.removeItemAt(this._model.getSelectedIndex());
        }
    },

    updateSelected: function (index) {
        this._model.setSelectedIndex(index);
    }
};

$(function () {
    var model = new ListModel(["PHP", "JavaScript"]),
        view = new ListView(model, {
            "list": $("#list"),
            "addButton": $("#plusBtn"),
            "delButton": $("#minusBtn")
        }),
        controller = new ListController(model, view);

    view.show();
});

index.html




    
    MVC


    
MVC模式說明:

model層和view層都繼承了觀察者類,觀察者類中包含訂閱和發(fā)布方法

model層定義了底層操作,包括對(duì)數(shù)據(jù)的增刪改查

view層綁定了增刪改事件,一旦所綁定的事件發(fā)生,就調(diào)用觀察者類中的發(fā)布方法發(fā)布消息;同時(shí)又訂閱了model層數(shù)據(jù)的變動(dòng),一旦所訂閱的model層的數(shù)據(jù)發(fā)生變化,就調(diào)用view層自身方法更新數(shù)據(jù)顯示

controller層訂閱了view層的增刪改事件,一旦所訂閱的事件發(fā)布了,就調(diào)用自身的方法經(jīng)過業(yè)務(wù)邏輯的處理,調(diào)用相應(yīng)的model層的方法

針對(duì)代碼做具體分析:

見下圖:

首先頁(yè)面加載執(zhí)行初始化代碼,執(zhí)行完成后頁(yè)面上會(huì)有一個(gè)列表,里面包含兩個(gè)選項(xiàng):PHP和Javascript,然后底下有"+"和"-"兩個(gè)按鈕,以點(diǎn)擊"+"為例,流程分析開始:

首先定義了一個(gè)觀察者Event構(gòu)造函數(shù)

view層中綁定了增刪改事件,同時(shí)訂閱了model層數(shù)據(jù)改動(dòng)事件;

我們點(diǎn)擊"+"號(hào)按鈕,觸發(fā)了view層中的addButton的click事件,然后addButtonClicked調(diào)用觀察者構(gòu)造函數(shù)的發(fā)布方法notify()發(fā)布消息,代碼如下:

    this._elements.addButton.click(function () {
        _this.addButtonClicked.notify();
    });
    
4.由于在controller層中訂閱了view層的addButtonClicked發(fā)布的消息,將addItem()保存在其對(duì)應(yīng)的listener數(shù)組中,所以此時(shí)執(zhí)行_this.addItem(),代碼如下:
    this._view.addButtonClicked.attach(function () {
        _this.addItem();
    });
    
5.在controller層中的addItem()方法中,如果有item輸入,就調(diào)用model層中的addItem(item)并傳入item,代碼如下:
    addItem: function () {
        var item = window.prompt("Add item:", "");
        if (item) {
           this._model.addItem(item);
        }
    }
    
6.在model層中的itemAdd()方法中,獲取到controller層中傳過來(lái)的item之后,將其保存到this.item數(shù)組中,然后model層中的item調(diào)用notify()發(fā)布消息,代碼如下:
    addItem: function (item) {
        this._items.push(item);
        this.itemAdded.notify({
            item: item
        });
    }
    
7.由于在view層中訂閱了model層的itemAdd發(fā)布的消息,將rebuildList()保存在其對(duì)應(yīng)的listener數(shù)組中,所以此時(shí)執(zhí)行_this.rebuildList(),代碼如下:
    this._model.itemAdded.attach(function () {
        _this.rebuildList();
    });
    
8.view層中的rebuildList()干的事情就是每次都先清空列表內(nèi)容,然后重新獲取內(nèi)容,再循環(huán)添加到列表中,最后調(diào)用model層中的setSelectedIndex(-1)把選中項(xiàng)的index還原為-1,代碼如下:
    rebuildList: function () {
        var list, items, key;
        list = this._elements.list;
        list.html("");
        items = this._model.getItems();
        for (key in items) {
            if (items.hasOwnProperty(key)) {
                list.append($(""));
            }
        }
        this._model.setSelectedIndex(-1);
    }
    
9.model層中的setSelectedIndex()干的事情就是把上一次的選中項(xiàng)的index和當(dāng)前選中項(xiàng)的index進(jìn)行交換,然后model層中的selectedIndexChanged調(diào)用notify()發(fā)布消息,代碼如下:
    setSelectedIndex: function (index) {
        var previousIndex;
        previousIndex = this._selectedIndex;
        this._selectedIndex = index;
        this.selectedIndexChanged.notify({
            previous: previousIndex
        });
    }
    
10.你會(huì)發(fā)現(xiàn)view層中沒有對(duì)selectedIndexChanged的訂閱,那寫起來(lái)干嘛呢?就是留著以后進(jìn)行擴(kuò)展用的,你可以繼續(xù)按照這個(gè)模式寫下去
MVC的優(yōu)點(diǎn):

耦合性低:視圖層和業(yè)務(wù)層分離了,如果頁(yè)面上顯示改變的話,直接在視圖層更改即可,不用動(dòng)模型層和控制層上的代碼;也就是視圖層 與 模型層和控制層

已經(jīng)分離了;所以很容易改變應(yīng)用層的數(shù)據(jù)層和業(yè)務(wù)規(guī)則。

可維護(hù)性:分離視圖層和業(yè)務(wù)邏輯層也使得WEB應(yīng)用更易于維護(hù)和修改。

MVC的缺點(diǎn):

個(gè)人覺得適合于大型項(xiàng)目,對(duì)于中小型項(xiàng)目并不適合,因?yàn)橐獙?shí)現(xiàn)一個(gè)簡(jiǎn)單的增刪改操作,只需要一點(diǎn)點(diǎn)JS代碼,但是MVC模式代碼量明顯增加了。

希望此文對(duì)你有幫助,如有疑問和錯(cuò)誤,請(qǐng)告訴我,謝謝!

參考資料:

https://alexatnet.com/article...

http://web.jobbole.com/84945/

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82541.html

相關(guān)文章

  • JavaScript 發(fā)布-訂閱模式

    摘要:發(fā)布訂閱模式訂閱者把自己想訂閱的事件注冊(cè)到調(diào)度中心,當(dāng)發(fā)布者發(fā)布該事件到調(diào)度中心,也就是該事件觸發(fā)時(shí),由調(diào)度中心統(tǒng)一調(diào)度訂閱者注冊(cè)到調(diào)度中心的處理代碼。 發(fā)布-訂閱模式,看似陌生,其實(shí)不然。工作中經(jīng)常會(huì)用到,例如 Node.js EventEmitter 中的 on 和 emit 方法;Vue 中的 $on 和 $emit 方法。他們都使用了發(fā)布-訂閱模式,讓開發(fā)變得更加高效方便。 一...

    13651657101 評(píng)論0 收藏0
  • JavaScript設(shè)計(jì)模式發(fā)布-訂閱模式察者模式)-Part1

    摘要:設(shè)計(jì)模式與開發(fā)實(shí)踐讀書筆記。發(fā)布訂閱模式又叫觀察者模式,它定義了對(duì)象之間的一種一對(duì)多的依賴關(guān)系。附設(shè)計(jì)模式之發(fā)布訂閱模式觀察者模式數(shù)據(jù)結(jié)構(gòu)和算法系列棧隊(duì)列優(yōu)先隊(duì)列循環(huán)隊(duì)列設(shè)計(jì)模式系列設(shè)計(jì)模式之策略模式 《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》讀書筆記。 發(fā)布-訂閱模式又叫觀察者模式,它定義了對(duì)象之間的一種一對(duì)多的依賴關(guān)系。當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴它的對(duì)象都將得到通知。 例...

    muzhuyu 評(píng)論0 收藏0
  • JavaScript 設(shè)計(jì)模式(六):察者模式發(fā)布訂閱模式

    摘要:觀察者模式維護(hù)單一事件對(duì)應(yīng)多個(gè)依賴該事件的對(duì)象關(guān)系發(fā)布訂閱維護(hù)多個(gè)事件主題及依賴各事件主題的對(duì)象之間的關(guān)系觀察者模式是目標(biāo)對(duì)象直接觸發(fā)通知全部通知,觀察對(duì)象被迫接收通知。 觀察者模式(Observer) 觀察者模式:定義了對(duì)象間一種一對(duì)多的依賴關(guān)系,當(dāng)目標(biāo)對(duì)象 Subject 的狀態(tài)發(fā)生改變時(shí),所有依賴它的對(duì)象 Observer 都會(huì)得到通知。 簡(jiǎn)單點(diǎn):女神有男朋友了,朋友圈曬個(gè)圖,甜...

    bingo 評(píng)論0 收藏0
  • JavaScript 察者模式

    摘要:生活中的觀察者模式就如我們?cè)趯Yu店預(yù)定商品如蘋果手機(jī),我們會(huì)向?qū)Yu店提交預(yù)定申請(qǐng),然后店家受申請(qǐng),正常這樣就完事了。中的觀察者模式在中觀察者模式的實(shí)現(xiàn)主要用事件模型。缺點(diǎn)使用全局的觀察者模式會(huì)明顯降低對(duì)象之間的聯(lián)系。 觀察者模式又叫做發(fā)布-訂閱模式。這是一種一對(duì)多的對(duì)象依賴關(guān)系,當(dāng)被依賴的對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都將得到通知。 生活中的觀察者模式 就如我們?cè)趯Yu店預(yù)定商...

    zhigoo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<