设计模式学习--复合模式(Compound Pattern)
设计模式学习--复合模式(Compound Pattern)
概述
2013年8月4日《Head First设计模式学习》
今天来介绍这本书最后一个模式——复合模式,当然设计模式可不仅仅只有那么多,经过前辈们演变出来的模式可是很多的,我所介绍的只是比较通用的模式,可以说是一种规范吧,我想在实际的工作中,简单的一种模式是不能满足项目千奇百怪的需求的,那就可能需要使用多种模式的组合来满足了,本篇博客主要介绍的就是MVC模式,这是复合模式的经典模式,我想做Java Web开发的开发者对这个模式一定不陌生,这个模式给开发带来大大的便利,把它分为了M(Model)、V(View)、C(Control)三层,让设计变得干净又有弹性。
复合模式——复合模式结合两个或以上的模式,组成一个解决方案,解决一再发生的一般性问题。
跟以往一样回顾以往的知识:
OO原则
- 封装变化
- 多用组合,少用继承
- 针对接口编程,不针对实现编程
- 为交互对象之间的松耦合设计而努力
- 类应该对扩展开放,对修改关闭
- 依赖抽象,不要以来具体类
- 只和朋友交谈
- 别找我,我会找你
- 类应该只有一个改变的理由
要点
- MVC是复合模式,结合观察者模式、策略模式和组合模式。
- 模式使用观察者模式,以便观察者更新,同时保持两者之间解耦。
- 控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为。
- 视图使用组合模式实现用户界面,用户界面通常组合了嵌套的组件,像面板、框架和按钮。
- 这些模式携手合作,把MVC模式的三层解耦,这样可以保持设计干净又有弹性。
- 适配器模式用来将新的模型适配成已有的视图和控制器。
- Model 2是MVC在Web上的应用。
- 在Model 2中,控制器实现成Servlet,而JSP/HTML实现视图
MVC模式
———————————————————————————————————————————————————
上面这幅图描述的就是MVC模式,下面根据这幅图对MVC进行一下解释。
1、你是用户—你和视图交互
视图是模型的窗口。当你对视图做一些事事(比方说:按下“播放”按钮),视图就告诉控制器你做了什么。控制器会负责处理。
2、控制器要求模型改变状态。
控制器解读你的动作。如果你按下某个按钮,控制器会理解这个动作的意义,并告知模型如何做出对应的动作。
3.控制器也可能要求视图做改变。
当控制器从视图接收到某一动作,结构可能是它也需要告诉视图改变其结果。比方说,控制器可以将界面上的某些按钮或菜单项变成有效或无效。
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);
}
}
效果如下图:
关于MVC模式就说到这里,下一篇模式见。
设计模式学习--复合模式(Compound Pattern)的更多相关文章
- 设计模式学习--迭代器模式(Iterator Pattern)和组合模式(Composite Pattern)
设计模式学习--迭代器模式(Iterator Pattern) 概述 ——————————————————————————————————————————————————— 迭代器模式提供一种方法顺序 ...
- 乐在其中设计模式(C#) - 组合模式(Composite Pattern)
原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:weba ...
- 乐在其中设计模式(C#) - 提供者模式(Provider Pattern)
原文:乐在其中设计模式(C#) - 提供者模式(Provider Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 提供者模式(Provider Pattern) 作者:weba ...
- 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern)
原文:乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 访问者模式(Visitor Pattern) 作者:webabc ...
- 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)
原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...
- 乐在其中设计模式(C#) - 状态模式(State Pattern)
原文:乐在其中设计模式(C#) - 状态模式(State Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 状态模式(State Pattern) 作者:webabcd 介绍 允 ...
- 乐在其中设计模式(C#) - 备忘录模式(Memento Pattern)
原文:乐在其中设计模式(C#) - 备忘录模式(Memento Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 备忘录模式(Memento Pattern) 作者:webabc ...
- 乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern)
原文:乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 迭代器模式(Iterator Pattern) 作者:weba ...
- 乐在其中设计模式(C#) - 解释器模式(Interpreter Pattern)
原文:乐在其中设计模式(C#) - 解释器模式(Interpreter Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 解释器模式(Interpreter Pattern) 作 ...
随机推荐
- Memento 备忘录 快照模式
简介 定义: 在不破坏封装的前提下,捕获一个对象的[内部状态],并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态. 角色: 发起人Originator:要被备份的成员,它提供一创 ...
- Spring.Net+NHibernate+asp.net mvc + easyui
毕业4个月的入手项目..前段时间在公司一直做的维护..为了弄明白自己也就跟着写了一个,目前也正在学习:不对的或者是有更好的还请各位赐教. 在学习的过程中主要参考::http://www.cnblogs ...
- 教你写Jquery插件
最近很多网友说 jQuery插件是什么啊?怎么写的啊?我不会写啊? 一大堆的问题一时都不知道怎么回答他们,个人认为是网友们把问题复杂化了. 其实就是把一些常用.实用.通用的功能封装起来而以,简单的来讲 ...
- CI 中css样式或者js样式加载不进来的情况
首先,目录应该是放在根目录下面的,和 application 目录同级 然后再application\config\config.php ,将默认路径配置成为自己的本访问路径 $config['bas ...
- DHCP服务器
DHCP指的是由服务器控制一段IP地址范围,客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码.首先,DHCP服务器必须是一台安装有Windows 2000 Server/Advanced ...
- 使用<span>标签为文字设置单独样式
这一小节讲解<span>标签,我们对<em>.<strong>.<span>这三个标签进行一下总结: 1. <em>和<strong& ...
- MySQL 管理
MySQL 管理 启动及关闭 MySQL 服务器 首先,我们需要通过以下命令来检查MySQL服务器是否启动: ps -ef | grep mysqld 如果MySql已经启动,以上命令将输出mysql ...
- Ipad亚麻布纹背景-最终效果_学习教程
- 50 Pow(x, n)(求x的n次方Medium)
题目意思:x为double,n为int,求x的n次方 思路分析:直接求,注意临界条件 class Solution { public: double myPow(double x, int n) { ...
- C# 构造函数如何调用父类构造函数或其他构造函数
class C : B{ C() : base(5) // call base constructor B(5) { } C(int i) : this() // ca ...