对mvc模式的理解

Model-View-Controller

MVC模式是个威力强大的复合模式,是由数个设计模式结合起来的模式;

我们先看一下一个mp3播放器的设计,来由浅至深地了解这个设计模式的精髓所在:

 

从最直观的地方入手,我们不要先入为主的去使用mvc这个模式,而是尝试用自己最为直观的方式去设计这个应用,那么事情会变成这样:

首先从交互的角度,我们先提出需求:

  • 用户界面上需要显示当前歌曲名
  • 用户可以通过按键直接选择上一首,下一首;
  • 用户可以通过menu按键,显示当前MP3中的所有歌曲列表,然后上下按键选择一首歌曲,并通过ok键播放

好的,其实上述需求,明确了一点,这些需求需要有视图,或者至少需要有View去告诉用户各种状态;ok,那有没有不需要view的需求呢?有,比如,按下风扇能转动,这种需求很简单就不需要view, 但是,这不是重点,重点在于,用户需要对机器当前的状态有个直观的感知,或者反馈,比如风扇上如果我们想要做高端,然后会加个面板,告诉用户当前的风速,室内温度等,最终还是免不了会有view的存在,view的形式可以是多样的,可以是网页的形式,可以是led的形式,可以是数码管的形式,这些只是展示方式的不同,真正的核心在于这些view展示的数据本身,这些才是用户真正care的地方;比如我的歌单里有没有某首歌(模型),比如我播放下一曲的时候,是否能正常切过去(控制器);简单总结就是:用户操作,会作用于控制器,控制器判断用户需要切歌,需要更改当前播放的歌曲索引,然后通知player 播放新的歌曲;模型的改变,会相应地引起视图的改变 ;

那么这里使用了哪些设计模式呢?

 

 

这里复习一下观察者模式和策略模式:

 

 

观察者模式的好处在于,模型对视图没有依赖,其含义是模型部分无需变更,便可以支持视图的替换,或多个视图去展示同一个模型;

 

纸上得来终觉浅,我们还是从代码的角度来看一下整个事情的细节吧:

class Mp3Model {
public:
    int     getSongIdxByString(string song);
    string  getSoneNameByIdx(int idx);
    string  getCurrentSong()

    void setCurrentSong(string song) {
         // hw hal to set song file
         ...
         // then notify observers
         notifyObserver(); // 通知观察者状态改变
    }
    // 实际的start/stop
    void start();
    void stop();
    void registerObsever(Observer* observer) // model提供注册观察者方法
    {
         mObserver = observer;
    }
private:
    void notifyObserver() {
        mObserver->onNotify();
    }
    Observer* mObserver;
};

class Mp3Controller {
public:
    Mp3Controller(Mp3Model* model) { mModel = model; }
    void playNext() { 
       mModel->setCurrentSong(mModel->getSongIdxByString(mModel->getCurrentSong()) + 1); 
    }
    void playPrevious() { 
       mModel->setCurrentSong(mModel->getSongIdxByString(mModel->getCurrentSong()) - 1); 
    }
    void start() { mModel->start();}
    void stop() { mModel->stop(); }
private:
    Mp3Model* mModel;
};

class Mp3View : public Observer {
public:
    Mp3View() {
       mModel = new Mp3Model;
       mModel->registerObserver((Oberver*)this);
       mController = new Mp3Controller(mModel);
    }
    void on_click_next() { mController->playNext(); }
    void on_click_previous() { mController->playPrevious(); }
    void on_click_start() { mContrlloer->start(); }
    void on_click_stop() { mController->stop(); }
    void onNotify() { //实现model变化时的回调,如改变控件状态等 } 
    void run();
    bool live();
private:
    Mp3Controller* mController;
    Mp3Model* mModel;
};

int main() {
  // 创建view需要controller, mode , 创建controller需要model
  Mp3View* mp3_view = new Mp3View;
  mp3_view.run();
  while(mp3_view.live()) {
     sleep(1);
  }
  return 0;
}

 

posted on 2023-02-19 17:15  疾速瓜牛  阅读(31)  评论(0编辑  收藏  举报

导航