设计模式学习--复合模式(Compound Pattern)

设计模式学习--复合模式(Compound Pattern)

分类: 【设计模式】   34人阅读  评论(0)  收藏  举报
设计模式 MVC 编程

目录(?)[+]

设计模式学习--复合模式(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模式

———————————————————————————————————————————————————

设计模式学习--复合模式(Compound Pattern)_第1张图片





上面这幅图描述的就是MVC模式,下面根据这幅图对MVC进行一下解释。

1、你是用户—你和视图交互

视图是模型的窗口。当你对视图做一些事事(比方说:按下“播放”按钮),视图就告诉控制器你做了什么。控制器会负责处理。

2、控制器要求模型改变状态

控制器解读你的动作。如果你按下某个按钮,控制器会理解这个动作的意义,并告知模型如何做出对应的动作。

3.控制器也可能要求视图做改变。

当控制器从视图接收到某一动作,结构可能是它也需要告诉视图改变其结果。比方说,控制器可以将界面上的某些按钮或菜单项变成有效或无效。

4.当模型发生改变时,模型会通知视图。

不管是你做了某些动作(比方说按下按钮)还是内部有了某些改变(比方说播放清单的下一首歌开始)只要当模型内的东西改变时,模型都会通知视图它的状态改变了。

5.视图向模型询问状态。

视图直接从模型取得它显示的状态。比方说,当模型通知视图新歌开始播放,视图向模型询问歌名并显示出来。当控制器请求视图改变时,视图也可能向模型询问某些状态。


戴着模式的有色眼镜看MVC

MVC使用哪些模式呢,由哪些模式组成的呢?

使用了:

1.策略模式

   视图和控制器实现了策略模式:视图是一个对象,可以被调整使用不同的策略,而控制提供了策略。视图只关心系统中可视的部分,对与任何界面行为,都委托给控制器处理。使用策略模式也可以让视图和模型之间关系解耦,因为控制器负责和模型交互来传递用户的请求。对与工作是怎么完成的,视图豪不知情。

2.观察者模式

   模型实现了观察者模式,当状态改变时,相关对象将持续更新。使用观察者模式,可以让模型完全独立于视图和控制器。同一个模型可以使用不同的视图,甚至可以同时使用多个视图。

3.组合模式

   显示包括了窗口、面板、按钮、文本标签等。每个显示组件如果不是组合节点(例如窗口),就是叶节点(例如按钮)。当控制器告诉视图更新时,只需告诉视图最顶层的组件即可,组合会处理其余的事。


以上就是关于MVC使用各种模式的说明,下面来看一个例子介绍本篇博客。


利用MVC控制节拍

BeatModelInterface.java

[java]  view plain copy print ?
  1. package combined;  
  2.   
  3. public interface BeatModelInterface {  
  4.       
  5.     void initialize(); //在BeatModel被初始化之后,就会调用此方法  
  6.     void on();          //打开节拍器  
  7.     void off();         //关闭节拍器  
  8.     void setBPM(int bpm);   //设置bmp值  
  9.     int getBPM();           //获得当前bmp值  
  10.     void registerObserver(BeatObserver o);   
  11.     void removeObserver(BeatObserver o);  
  12.     void registerObserver(BPMObserver o);  
  13.     void removeObserver(BPMObserver o);  
  14. }  

模型

BeatModel.java

[java]  view plain copy print ?
  1. package combined;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. import javax.sound.midi.MetaEventListener;  
  6. import javax.sound.midi.MetaMessage;  
  7. import javax.sound.midi.MidiEvent;  
  8. import javax.sound.midi.MidiSystem;  
  9. import javax.sound.midi.Sequence;  
  10. import javax.sound.midi.Sequencer;  
  11. import javax.sound.midi.ShortMessage;  
  12. import javax.sound.midi.Track;  
  13.   
  14. public class BeatModel implements BeatModelInterface, MetaEventListener {  
  15.     Sequencer sequencer;    //定序器(Sequencer)对象知道如何产生真实的节拍  
  16.     ArrayList beatObservers = new ArrayList();  //两种观察者(一种观察节拍,一种观察BPM改变)  
  17.     ArrayList bpmObservers = new ArrayList();  
  18.     int bpm = 90;  
  19.     Sequence sequence;  
  20.     Track track;  
  21.       
  22.     public void initialize() {  
  23.         setUpMidi();  
  24.         buildTrackAndStart();  
  25.     }  
  26.    
  27.     public void on() {  
  28.         sequencer.start();  
  29.         setBPM(90);  
  30.     }  
  31.    
  32.     public void off() {  
  33.         setBPM(0);  
  34.         sequencer.stop();  
  35.     }  
  36.    
  37.     public void setBPM(int bpm) {  
  38.         this.bpm = bpm;         //设置BPM实例变量  
  39.         sequencer.setTempoInBPM(getBPM());  //要求定序器改变BPM  
  40.         notifyBPMObservers();   //通知所有的BPM观察者,BPM已经改变  
  41.     }  
  42.     
  43.     public int getBPM() {  
  44.         return bpm;  
  45.     }  
  46.     
  47.     void beatEvent() {  
  48.         notifyBeatObservers();  
  49.     }  
  50.     
  51.      
  52.     public void registerObserver(BeatObserver o) {  
  53.         beatObservers.add(o);  
  54.     }  
  55.     
  56.     public void notifyBeatObservers() {  
  57.         for(int i = 0; i < beatObservers.size(); i++) {  
  58.             BeatObserver observer = (BeatObserver)beatObservers.get(i);  
  59.             observer.updateBeat();  
  60.         }  
  61.     }  
  62.     
  63.     public void registerObserver(BPMObserver o) {  
  64.         bpmObservers.add(o);  
  65.     }  
  66.     
  67.     public void notifyBPMObservers() {  
  68.         for(int i = 0; i < bpmObservers.size(); i++) {  
  69.             BPMObserver observer = (BPMObserver)bpmObservers.get(i);  
  70.             observer.updateBPM();  
  71.         }  
  72.     }  
  73.   
  74.   
  75.     public void removeObserver(BeatObserver o) {  
  76.         int i = beatObservers.indexOf(o);  
  77.         if (i >= 0) {  
  78.             beatObservers.remove(i);  
  79.         }  
  80.     }  
  81.   
  82.   
  83.   
  84.     public void removeObserver(BPMObserver o) {  
  85.         int i = bpmObservers.indexOf(o);  
  86.         if (i >= 0) {  
  87.             bpmObservers.remove(i);  
  88.         }  
  89.     }  
  90.   
  91.   
  92.     public void meta(MetaMessage message) {  
  93.         if (message.getType() == 47) {  
  94.             beatEvent();  
  95.             sequencer.start();  
  96.             setBPM(getBPM());  
  97.         }  
  98.     }  
  99.   
  100.     public void setUpMidi() {  
  101.         try {  
  102.             sequencer = MidiSystem.getSequencer();  
  103.             sequencer.open();  
  104.             sequencer.addMetaEventListener(this);  
  105.             sequence = new Sequence(Sequence.PPQ,4);  
  106.             track = sequence.createTrack();  
  107.             sequencer.setTempoInBPM(getBPM());  
  108.         } catch(Exception e) {  
  109.                 e.printStackTrace();  
  110.         }  
  111.     }   
  112.   
  113.      public void buildTrackAndStart() {  
  114.         int[] trackList = {350460};  
  115.       
  116.         sequence.deleteTrack(null);  
  117.         track = sequence.createTrack();  
  118.   
  119.         makeTracks(trackList);  
  120.         track.add(makeEvent(192,9,1,0,4));        
  121.         try {  
  122.             sequencer.setSequence(sequence);                      
  123.         } catch(Exception e) {  
  124.             e.printStackTrace();  
  125.         }  
  126.     }   
  127.               
  128.     public void makeTracks(int[] list) {          
  129.          
  130.        for (int i = 0; i < list.length; i++) {  
  131.           int key = list[i];  
  132.   
  133.           if (key != 0) {  
  134.              track.add(makeEvent(144,9,key, 100, i));  
  135.              track.add(makeEvent(128,9,key, 100, i+1));  
  136.           }  
  137.        }  
  138.     }  
  139.           
  140.     public  MidiEvent makeEvent(int comd, int chan, int one, int two, int tick) {  
  141.         MidiEvent event = null;  
  142.         try {  
  143.             ShortMessage a = new ShortMessage();  
  144.             a.setMessage(comd, chan, one, two);  
  145.             event = new MidiEvent(a, tick);  
  146.               
  147.         } catch(Exception e) {  
  148.             e.printStackTrace();   
  149.         }  
  150.         return event;  
  151.     }  
  152. }  


观察者

BeatObserver.java

[java]  view plain copy print ?
  1. package combined;  
  2.   
  3. public interface BeatObserver {  
  4.     void updateBeat();  
  5. }  


BPMObserver.java
[java]  view plain copy print ?
  1. package combined;  
  2.   
  3. public interface BPMObserver {  
  4.     void updateBPM();  
  5. }  

视图

BeatBar.java

[java]  view plain copy print ?
  1. package combined;  
  2.   
  3. import javax.swing.JProgressBar;  
  4.   
  5. public class BeatBar extends JProgressBar implements Runnable {  
  6.     JProgressBar progressBar;  
  7.     Thread thread;  
  8.       
  9.   
  10.     public BeatBar() {  
  11.         thread = new Thread(this);  
  12.         setMaximum(100);  
  13.         thread.start();  
  14.     }  
  15.   
  16.   
  17.     @Override  
  18.     public void run() {  
  19.         for(;;) {  
  20.             int value = getValue();  
  21.             value = (int)(value * 0.75);  
  22.             setValue(value);  
  23.             repaint();  
  24.             try {  
  25.                 Thread.sleep(50);  
  26.             } catch (Exception e) {  
  27.                 e.printStackTrace();  
  28.             }  
  29.         }  
  30.     }  
  31.   
  32. }  



DJView.java

[java]  view plain copy print ?
  1. package combined;  
  2.   
  3. import java.awt.BorderLayout;  
  4. import java.awt.Dimension;  
  5. import java.awt.GridLayout;  
  6. import java.awt.event.ActionEvent;  
  7. import java.awt.event.ActionListener;  
  8.   
  9. import javax.imageio.plugins.bmp.BMPImageWriteParam;  
  10. import javax.swing.BorderFactory;  
  11. import javax.swing.JButton;  
  12. import javax.swing.JFrame;  
  13. import javax.swing.JLabel;  
  14. import javax.swing.JMenu;  
  15. import javax.swing.JMenuBar;  
  16. import javax.swing.JMenuItem;  
  17. import javax.swing.JPanel;  
  18. import javax.swing.JTextField;  
  19. import javax.swing.SwingConstants;  
  20.   
  21. /** 
  22.  * 视图类,它是一个观察者,同时关心实时节拍和BPM的改变 
  23.  * @author Administrator 
  24.  * 
  25.  */  
  26. public class DJView implements ActionListener, BeatObserver, BPMObserver {  
  27.     BeatModelInterface model;  
  28.     ControllerInterface controller;  
  29.     JFrame viewFrame;  
  30.     JPanel viewPanel;  
  31.     BeatBar beatBar;  
  32.     JLabel bpmOutputLabel;  
  33.     JFrame controlFrame;  
  34.     JPanel controlPanel;  
  35.     JLabel bpmLabel;  
  36.     JTextField bpmTextField;  
  37.     JButton setBPMButton;  
  38.     JButton increaseBPMButton;  
  39.     JButton decreaseBPMButton;  
  40.     JMenuBar menuBar;  
  41.     JMenu menu;  
  42.     JMenuItem startMenuItem;  
  43.     JMenuItem stopMenuItem;  
  44.   
  45.     public DJView(ControllerInterface controller, BeatModelInterface model) {     
  46.         this.controller = controller;  
  47.         this.model = model;  
  48.         model.registerObserver((BeatObserver)this);  
  49.         model.registerObserver((BPMObserver)this);  
  50.     }  
  51.       
  52.     public void createView() {  
  53.         // Create all Swing components here  
  54.         viewPanel = new JPanel(new GridLayout(12));  
  55.         viewFrame = new JFrame("View");  
  56.         viewFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  57.         viewFrame.setSize(new Dimension(10080));  
  58.         bpmOutputLabel = new JLabel("offline", SwingConstants.CENTER);  
  59.         beatBar = new BeatBar();  
  60.         beatBar.setValue(0);  
  61.         JPanel bpmPanel = new JPanel(new GridLayout(21));  
  62.         bpmPanel.add(beatBar);  
  63.         bpmPanel.add(bpmOutputLabel);  
  64.         viewPanel.add(bpmPanel);  
  65.         viewFrame.getContentPane().add(viewPanel, BorderLayout.CENTER);  
  66.         viewFrame.pack();  
  67.         viewFrame.setVisible(true);  
  68.     }  
  69.     
  70.     
  71.     public void createControls() {  
  72.         // Create all Swing components here  
  73.         JFrame.setDefaultLookAndFeelDecorated(true);  
  74.         controlFrame = new JFrame("Control");  
  75.         controlFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  
  76.         controlFrame.setSize(new Dimension(10080));  
  77.   
  78.         controlPanel = new JPanel(new GridLayout(12));  
  79.   
  80.         menuBar = new JMenuBar();  
  81.         menu = new JMenu("DJ Control");  
  82.         startMenuItem = new JMenuItem("Start");  
  83.         menu.add(startMenuItem);  
  84.         startMenuItem.addActionListener(new ActionListener() {  
  85.             public void actionPerformed(ActionEvent event) {  
  86.                 controller.start();  
  87.             }  
  88.         });  
  89.         stopMenuItem = new JMenuItem("Stop");  
  90.         menu.add(stopMenuItem);   
  91.         stopMenuItem.addActionListener(new ActionListener() {  
  92.             public void actionPerformed(ActionEvent event) {  
  93.                 controller.stop();  
  94.             }  
  95.         });  
  96.         JMenuItem exit = new JMenuItem("Quit");  
  97.         exit.addActionListener(new ActionListener() {  
  98.             public void actionPerformed(ActionEvent event) {  
  99.                 System.exit(0);  
  100.             }  
  101.         });  
  102.   
  103.         menu.add(exit);  
  104.         menuBar.add(menu);  
  105.         controlFrame.setJMenuBar(menuBar);  
  106.   
  107.         bpmTextField = new JTextField(2);  
  108.         bpmLabel = new JLabel("Enter BPM:", SwingConstants.RIGHT);  
  109.         setBPMButton = new JButton("Set");  
  110.         setBPMButton.setSize(new Dimension(10,40));  
  111.         increaseBPMButton = new JButton(">>");  
  112.         decreaseBPMButton = new JButton("<<");  
  113.         setBPMButton.addActionListener(this);  
  114.         increaseBPMButton.addActionListener(this);  
  115.         decreaseBPMButton.addActionListener(this);  
  116.   
  117.         JPanel buttonPanel = new JPanel(new GridLayout(12));  
  118.   
  119.         buttonPanel.add(decreaseBPMButton);  
  120.         buttonPanel.add(increaseBPMButton);  
  121.   
  122.         JPanel enterPanel = new JPanel(new GridLayout(12));  
  123.         enterPanel.add(bpmLabel);  
  124.         enterPanel.add(bpmTextField);  
  125.         JPanel insideControlPanel = new JPanel(new GridLayout(31));  
  126.         insideControlPanel.add(enterPanel);  
  127.         insideControlPanel.add(setBPMButton);  
  128.         insideControlPanel.add(buttonPanel);  
  129.         controlPanel.add(insideControlPanel);  
  130.           
  131.         bpmLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));  
  132.         bpmOutputLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));  
  133.   
  134.         controlFrame.getRootPane().setDefaultButton(setBPMButton);  
  135.         controlFrame.getContentPane().add(controlPanel, BorderLayout.CENTER);  
  136.   
  137.         controlFrame.pack();  
  138.         controlFrame.setVisible(true);  
  139.     }  
  140.   
  141.     public void enableStopMenuItem() {  
  142.         stopMenuItem.setEnabled(true);  
  143.     }  
  144.   
  145.     public void disableStopMenuItem() {  
  146.         stopMenuItem.setEnabled(false);  
  147.     }  
  148.   
  149.     public void enableStartMenuItem() {  
  150.         startMenuItem.setEnabled(true);  
  151.     }  
  152.   
  153.     public void disableStartMenuItem() {  
  154.         startMenuItem.setEnabled(false);  
  155.     }  
  156.   
  157.     public void actionPerformed(ActionEvent event) {  
  158.         if (event.getSource() == setBPMButton) {  
  159.             int bpm = Integer.parseInt(bpmTextField.getText());  
  160.             controller.setBPM(bpm);  
  161.         } else if (event.getSource() == increaseBPMButton) {  
  162.             controller.increaseBPM();  
  163.         } else if (event.getSource() == decreaseBPMButton) {  
  164.             controller.decreaseBPM();  
  165.         }  
  166.     }  
  167.   
  168.     public void updateBPM() {  
  169.         if (model != null) {  
  170.             int bpm = model.getBPM();  
  171.             if (bpm == 0) {  
  172.                 if (bpmOutputLabel != null) {  
  173.                     bpmOutputLabel.setText("offline");  
  174.                 }  
  175.             } else {  
  176.                 if (bpmOutputLabel != null) {  
  177.                     bpmOutputLabel.setText("Current BPM: " + model.getBPM());  
  178.                 }  
  179.             }  
  180.         }  
  181.     }  
  182.     
  183.     public void updateBeat() {  
  184.         if (beatBar != null) {  
  185.              beatBar.setValue(100);  
  186.         }  
  187.     }  
  188.   
  189. }  

控制器

[java]  view plain copy print ?
  1. package combined;  
  2.     
  3. public interface ControllerInterface {  
  4.     void start();  
  5.     void stop();  
  6.     void increaseBPM();  
  7.     void decreaseBPM();  
  8.     void setBPM(int bpm);  
  9. }  


BeatController.java
[java]  view plain copy print ?
  1. package combined;  
  2. /** 
  3.  * 控制器的实现 
  4.  * @author Administrator 
  5.  * 
  6.  */  
  7. public class BeatController implements ControllerInterface {  
  8.     BeatModelInterface model;  
  9.     DJView view;  
  10.       
  11.       
  12.   
  13.     public BeatController(BeatModelInterface model) {  
  14.         this.model = model;  
  15.         view = new DJView(this, model);  
  16.         view.createView();  
  17.         view.createControls();  
  18.         view.disableStopMenuItem();  
  19.         view.disableStartMenuItem();  
  20.         model.initialize();  
  21.     }  
  22.   
  23.     @Override  
  24.     public void start() {  
  25.         model.on();  
  26.         view.disableStartMenuItem();  
  27.         view.enableStopMenuItem();  
  28.     }  
  29.   
  30.     @Override  
  31.     public void stop() {  
  32.         model.off();  
  33.         view.disableStopMenuItem();  
  34.         view.enableStartMenuItem();  
  35.     }  
  36.   
  37.     @Override  
  38.     public void increaseBPM() {  
  39.         int bpm = model.getBPM();  
  40.         model.setBPM(bpm + 1);  
  41.     }  
  42.   
  43.     @Override  
  44.     public void decreaseBPM() {  
  45.         int bpm = model.getBPM();  
  46.         model.setBPM(bpm - 1);  
  47.     }  
  48.   
  49.     @Override  
  50.     public void setBPM(int bpm) {  
  51.         model.setBPM(bpm);  
  52.     }  
  53.   
  54. }  

测试

DJTestDrive.java

[java]  view plain copy print ?
  1. package combined;  
  2.     
  3. public class DJTestDrive {  
  4.   
  5.     public static void main (String[] args) {  
  6.         BeatModelInterface model = new BeatModel();  
  7.         ControllerInterface controller = new BeatController(model);  
  8.     }  
  9. }  


效果如下图:

    设计模式学习--复合模式(Compound Pattern)_第2张图片


关于MVC模式就说到这里,下一篇模式见。

你可能感兴趣的:(【设计模式】)