`
0428loveyu
  • 浏览: 29129 次
  • 性别: Icon_minigender_2
  • 来自: 西安
文章分类
社区版块
存档分类
最新评论

GUI中的观察者模式

阅读更多

MVC模式对于用户界面的开发有着重要的意义,在Java中,不是按照标准的MVC模式实现的,而是将控制器和视图结合起来,而模型独立存在。模型成为观察者模式中的被观察对象,而控制器和视图则作为观察者。


下面是一个改自《重构》的例子,如下图所示:三个输入框之间的关系为start+length=end。 修改其中的任何一个输入框,都要保持这个关系恒成立。如果将数据模型和GUI界面、事件处理全部混在一个类,一样可以实现这个功能,但是代码将十分难懂,也难以维护和拓展。因此将数据模型独立出来。



首先定义数据模型类,数据模型提供接口操作,用于查询、修改或者其他更复杂的数据操作,供用户调用,代码如下:

/**
 * 
 */
package design.patterns.eventgenerator.observer;

import java.util.Observable;

/**
 * @author Brandon B. Lin
 * 
 */
public class TestModel extends Observable {

	private String end = "0";
	private String start = "0";
	private String length = "0";

	public String getEnd() {
		return end;
	}

	public void setEnd(String end) {
		this.end = end;
		setChanged();
		notifyObservers();
	}

	public String getStart() {
		return start;
	}

	public void setStart(String start) {
		this.start = start;
		setChanged();
		notifyObservers();
	}

	public String getLength() {
		return length;
	}

	public void setLength(String length) {
		this.length = length;
		setChanged();
		notifyObservers();
	}

	public void calculateLength() {
		try {
			int start = Integer.parseInt(getStart());
			int end = Integer.parseInt(getEnd());
			int length = end - start;
			setLength(String.valueOf(length));
		} catch (NumberFormatException exception) {
			exception.printStackTrace();
		}
	}

	public void calculateEnd() {
		try {
			int start = Integer.parseInt(getStart());
			int lenght = Integer.parseInt(getLength());
			int end = start + lenght;
			setEnd(String.valueOf(end));
		} catch (NumberFormatException exception) {
			exception.printStackTrace();
		}
	}

}
这个模型类继承了Observable抽象类,提供查询数据的get方法,同时提供修改数据的方法set,如果数据被修改,通知所有监听者(setChanged和notifyObservers方法)。除此以外,它还提供了逻辑操作接口calculateLength和calculateEnd。


接着定义用户界面,处理时间,同时与模型交互。代码如下:

/**
 * 
 */
package design.patterns.eventgenerator.observer;

import java.awt.GridLayout;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

/**
 * @author Brandon B. Lin
 * 
 */
public class TestWindow extends JFrame implements Observer {

	private static final long serialVersionUID = 8232669335169364475L;
	private JTextField startField;
	private JTextField endField;
	private JTextField lengthField;

	private TestModel model;

	public TestWindow() {
		initFrame();
		initModel();
	}

	private void initFrame() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setTitle("Test Window");
		setSize(400, 300);
		add(createTextFieldPanel());
	}

	private void initModel() {
		model = new TestModel();
		model.addObserver(this);
		update(model, null);
	}

	private JPanel createTextFieldPanel() {
		JPanel textFieldPanel = new JPanel();
		textFieldPanel.setLayout(new GridLayout(3, 2));
		JLabel startLabel = new JLabel("Start: ");
		startField = new JTextField("0", 5);

		SymbolFocus listener = new SymbolFocus();
		startField.addFocusListener(listener);

		JLabel endLabel = new JLabel("End: ");
		endField = new JTextField("0", 5);
		endField.addFocusListener(listener);
		JLabel lengthLabel = new JLabel("Length: ");
		lengthField = new JTextField("0", 5);
		lengthField.addFocusListener(listener);

		textFieldPanel.add(startLabel);
		textFieldPanel.add(startField);
		textFieldPanel.add(endLabel);
		textFieldPanel.add(endField);
		textFieldPanel.add(lengthLabel);
		textFieldPanel.add(lengthField);

		return textFieldPanel;

	}

	// self encapsulate field
	public String getEnd() {
		return model.getEnd();
	}

	public void setEnd(String newValue) {
		model.setEnd(newValue);
	}

	public String getStart() {
		return model.getStart();
	}

	public void setStart(String newValue) {
		model.setStart(newValue);
	}

	public String getLength() {
		return model.getLength();
	}

	public void setLength(String newValue) {
		model.setLength(newValue);
	}

	@Override
	public void update(Observable observable, Object context) {
		endField.setText(model.getEnd());
		startField.setText(model.getStart());
		lengthField.setText(model.getLength());
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {
				new TestWindow().setVisible(true);
			}
		});

	}

	class SymbolFocus extends FocusAdapter {
		@Override
		public void focusLost(FocusEvent event) {
			Object source = event.getSource();
			if (source == lengthField) {
				setLength(lengthField.getText());
				model.calculateEnd();
			} else if (source == startField) {
				setStart(startField.getText());
				model.calculateLength();
			} else {
				setEnd(endField.getText());
				model.calculateLength();
			}
		}

	}

}

这个类实现了观察者接口Observer,在构造函数中,初始化用户界面,然后初始化模型。通过持有对模型类的引用来与模型类交互。当用户改变任何一个输入框的值的时候,作为响应,首先改变模型类中相应的数据,然后调用模型的业务逻辑,其结果也是改变了模型的数据,而一旦有模型数据改变,作为观察者的用户界面都会得到通知,得到通知后就可以更新界面。逻辑十分清晰。


《重构》中把这个称谓“Duplicate Observed Data”,其实就是通过观察者模式来保持数据模型和用户界面(数据的显示)之间的同步,是一种MVC变体。我们还看到在TestWindow类中,用到了“Self encapsulate field”重构方法,这一重构在这个例子中也许看不到什么好处,我们完全可以通过对model相关方法直接调用,但是通过封装,以函数的形式提供访问,显得更加整洁,另外,当子类覆盖这些方法的时候,可以对这些数据进行额外的操作修改。




分享到:
评论

相关推荐

    Android设计模式--观察者模式DEMO

    Android设计模式--观察者模式DEMO 观察者模式是一个使用频率非常高的模式,他最常用的地方是GUI系统和订阅-发布系统。 该模式的最重要的作用就是解耦,使观察者和被观察者之间依赖尽可能小,甚至好无依赖。

    浅谈Android设计模式学习之观察者模式

    观察者模式在实际项目中使用的也是非常频繁的,它最常用的地方是GUI系统、订阅——发布系统等。因为这个模式的一个重要作用就是解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。以GUI系统来说,应用的UI具有易变...

    软件设计模式与体系结构(讲解+代码)

     【例6.17】事件体系结构-观察者模式-大草原1  【例6.18】事件体系结构-观察者模式-大草原2  【例6.19】事件体系结构-观察者模式-温度显示  【例6.21】层次架构-软件测试  【例6.22】层次架构-银行- ...

    基于Java采用5种设计模式开发的(GUI)五子棋【100012593】

    其中工厂方法模式给用户选择背景音乐、享元模式用于设计五子棋的棋子类、备忘录模式来实现悔棋功能,观察者模式来实现不同类中的JPanel与JFrame通信来实现关闭窗口,策略模式来提供用户来选择人机模式与人人模式。

    GUI.rar_chat observer

    GUI编程与观察者模式。实现一个简单的聊天程序,实现客户端和服务器端的消息互通

    观察者模式:观察者模式的一个例子-matlab开发

    观察者模式允许将 GUI 元素(控件和视图)与数据模型分离。 所有视图通过notify()/update()自动同步 例子: iw1 = interval_window(); iw2 = interval_window_flow(); iv = interval_view(); i1 = 间隔(2,8,6); ...

    体系结构学习代码!特别详细丰富

     【例6.19】事件体系结构-观察者模式-温度显示  【例6.21】层次架构-软件测试  【例6.22】层次架构-银行- Access数据库  【例6.23】MVC架构-二手车拍卖-无观察者  【例6.24】MVC架构-二手车拍卖-观察者-3...

    Java的23种设计模式

    工厂模式, 工厂方法模式,单例模式, 外观(Facade)模式, 观察者(Observer)模式,桥接(Bridge)模式都是比较常用的,不同的项目有不同的设计方向.....

    毕业设计JAVA Gui Swing 仓库商品管理系统(文档+视频+源码)

    能学到什么:①工厂模式、策略模式、观察者模 ;②java gui中的事件监听、事件触发、并发编程等内容 阅读建议:此资源以开发简化图书馆管理系统学习swing设计的原理和应用,不仅是代码编写实现也更注重内容上的需求...

    基于QT+C++开发的2048游戏+源码(毕业设计&课程设计&项目开发)

    基于QT+C++开发的2048游戏+源码,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申...核心使用观察者模式与GUI解耦,因此很容易提取代码,提取核心,然后围绕它构建新的GUI。

    java swing的mvc模式的简单框架

    java swing的mvc模式的简单框架,应用了用观察者模式于gui和控制器之间,将gui作为一个对象传进控制器进行处理,这个简单框架的控制器那里还有待改进。这个代码中包含了使用框架的简单例子在里面

    Object-Oriented-Analysis-Design:面向对象的分析和设计(JAVA语言)设计模式,Java GUI

    家庭作业的主题: HW01: PART1->策略设计模式PART2->观察者设计模式PART3->装饰器设计模式HW02: PART1->单例设计模式PART2->迭代器设计模式PART3->状态和观察者模式PART4->代理设计模式中期: PART1->抽象工厂...

    email-service:通过GUI实现电子邮件服务的Java应用程序

    源代码包含服务器和客户端实现,使用MVC模式并遵循观察者模式原则。目录项目介绍该项目由电子邮件服务器构成,该服务器同时处理用户的邮箱和必要的邮件客户端,允许用户登录各自的邮箱。 邮件服务器处理电子邮件...

    Java理论与实践:做个好的(事件)侦听器

    本文介绍了AWT 和Swing组件使用观察者模式消除了GUI事件生成与它们在指定应用程序中的语义之间的耦合。类似地,Swing 的模型类,也使用观察者消除数据模型表示 与视图生成之间的耦合,从而支持相同数据的多个独立的...

    level4project.zip

    用设计模式做的带GUI界面的Java小程序,导入时注意包中包的建立。包括了观察者模式 装饰器模式 工厂模式 单例模式 外观模式等

    纯swing开发的界面

    这是一个纯swing开发的界面,内部采用了观察言观察者模式,但观察者模式在此用得不很合适,有一个小地方在这方面设计上并不是理想的效果.建议采用命令模式重新设计为佳.

    Java-Robot-Roundup:通过Java Swing GUI显示的机器人互动益智游戏

    Java-Robot-Roundup 一个用Java编写的简单机器人综述游戏。 使用观察者/观察者模式。 所有图形用户界面均使用Java Swing编写。

    C#,MVC实列,可以在VS2008上直接运行

    C#,MVC实列,可以在VS2008上直接运行,MVC实际上是,观察者模式,组合模式,策略模式联合运用的一种复合模式,因为组合模式已经被集成在GUI上面了,实际上就是观察都与策略模式复合运用形成的一个模式,...

    java8源码-jcohy-study-sample:个人学习整理

    java8 源码 本项目已迁移至 ...策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。大致分为四类关系: jcohy-study-

Global site tag (gtag.js) - Google Analytics