日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【HeadFirst 设计模式学习笔记】13 MVC分析

發布時間:2025/4/5 c/c++ 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【HeadFirst 设计模式学习笔记】13 MVC分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作者:gnuhpc
出處:http://www.cnblogs.com/gnuhpc/

1.M-V-C ——Model--View--Controller,模式-視圖-控制器,這是一種范型。模型對象正是應用系統存在的理由,你設計的對象,包含了數據、邏輯和其他在你的應用領域創建定制的類。視圖通常是控件,用來顯示和編輯,控制器位于二者中間,負責將每個改變的狀態送進送出。而學習設計模式是理解MVC的鑰匙。書中用一個iTunes的例子直觀描述了MVC:

2.MVC的基本原理:

  • 視圖:用來呈現模型。視圖通常直接從模型中取得它需要顯示的數據。 視圖不會直接操作模型。
  • 控制器:取得用戶的輸入并解讀其對模型的意思。 控制器不會實現應用邏輯,它為視圖實現行為,將視圖傳過來的行為轉化為模型上的動作。它只負責決定調用哪一個模型。
  • 模型:持有所有的數據,狀態和程序邏輯。模型沒有注意到視圖和控制器,雖然它提供了操縱和檢索狀態的接口,并且發送狀態改變通知觀察者。 模型只知道有一些觀察者它需要通知,并且提供一些接口供視圖和控制器獲得并設置狀態。

他們三者的交互如下圖:

這里充分體現了我們“單一職責”的這個原則。

3.MVC模式分析:

1)視圖和控制器實現了經典的策略模式:視圖是一個對象,可以被調整使用不同的策略。視圖只關心顯示,而其行為的控制則都使用控制器進行。這樣一來,視圖和模型之間也完成了解耦,因為控制器負責和模型進行用戶請求的交互。

2)視圖中的顯示中包含了很多的要素,這就用到了組合模式,當控制器告訴視圖更新時,只需告訴視圖最頂層的組件即可,組合會處理其余的事。

3)模型則實現了觀察者模式,當狀態改變時,相關對象將持續更新。

4.MVC實例——DJ View

這是一個控制節拍(BPM,每分鐘XX拍)并產生鼓聲的工具。下邊是這個系統的核心,他負責根據節拍(可以設置可以讀取)產生鼓聲——模型:

我們先看看模型的接口:

public interface BeatModelInterface {?
??? void initialize();?
??? void on();?
??? void off();?
??? void setBPM(int bpm);?
??? int getBPM();?
??? void registerObserver(BeatObserver o);//有兩種觀察者,一種觀察者希望每個節拍都被通知,另一種觀察者希望BPM改變時被通知?
??? void removeObserver(BeatObserver o);?
??? void registerObserver(BPMObserver o);?
??? void removeObserver(BPMObserver o);?
}

根據這個接口,我們可以實現模型:

public class BeatModel implements BeatModelInterface, MetaEventListener {?
??? Sequencer sequencer;?
??? ArrayList beatObservers = new ArrayList();?
??? ArrayList bpmObservers = new ArrayList();?
??? int bpm = 90;?
??? Sequence sequence;?
??? Track track;?
??? public void initialize() {?
??????? setUpMidi();?
??????? buildTrackAndStart();?
??? }?
??? public void on() {?
??????? sequencer.start();?
??????? setBPM(90);?
??? }?
??? public void off() {?
??????? setBPM(0);?
??????? sequencer.stop();?
??? }?
??? public void setBPM(int bpm) {?
??????? this.bpm = bpm;?
??????? sequencer.setTempoInBPM(getBPM());?
????? ?
notifyBPMObservers();?
??? }?
??? public int getBPM() {?
??????? return bpm;?
??? }?
??? void beatEvent() {?
?????? ?
notifyBeatObservers();?
??? }?
??? public void registerObserver(BeatObserver o) {?
??????? beatObservers.add(o);?
??? }?
??? public void notifyBeatObservers() {?
??????? for(int i = 0; i < beatObservers.size(); i++) {?
??????????? BeatObserver observer = (BeatObserver)beatObservers.get(i);?
??????????? observer.updateBeat();?
??????? }?
??? }?
??? public void registerObserver(BPMObserver o) {?
??????? bpmObservers.add(o);?
??? }?
??? public void notifyBPMObservers() {?
??????? for(int i = 0; i < bpmObservers.size(); i++) {?
??????????? BPMObserver observer = (BPMObserver)bpmObservers.get(i);?
??????????? observer.updateBPM();?
??????? }?
??? }

??? public void removeObserver(BeatObserver o) {?
??????? int i = beatObservers.indexOf(o);?
??????? if (i >= 0) {?
??????????? beatObservers.remove(i);?
??????? }?
??? }

??? public void removeObserver(BPMObserver o) {?
??????? int i = bpmObservers.indexOf(o);?
??????? if (i >= 0) {?
??????????? bpmObservers.remove(i);?
??????? }?
??? }

??? public void meta(MetaMessage message) {?
??????? if (message.getType() == 47) {?
??????????? beatEvent();?
??????????? sequencer.start();?
??????????? setBPM(getBPM());?
??????? }?
??? }

??? public void setUpMidi() {?
??????? try {?
??????????? sequencer = MidiSystem.getSequencer();?
??????????? sequencer.open();?
??????????? sequencer.addMetaEventListener(this);?
??????????? sequence = new Sequence(Sequence.PPQ,4);?
??????????? track = sequence.createTrack();?
??????????? sequencer.setTempoInBPM(getBPM());?
??????? } catch(Exception e) {?
??????????????? e.printStackTrace();?
??????? }?
??? }

???? public void buildTrackAndStart() {?
??????? int[] trackList = {35, 0, 46, 0};?
??????? sequence.deleteTrack(null);?
??????? track = sequence.createTrack();

????????? makeTracks(trackList);?
??????? track.add(makeEvent(192,9,1,0,4));???? ?
???????? try {?
??????????? sequencer.setSequence(sequence);?????????????????? ?
??????? } catch(Exception e) {?
??????????? e.printStackTrace();?
??????? }?
??? }?
??? public void makeTracks(int[] list) {?????? ?
?????? for (int i = 0; i < list.length; i++) {?
????????? int key = list[i];

????????? if (key != 0) {?
???????????? track.add(makeEvent(144,9,key, 100, i));?
???????????? track.add(makeEvent(128,9,key, 100, i+1));?
????????? }?
?????? }?
??? }?
??? public? MidiEvent makeEvent(int comd, int chan, int one, int two, int tick) {?
??????? MidiEvent event = null;?
??????? try {?
??????????? ShortMessage a = new ShortMessage();?
??????????? a.setMessage(comd, chan, one, two);?
??????????? event = new MidiEvent(a, tick);?
??????? } catch(Exception e) {?
??????????? e.printStackTrace();?
??????? }?
??????? return event;?
??? }?
}

我們現在要把視圖掛上去,讓這個模型可視化!BeatModel對視圖一無所知,我們利用觀察者模式當狀態改變時,只要是注冊為觀察者的視圖都會收到通知。而視圖使用模型的API訪問狀態。

public class DJView implements ActionListener, ?BeatObserver, BPMObserver?{//同時關心時時節拍和BPM的改變?
??? BeatModelInterface model;?
??? ControllerInterface controller;//視圖持有模型和控制器的引用
?
??? JFrame viewFrame;?
??? JPanel viewPanel;?
??? BeatBar beatBar;?
??? JLabel bpmOutputLabel;?
??? JFrame controlFrame;?
??? JPanel controlPanel;?
??? JLabel bpmLabel;?
??? JTextField bpmTextField;?
??? JButton setBPMButton;?
??? JButton increaseBPMButton;?
??? JButton decreaseBPMButton;?
??? JMenuBar menuBar;?
??? JMenu menu;?
??? JMenuItem startMenuItem;?
??? JMenuItem stopMenuItem;

??? public DJView(ControllerInterface controller, BeatModelInterface model) {?? ?
??????? this.controller = controller;?
??????? this.model = model;?
????? ?
model.registerObserver((BeatObserver)this);//注冊觀察者?
??????? model.registerObserver((BPMObserver)this);?
??? }?
??? public void createView() {?
??????? // Create all Swing components here?
??????? viewPanel = new JPanel(new GridLayout(1, 2));?
??????? viewFrame = new JFrame("View");?
??????? viewFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);?
??????? viewFrame.setSize(new Dimension(100, 80));?
??????? bpmOutputLabel = new JLabel("offline", SwingConstants.CENTER);?
??????? beatBar = new BeatBar();?
??????? beatBar.setValue(0);?
??????? JPanel bpmPanel = new JPanel(new GridLayout(2, 1));?
??????? bpmPanel.add(beatBar);?
??????? bpmPanel.add(bpmOutputLabel);?
??????? viewPanel.add(bpmPanel);?
??????? viewFrame.getContentPane().add(viewPanel, BorderLayout.CENTER);?
??????? viewFrame.pack();?
??????? viewFrame.setVisible(true);?
??? }?
??? public void createControls() {?
??????? // Create all Swing components here?
??????? JFrame.setDefaultLookAndFeelDecorated(true);?
??????? controlFrame = new JFrame("Control");?
??????? controlFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);?
??????? controlFrame.setSize(new Dimension(100, 80));

??????? controlPanel = new JPanel(new GridLayout(1, 2));

??????? menuBar = new JMenuBar();?
??????? menu = new JMenu("DJ Control");?
??????? startMenuItem = new JMenuItem("Start");?
??????? menu.add(startMenuItem);?
??????? startMenuItem.addActionListener(new ActionListener() {?
??????????? public void actionPerformed(ActionEvent event) {?
?????????????? ?
controller.start();//視圖的點擊觸發控制器的事件?
??????????? }?
??????? });?
??????? stopMenuItem = new JMenuItem("Stop");?
??????? menu.add(stopMenuItem);?
??????? stopMenuItem.addActionListener(new ActionListener() {?
??????????? public void actionPerformed(ActionEvent event) {?
?????????????? ?
controller.stop();?
??????????? }?
??????? });?
??????? JMenuItem exit = new JMenuItem("Quit");?
??????? exit.addActionListener(new ActionListener() {?
??????????? public void actionPerformed(ActionEvent event) {?
??????????????? System.exit(0);?
??????????? }?
??????? });

??????? menu.add(exit);?
??????? menuBar.add(menu);?
??????? controlFrame.setJMenuBar(menuBar);

??????? bpmTextField = new JTextField(2);?
??????? bpmLabel = new JLabel("Enter BPM:", SwingConstants.RIGHT);?
??????? setBPMButton = new JButton("Set");?
??????? setBPMButton.setSize(new Dimension(10,40));?
??????? increaseBPMButton = new JButton(">>");?
??????? decreaseBPMButton = new JButton("<<");?
??????? setBPMButton.addActionListener(this);?
??????? increaseBPMButton.addActionListener(this);?
??????? decreaseBPMButton.addActionListener(this);

??????? JPanel buttonPanel = new JPanel(new GridLayout(1, 2));

??????? buttonPanel.add(decreaseBPMButton);?
??????? buttonPanel.add(increaseBPMButton);

??????? JPanel enterPanel = new JPanel(new GridLayout(1, 2));?
??????? enterPanel.add(bpmLabel);?
??????? enterPanel.add(bpmTextField);?
??????? JPanel insideControlPanel = new JPanel(new GridLayout(3, 1));?
??????? insideControlPanel.add(enterPanel);?
??????? insideControlPanel.add(setBPMButton);?
??????? insideControlPanel.add(buttonPanel);?
??????? controlPanel.add(insideControlPanel);?
??????? bpmLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));?
??????? bpmOutputLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

??????? controlFrame.getRootPane().setDefaultButton(setBPMButton);?
??????? controlFrame.getContentPane().add(controlPanel, BorderLayout.CENTER);

??????? controlFrame.pack();?
??????? controlFrame.setVisible(true);?
??? }

??? public void enableStopMenuItem() {?
??????? stopMenuItem.setEnabled(true);?
??? }

??? public void disableStopMenuItem() {?
??????? stopMenuItem.setEnabled(false);?
??? }

??? public void enableStartMenuItem() {?
??????? startMenuItem.setEnabled(true);?
??? }

??? public void disableStartMenuItem() {?
??????? startMenuItem.setEnabled(false);?
??? }

??? public void actionPerformed(ActionEvent event) {?
??????? if (event.getSource() == setBPMButton) {?
??????????? int bpm = Integer.parseInt(bpmTextField.getText());?
?????????? ?controller.setBPM(bpm);//視圖的改變會直接傳遞給控制器?
??????? } else if (event.getSource() == increaseBPMButton) {?
?????????? ?controller.increaseBPM();?
??????? } else if (event.getSource() == decreaseBPMButton) {?
?????????? ?controller.decreaseBPM();?
??????? }?
??? }

??? public void updateBPM() {//模型發生改變時,這個方法會被調用?
??????? if (model != null) {?
??????????? int bpm = model.getBPM();?
??????????? if (bpm == 0) {?
??????????????? if (bpmOutputLabel != null) {?
??????????????????? bpmOutputLabel.setText("offline");?
??????????????? }?
??????????? } else {?
??????????????? if (bpmOutputLabel != null) {?
??????????????????? bpmOutputLabel.setText("Current BPM: " + model.getBPM());?
??????????????? }?
??????????? }?
??????? }?
??? }?
??? public void updateBeat() {//相應的,當模型開始一個新的節拍時,這個方法會被調用?
??????? if (beatBar != null) {?
???????????? beatBar.setValue(100);?
??????? }?
??? }?
}

有了視圖,有了模型,我們要構建控制器,使得視圖更加聰明,我們使用策略模式,從控制器接口開始設計:

public interface ControllerInterface {?
??? void start();?
??? void stop();?
??? void increaseBPM();?
??? void decreaseBPM();?
???? void setBPM(int bpm);?
}

根據這個接口,我們實現這個控制器:

public class BeatController implements ControllerInterface {?
??? BeatModelInterface model;//MVC中,控制器在中間,所以要同時持有模型以及視圖的引用。?
??? DJView view;
?
??? public BeatController(BeatModelInterface model) {?
??????? this.model = model;?
?? ?
??? view = new DJView(this, model);//控制器創建視圖?
??????? view.createView();?
??????? view.createControls();?
??????? view.disableStopMenuItem();?
??????? view.enableStartMenuItem();?
??????? model.initialize();?
??? }?
??? public void start() {//控制器在得到start指令時去操縱模型和視圖,下邊的幾個動作同理。?
??????? model.on();?
??????? view.disableStartMenuItem();
//注意,控制器這時在幫視圖做決定,視圖只知道如何將菜單項變成開或者關而不知道在何時該這么做?
??????? view.enableStopMenuItem();?
??? }?
??? public void stop() {?
??????? model.off();?
??????? view.disableStopMenuItem();?
??????? view.enableStartMenuItem();?
??? }?
??? public void increaseBPM() {//控制器擴展了模型的動作?
??????? int bpm = model.getBPM();?
??????? model.setBPM(bpm + 1);?
??? }?
??? public void decreaseBPM() {?
??????? int bpm = model.getBPM();?
??????? model.setBPM(bpm - 1);?
????? }?
???? public void setBPM(int bpm) {?
??????? model.setBPM(bpm);?
??? }?
}

搞定!我們寫一段測試代碼來使用我們自己的MVC,先創建一個模型,然后創建一個控制器,將模型傳入其中,控制器創建視圖:

public class DJTestDrive {

??? public static void main (String[] args) {?
??????? BeatModelInterface model = new BeatModel();?
??????? ControllerInterface controller = new BeatController(model);?
??? }?
}

5.我們現在利用這個MVC模型完成另一項工作:心臟監視。我們希望將HeartModel適配成BeatModel

首先我們更換一下模型:

public interface HeartModelInterface {?
??? int getHeartRate();?
??? void registerObserver(BeatObserver o);?
??? void removeObserver(BeatObserver o);?
??? void registerObserver(BPMObserver o);?
??? void removeObserver(BPMObserver o);?
}

此時,我們需要知道視圖只知道getBPM而不知道getHeartRate,那么這就需要我們使用適配器模式進行適配了。這就引出了一個MVC中重要的技巧:

使用適配器將模型適配成符合現有視圖和控制器的需要的模型。

public class HeartAdapter?implements BeatModelInterface?{//適配器要對被適配的接口進行實現,也就是那個在Client中被直接使用的部分?
??? HeartModelInterface heart;//適配器中要保留另一部分的引用?
??? public HeartAdapter(HeartModelInterface heart) {?
??????? this.heart = heart;?
??? }

??? public void initialize() {}//不需要的部分我們在適配器中留空。?
??? public void on() {}?
??? public void off() {}?
??? public int getBPM() {?
??????? return heart.getHeartRate();//適配器在此處運轉?
??? }?
??? public void setBPM(int bpm) {}?
??? public void registerObserver(BeatObserver o) {//將注冊觀察者Server的方法委托給heart?
??????? heart.registerObserver(o);?
??? }?
??? public void removeObserver(BeatObserver o) {?
??????? heart.removeObserver(o);?
??? }?
??? public void registerObserver(BPMObserver o) {?
??????? heart.registerObserver(o);?
??? }?
??? public void removeObserver(BPMObserver o) {?
??????? heart.removeObserver(o);?
??? }?
}

適配器ready以后,我們可以完成控制器了:

public class HeartController implements ControllerInterface {?
??? HeartModelInterface model;?
??? DJView view;?
??? public HeartController(HeartModelInterface model) {?
??????? this.model = model;?
????? ?
view = new DJView(this, new HeartAdapter(model)); //用適配器進行包裝?
??????? view.createView();?
??????? view.createControls();?
??????? view.disableStopMenuItem();?
??????? view.disableStartMenuItem();?
??? }?
??? public void start() {} //沒有實際作用的我們留空?
??? public void stop() {}?
??? public void increaseBPM() {}?
??? public void decreaseBPM() {}?
???? public void setBPM(int bpm) {}?
}

我們現在就可以寫一段測試代碼了:

public class HeartTestDrive {

??? public static void main (String[] args) {?
??????? HeartModel heartModel = new HeartModel();//首先創建模型?
??????? ControllerInterface model = new HeartController(heartModel);//然后創建控制器,控制器中創建了視圖?
??? }?
}

6.最后我們提一句:在Web開發中,MVC被經常叫做Model 2。有了這個模型,該編程的人就去做編程,該做網頁的人就去做網頁。JSP只知道會從控制器收到一個Bean。在這個場景中,其實Bean其實就是模型,而且JSP只用到這個bean的BPM屬性。

作者:gnuhpc
出處:http://www.cnblogs.com/gnuhpc/

總結

以上是生活随笔為你收集整理的【HeadFirst 设计模式学习笔记】13 MVC分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。