要點
———————————————————————————————————————————————————java
MVC是複合模式,結合觀察者模式、策略模式和組合模式。
模式使用觀察者模式,以便觀察者更新,同時保持二者之間解耦。
控制器是視圖的策略,視圖可使用不一樣的控制器實現,獲得不一樣的行爲。
視圖使用組合模式實現用戶界面,用戶界面一般組合了嵌套的組件,像面板、框架和按鈕。
這些模式攜手合做,把MVC模式的三層解耦,這樣能夠保持設計乾淨又有彈性。
適配器模式用來將新的模型適配成已有的視圖和控制器。
Model 2是MVC在Web上的應用。
在Model 2中,控制器實現成Servlet,而JSP/HTML實現視圖框架
MVC模式
———————————————————————————————————————————————————ide
上面這幅圖描述的就是MVC模式,下面根據這幅圖對MVC進行一下解釋。測試
一、你是用戶—你和視圖交互ui
視圖是模型的窗口。當你對視圖作一些事事(比方說:按下「播放」按鈕),視圖就告訴控制器你作了什麼。控制器會負責處理。this
二、控制器要求模型改變狀態。.net
控制器解讀你的動做。若是你按下某個按鈕,控制器會理解這個動做的意義,並告知模型如何作出對應的動做。設計
3.控制器也可能要求視圖作改變。component
當控制器從視圖接收到某一動做,結構多是它也須要告訴視圖改變其結果。比方說,控制器能夠將界面上的某些按鈕或菜單項變成有效或無效。orm
4.當模型發生改變時,模型會通知視圖。
無論是你作了某些動做(比方說按下按鈕)仍是內部有了某些改變(比方說播放清單的下一首歌開始)只要當模型內的東西改變時,模型都會通知視圖它的狀態改變了。
5.視圖向模型詢問狀態。
視圖直接從模型取得它顯示的狀態。比方說,當模型通知視圖新歌開始播放,視圖向模型詢問歌名並顯示出來。當控制器請求視圖改變時,視圖也可能向模型詢問某些狀態。
戴着模式的有色眼鏡看MVC
MVC使用哪些模式呢,由哪些模式組成的呢?
使用了:
1.策略模式
視圖和控制器實現了策略模式:視圖是一個對象,能夠被調整使用不一樣的策略,而控制提供了策略。視圖只關心繫統中可視的部分,對與任何界面行爲,都委託給控制器處理。使用策略模式也可讓視圖和模型之間關係解耦,由於控制器負責和模型交互來傳遞用戶的請求。對與工做是怎麼完成的,視圖豪不知情。
2.觀察者模式
模型實現了觀察者模式,當狀態改變時,相關對象將持續更新。使用觀察者模式,可讓模型徹底獨立於視圖和控制器。同一個模型可使用不一樣的視圖,甚至能夠同時使用多個視圖。
3.組合模式
顯示包括了窗口、面板、按鈕、文本標籤等。每一個顯示組件若是不是組合節點(例如窗口),就是葉節點(例如按鈕)。當控制器告訴視圖更新時,只需告訴視圖最頂層的組件便可,組合會處理其他的事。
以上就是關於MVC使用各類模式的說明,下面來看一個例子介紹本篇博客。
利用MVC控制節拍
BeatModelInterface.java
package combined;
public interface BeatModelInterface {
void initialize(); //在BeatModel被初始化以後,就會調用此方法
void on(); //打開節拍器
void off(); //關閉節拍器
void setBPM(int bpm); //設置bmp值
int getBPM(); //得到當前bmp值
void registerObserver(BeatObserver o);
void removeObserver(BeatObserver o);
void registerObserver(BPMObserver o);
void removeObserver(BPMObserver o);
}
模型
BeatModel.java
package combined;
import java.util.ArrayList;
import javax.sound.midi.MetaEventListener;
import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
public class BeatModel implements BeatModelInterface, MetaEventListener {
Sequencer sequencer; //定序器(Sequencer)對象知道如何產生真實的節拍
ArrayList beatObservers = new ArrayList(); //兩種觀察者(一種觀察節拍,一種觀察BPM改變)
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; //設置BPM實例變量
sequencer.setTempoInBPM(getBPM()); //要求定序器改變BPM
notifyBPMObservers(); //通知全部的BPM觀察者,BPM已經改變
}
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;
}
}
觀察者
BeatObserver.java
package combined;
public interface BeatObserver {
void updateBeat();
}
BPMObserver.java
package combined;
public interface BPMObserver {
void updateBPM();
}
視圖
BeatBar.java
package combined;
import javax.swing.JProgressBar;
public class BeatBar extends JProgressBar implements Runnable {
JProgressBar progressBar;
Thread thread;
public BeatBar() {
thread = new Thread(this);
setMaximum(100);
thread.start();
}
@Override
public void run() {
for(;;) {
int value = getValue();
value = (int)(value * 0.75);
setValue(value);
repaint();
try {
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
DJView.java
package combined;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.imageio.plugins.bmp.BMPImageWriteParam;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
/**
* 視圖類,它是一個觀察者,同時關心實時節拍和BPM的改變
* @author Administrator
*
*/
public class DJView implements ActionListener, BeatObserver, BPMObserver {
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);
}
}
}
控制器
package combined;
public interface ControllerInterface {
void start();
void stop();
void increaseBPM();
void decreaseBPM();
void setBPM(int bpm);
}
BeatController.java
package combined;
/**
* 控制器的實現
* @author Administrator
*
*/
public class BeatController implements ControllerInterface {
BeatModelInterface model;
DJView view;
public BeatController(BeatModelInterface model) {
this.model = model;
view = new DJView(this, model);
view.createView();
view.createControls();
view.disableStopMenuItem();
view.disableStartMenuItem();
model.initialize();
}
@Override
public void start() {
model.on();
view.disableStartMenuItem();
view.enableStopMenuItem();
}
@Override
public void stop() {
model.off();
view.disableStopMenuItem();
view.enableStartMenuItem();
}
@Override
public void increaseBPM() {
int bpm = model.getBPM();
model.setBPM(bpm + 1);
}
@Override
public void decreaseBPM() {
int bpm = model.getBPM();
model.setBPM(bpm - 1);
}
@Override
public void setBPM(int bpm) {
model.setBPM(bpm);
}
}
測試
DJTestDrive.java
package combined;
public class DJTestDrive {
public static void main (String[] args) {
BeatModelInterface model = new BeatModel();
ControllerInterface controller = new BeatController(model);
}
}
效果以下圖:
————————————————版權聲明:本文爲CSDN博主「IT_xiao小巫」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連接及本聲明。原文連接:https://blog.csdn.net/wwj_748/article/details/9747941