个人管理功能

在CSDN Blog撰写技术文章,即有机会入选CSDN技术中心,现在就去免费注册!已注册用户,点击登录

热门标签

专题历史

有人说SOA是一种IT策略,有人说SOA是一种架构理念,还有人说SOA是一种服务。SOA到底是什么?它将带来什么?软件产业的变革亦或是新的机遇下的挑战?业界权威专家带领我们一起去深究,去探索。BEA三位重量级专家与您共同探讨SOA

随着WPF/E更名为正式名称Silverlight,以及Silverlight 1.1 Alpha 版本的发布,答案变得清晰,而且令人兴奋! - 一个跨操作系统,跨浏览器的Web应用平台出现了。Silverlight 这样一个4.5MB的浏览器插件(1.1 Alpha文件)是如何做到的这些的?周岳: SilverLight-Web应用的一道强光

中国移动用户数量在大踏步地发展与增长,根据产业部的数据,仅三月就新增了670万户。预估计6月份之后,中国很快将迎来第五亿手机用户(平均不到3人拥有一台手机)而J2ME做为最重要的手机跨平台技术,凭借Java平台以其良好的开放性和支持能力,得到了众多手机厂商的支持。对众多开发者来说,J2ME程序易于移植,轻松实现“一次编写,到处运行”。J2ME系列开发专题,将带你从最基本的工具安装,环境配置开始,进入移动应用开发的世界。
 
CSDN移动开发系列之-“J2ME开发实训”

7月31日-8月1日,即将在上海召开甲骨文全球大会•亚太地区会议同期举行的甲骨文开发者大会,这是一项付费参加的面向开发人员的活动。在甲骨文开发者大会期间,您将听到世界一流的专家讲述如何使用Java、.NET、XML和PL/SQL以及Ajax、PHP、Spring、Groovy on Rails等流行技术来简化开发过程。在为期两天的甲骨文开发者大会中,您将能够提高自身的开发技能,扩充知识,参加几十场由专家主持的深入细致的技术讲座并在专家的辅导下进行上机操作、了解高级技能和获得详细指导。在甲骨文开发者大会期间,您有机会直接向业界一流的技术专家和开发人员请教。欢迎参加甲骨文全球大会·2007·亚太地区开发者大会

2007年6月29日,自由软件基金会宣布,其创始人Richard Stallman将在GNU的网站上,在本周太平洋时间星期五上午9点通过视频发布GPLv3。本来,GPL并不是所有开源组织所认可的协议。其从出现以来一直存在争议,GPL被认为是一种“病毒式”的协议,BSD的fans和老牌Unix黑客们认为,他们编写Unix的年头都比GPL声明要长得多,他们更愿意采用比GPL更加的自由的BSD协议。今天,开源社区中有70%左右的项目采用了GPL。很多在开源社区的老牌黑客们认为,Richard Stallman所鼓吹开源软件的言行与当年卡尔·马克思号召产业无产阶级反抗工作的努力如出一辙。在GPLv3的第三版修订案发布时,开源软件团体中的许多成员都反对这种协议。尤其是Linux的核心开发小组,其中29个高级架构师有28个反对这个协议。Linus Torvalds称这个协议有“宗教性质”,并公开反对。而整个软件行业特别是开源社区对GPLv3的争论也愈演愈烈。GPLv3:大教堂和集市的新一轮对抗

2007年7月14日由CSDN与ThoughtWorks联合主办的第二届“敏捷中国”技术大会在北京丽亭华苑酒店召开,多位开源社区和ThoughtWorks公司的技术领袖即将带来精彩的演讲。本次“敏捷中国”技术大会集中展现塑造敏捷企业所需的方方面面:业界领先的敏捷项目管理工具;极大提升软件开发效率的新语言和新框架;数据库领域的敏捷实践;全方位的敏捷项目管理指导;还有身临其境的亲身体验。来自开源社区和ThoughtWorks公司的技术领导者们将带领听众全面感受敏捷企业。“敏捷中国大会”现场直击

从2004年起,在每年的夏季,CSDN都会举办面向中国程序员的大型网上调查活动。这是中国样本最丰富的开发者社区调查,持续、全面和深入地反映了中国开发者社群自身状况、各项技术、工具、产品的使用状况和发展趋势,是完整、准确地了解中国开发者市场的重要参考资料。本次调查覆盖基础信息、.NET、Java、C/C++、Web开发、数据库应用开发、软件工程及项目管理、移动及嵌入式开发、开放源代码、企业信息化等10个领域。还有惊喜大奖等着你哦,赶快进入吧! 2007中国软件开发者大调查正式启动

推荐作者
  • 大宝大宝

    时间如流水,知惜方成功。

  • SkymanSkyman

    江苏人氏,梅兰芳之老乡。现游学渝州之最...

  • ralph623ralph623

新进作者
  • 冲 s冲 s

  • 小鱼小鱼

  • 棱角棱角

    多年J2EE构架设计与开发经验,专注于企业信息系统建设,精通Java设计模式,并能熟练的运用到企业开发中。 精通Struts与Spring框架。数据库方面精通Oracle数据库,从事过数据库方面的开发以及oracle优化方面的工作。

最新技术图书推荐
再战MVC(-)

发表日期:2007-9-21
更新日期:2007-9-21
作者文章阅读次数:9646

源自:gaolin_bei (个人网站) 标签:

您认为本文应该得        共有6人参与打分打印|收藏|讨论|投诉

看MVC模式所蕴含的设计模式~~

   

前言
  之所以说是再战,是因为在没有学习设计模式之前已经基于MVC体系结构做过一些项目,主要是小项目,当初理解MVC有一些困难。现在已经把Gof所说的相对简单但是最常见的这些设计模式:
  • Abstract Factory
  • Adapter
  • Composite
  • Decorator
  • Factory Method
  • Observer
  • Strategy
  • Template Method 
都详细过了一遍了,而我们都知道MVC是一种比较特殊的模式,MVC并不属于GOF的23个设计模式之列,但是Smalltalk的MVC框架结构在著名的GOF书中作为一个重要的例子被提出来,并给予了很高的评价。一般的来讲,我们认为GOF的23个模式是一些中级的模式,在它下面还可以抽象出一些更为一般的低层的模式,在其上也可以通过组合来得到一些高级的模式,即架构模式。MVC就可以看作是一些模式进行组合之后的结果(实际上,MVC的出现要早于设计模式的提出,因而只是对它在设计模式的基础上进行在分析)。所以说现在有必要站在设计模式的思想上来看MVC模式。<<Java与模式>>在MVC模式与用户输入数据检查这个专题里大量地谈到MVC模式跟设计模式的关系,本文按这个专题的思路以笔记的形式展开。
MVC模式可以分解为以下设计模式
在GOF书的Introduction中,有一小节是“Design Patterns in Smalltalk MVC”即介绍在MVC模式里用到的设计模式。它大概向我们传达了这样的信息:合成模式+策略模式+观察者模式约等于MVC模式(当然MVC模式要多一些东西)。也就是说它在大部分情况下是下面几个模式:
1 观察者模式
 类图结构在Gof里的表示如下:
 
2 合成模式
类图结构在Gof里的表示如下:
3 策略模式
 
除了这三种主要的设计模式,Gof最后也提到了MVC还使用了其它的设计模式,比如说工厂方法模式用来说明对一个view的默认的控制器,还有装饰模式用来为view增加一个滚动条等。但是在MVC模式里起主要作用的还是前面列出来的三个设计模式。
模式的分类
 书中提到由于[GOF95]是论述软件模式的著作的第一本,也是OO设计理论著作中最流行的一本,因此有些人常常使用设计模式(Design Pattern)一词来指所有直接处理软件架构,设计,程序实现的任何种类的模式。另外一种说法是强调要划分三种不同层次的模式:架构模式(Architectual Pattern),设计模式(Design Pattern),成例(Idiom)。成例有时称为代码模式(Codeing Pattern)。
架构模式(Architectual Pattern)
面向对象软件大师Martin Fowler有本书叫做<< Patterns of Enterprise Application Architecture>>中文名叫<<企业应用架构模式>>。这本书就是关于如何将企业应用分层,以及如何组织各层工作的。例如这本书在第二部分深入讲解模式时,在谈到了Web表示层的时候就分析了MVC模式,从这些我们可以知道架构模式提供一些事先定义好的子系统,指定他们的责任,并给出把它们组织在一起的法则和指南,一个架构模式常常可以分解成很多个设计模式的联合使用。
 设计模式
设计模式描述在软件设计过程中普遍存在相互通信的组件中重复出现的结构,这种结构解决在一定的背景中的具有一般性的设计问题。
 代码模式或成例(Coding PatternIdiom
 代码模式(或成例)是较低层次的模式,并与编程语言密切相关。代码模式描述怎样利用一个特定的编程语言的特点来实现一个组件的某些特定的方面或关系。
 从上面的叙述中其实我们不难从一个软件系统中找到他们,因为三种不同的模式存在于它们自的抽象层次和具体层次上,所以少了其中任何一种模式,或者有一种设计的不好,都会给整个软件系统带来害处,如可维护性低等缺点。因为架构模式是一个系统的高层次策略,涉及到大尺度的组件以及整体性质和力学,它设计的好坏可以影响到总体布局和框架性结构。设计模式是中等尺度的结构策略。这些中等尺度的结构实现了一些大尺度组件的行为和它们之间的关系,所以设计模式的好坏不会影响到系统的总休布局和总体框架,但是它会影响到系统的扩展性,维护性等方面。代码模式是特定的范例和与特定编程语言有关的编程技巧。它不会影响到一个部件或子系统的中等尺度的结构,更不会影响到系统的总体布局和大尺度框架,但是会影响到一个中等尺度组件的内部,外部的结构或行为的底层细节。
 
  MVC架构模式
MVC中的三个角色
Model(模型端)
Mod封装的是数据源和所有基于对这些数据的操作。在一个组件中,Model往往表示组件的状态和操作这些状态的方法,往往是一系列的公开方法。通过这些公开方法,便可以取得模型端的所有功能。
在这些公开方法中,有些是取值方法,让系统其他部分可以得到模型端的内部状态参数,其他的改值方法则允许外部修改模型端的内部状态。模型端还必须有方法登记视图,以便在模型端的内部状态发生变化时,可以通知视图端。我们可以自己定义一个Subject接口来提供登记和通知视图所需的接口或者继承Java.util.Observable类,让父类完成这件事。
多个View(视图端)
View封装的是对数据源Model的一种显示。一个模型可以由多个视图,并且可以在需要的时候动态地登记上所需的视图。而一个视图理论上也可以同不同的模型关联起来。
在前言里提到了,MVC模式用到了合成模式,这是因为在视图端里,视图可以嵌套,比如说在一个JFrame组件里面,可以有菜单组件,很多按钮组件等。
多个Controller(控制器端)
封装的是外界作用于模型的操作。通常,这些操作会转发到模型上,并调用模型中相应的一个或者多个方法(这个方法就是前面在介绍模型的时候说的改值方法)。一般ControllerModelView之间起到了沟通的作用,处理用户在View上的输入,并转发给Model来更改其状态值。这样ModelView两者之间可以做到松散耦合,甚至可以彼此不知道对方,而由Controller连接起这两个部分。也在前言里提到,MVC用到了策略模式,这是因为View用一个特定的Controller的实例来实现一个特定的响应策略,更换不同的Controller,可以改变View对用户输入的响应。
MVC模式用在基于C/S的应用
尽管MVC设计模式通常是用来设计整个用户界面(GUI)的,JFC的设计者们却独创性的把这种设计模式用来设计Swing中的单个的组件(Component),例如表格Jtable等。下面的讨论也就是对于Swing单个组件所体现出来的这种MVC模式来说的。
严格地讲,Swing中的MVC实际上是MVC的一个变体:M-VC。 拿JTable来说,MVC 就是 TableModel  JTable  TableUI. Swing中只显示的定义了Model接口(TableModel),而在一个UI对象中集成了视图和控制器的部分机制(JTable)。View和Control比较松散的交叉组合在一起,而更多的控制逻辑是在事件监听者部分引入的为了更好地展现Swing是一个设计优秀的Java包,充满了大师的智慧,让我们更加深入的进行分析,我将采用最常见的组件button来说明
注:以下例子是摘自网上一篇名为“通过Java Swing看透MVC设计模式”的佚名文章,感觉对从Swing库的设计来看MVC模式的应用有相当大的帮助,故插到此处同大家分享,黑色字迹部分为自己的说明。

(转载开始)

Model的设计

  一个按钮的model所应该具备的行为由一个接口ButtonModel来完成。一个按钮model实例封装了其内部的状态,并且定义了按钮的行为。它的所有方法可以分为四类:

  1、查询内部状态

  2、操作内部状态

  3、添加和删除事件监听器

  4、发生事件

  程序员通常并不会直接和model以及view/controller打交道,他们通常隐藏于那些继承自java.awt.Component的组件里面了,这些组件就像胶水一样把MVC三者合三为一。也正是由于这些继承的组件对象,一个程序员可以很方便的混合使用Swing组件和AWT组件,然后,我们知道,Swing组件有很多都是直接继承自相应的AWT组件,它能提供比AWT组件更加方便易用的功能,所以通常情况下,我们没有必要混合使用两者。

   

 

一个实例

  现在我们已经明白了Java类与MVC各个部分的对应关系,我们可以更加深入一点去分析问题了。下面将要讲述一个小型的使用MVC模式开发的例子。因为JFC十分的复杂,我只能把我的例子局限于一个用户界面组件里面(如果你猜是一个按钮的例子,那么你对了!)

  让我们来看看这个例子的所有部分吧。
  Button组件
  最显而易见的开始的地方就是代表了按钮组件本身的代码,因为这个类是大部分程序员会接触的。
  就像我前面提到的,按钮用户界面组件类实际上就是model和view/controller的之间的黏合剂。每个按钮组件都和一个model以及一个controller关联,model定义了按钮的行为,而view/controller定义了按钮的表现。而应用程序可以在任何事件改变这些关联。让我们看看得以实现此功能的代码。
注:以下代码是我从JDK1.4源代码AbstractButton类中提取出来的,因为查看Jbutton源代码(再次提供JDK1.4在线源代码地址)我们可以发现,它是继承自AbstractButton类的,所以下面的代码是来自AbstractButton的,跟原文有点不一样
1.           /**
2.            
3.                * Sets the model that this button represents.
4.            
5.                * @param m the new <code>ButtonModel</code>
6.            
7.                * @see #getModel
8.            
9.                * @beaninfo
10.        
11.            *        bound: true
12.        
13.            * description: Model that the Button uses.
14.        
15.            */
16.        
17.           public void setModel(ButtonModel newModel) {
18.        
19.               
20.        
21.               ButtonModel oldModel = getModel();
22.        
23.               
24.        
25.               if (oldModel != null) {
26.        
27.                   oldModel.removeChangeListener(changeListener);
28.        
29.                   oldModel.removeActionListener(actionListener);
30.        
31.                   changeListener = null;
32.        
33.                   actionListener = null;
34.        
35.               }
36.        
37.               
38.        
39.               model = newModel;
40.        
41.               
42.        
43.               if (newModel != null) {
44.        
45.                   changeListener = createChangeListener();
46.        
47.                   actionListener = createActionListener();
48.        
49.                   itemListener = createItemListener();
50.        
51.                   newModel.addChangeListener(changeListener);
52.                 
53.             newModel.addActionListener(actionListener);
54.             
55.             newModel.addItemListener(itemListener);
56.             
57.             mnemonic = newModel.getMnemonic();
58.        
59.               } else {
60.        
61.                   mnemonic = '\0';
62.        
63.               }
64.        
65.        
66.        
67.               updateDisplayedMnemonicIndex(getText(), mnemonic);
68.        
69.        
70.        
71.               firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel);
72.        
73.               if (newModel != oldModel) {
74.        
75.                   revalidate();
76.        
77.                   repaint();
78.        
79.               }
80.        
81.           }

 注:你可以多花一些时间按我上面提供的链接地址来仔细阅读一下Button类及其它相关类的源代码。

  ButtonModel类
  ButtonModel维护着三种类型的状态信息:是否被按下(pressed),是否“武装上了”(armed),是否被选择(selected)。它们都是boolean类型的值。
  一个按钮被按下(pressed)是指当鼠标在按钮上面的时候,按下鼠标但是还没有松开鼠标按钮的状态,即使用户此时把鼠标拖拽到按钮的外面也没有改变这种状态。
  一个按钮是否“武装了”(armed)是指按钮被按下,并且鼠标还在按钮的上面。
  一些按钮还可能被选择(selected),这种状态通过重复的点击按钮取得true或者false的值。
  注:查看ButtonModel源代码我们可以看到它是一个接口,定义了一组方法:
public interface ButtonModel extends ItemSelectable {
 boolean isArmed();
boolean isPressed();
boolean isRollover();
void addActionListener(ActionListener l);
void removeActionListener(ActionListener l);
void addItemListener(ItemListener l);
void removeChangeListener(ChangeListener l);
其实看到这里,如果你再回头看下这个例子刚开始时“Model的设计”以及前面的内容,就会明白什么是“Mod封装的是数据源和所有基于对这些数据的操作。在一个组件中,Model往往表示组件的状态和操作这些状态的方法,往往是一系列的公开方法。通过这些公开方法,便可以取得模型端的所有功能”
我们再来看看AbstractButton的源代码:
1.           public abstract class   implements ItemSelectable, SwingConstants { AbstractButton extends JComponent 
2.    protected ButtonModel model= null
3.    protected ChangeListener changeListener = null;
4.    protected ActionListener actionListener = null;
5.    protected ItemListener itemListener = null;
6.    protected transient ChangeEvent changeEvent;
7.        public boolean isSelected() {
8.     return model.isSelected();
9.    }
10.public void doClick() {
11.doClick(68);
12.    }
13.public void doClick(int pressTime) {
14. Dimension size = getSize();
15.model.setArmed(true);
16. model.setPressed(true);
17. paintImmediately(new Rectangle(0,0, size.width, size.height));
18.try {
19.Thread.currentThread().sleep(pressTime);
20. } catch(InterruptedException ie) {
21.}
22.model.setPressed(false);
23.model.setArmed(false);
24.}
25.//其它代码
26.}
 上面的代码setArmed等方法是由DefaultButtonModel定义的,它是ButtonModel接口的一个默认实现。我们如果继承了DefaultButtonModel,这样可以覆盖缺省的状态定义,实现有个性的按钮。ButtonUI类
  按钮的view/controller是负责构建表示层的。缺省情况下它仅仅是用背景色画一个矩形而已,他们的子类继承了他们并且覆盖了绘制的方法,使得按钮可以有许多不同的表现,例如MOTIF,Windows 95,Java样式等等。
 注:在javax.swing.plaf这个包里我们可以找到ButtonUI,这是一个抽象类,类内部是空的,而在javax.swing.plaf.basic这个包里我们可以找到BasicButtonUI它继承自ButtonUI,其实我们观察下包结构会发现有javax.swing.plaf.metaljavax.swing.plaf.multi,这几个就是来控制Button在不同系统间的不同的显示效果。
public void update(Button button, Graphics graphics)
{
}
public void paint(Button button, Graphics graphics)
{
 Dimension dimension = button.getSize();
 Color color = button.getBackground();
 graphics.setColor(color);
 graphics.fillRect(0, 0, dimension.width, dimension.height);
}

  ButtonUI类并不自己处理AWT事件,他们会使用一个定制的事件监听器把低级的AWT事件翻译为高级的Button模型期望的语义事件。下面就是安装/卸载事件监听器的代码。

private static ButtonUIListener buttonuilistener = null

public void uninstallUI(Button button)
{
 button.removeMouseListener(buttonuilistener);
 button.removeMouseMotionListener(buttonuilistener);
 button.removeChangeListener(buttonuilistener);
}

  View/Controller实际上就是一些方法。他们不维护任何自己的状态信息。因此,许多按钮的实例可以共享一个ButtonUI实例。ButtonUI是通过在方便的参数列表里面加上按钮的引用来区分各个不同的按钮。

  ButtonUIListener类

  ButtonUIListener类可以帮助Button类去转变鼠标或者键盘的输入为对按钮模型的操作。这个监听器类实现了:MouseListener,MouseMotionListener,ChangeListener接口,并且处理一下事件:

public void mouseDragged(MouseEvent mouseevent)
{
 Button button = (Button)mouseevent.getSource();
 ButtonModel buttonmodel = button.getModel();

 if (buttonmodel.isPressed())
 {
  if (button.getUI().contains(button, mouseevent.getPoint()))
  {
   buttonmodel.setArmed(true);
  }
  else
  {
   buttonmodel.setArmed(false);
  }
 }
}

public void mousePressed(MouseEvent mouseevent)
{
 Button button = (Button)mouseevent.getSource();
 ButtonModel buttonmodel = button.getModel();
 buttonmodel.setPressed(true);
 buttonmodel.setArmed(true);
}

public void mouseReleased(MouseEvent mouseevent)
{
 Button button = (Button)mouseevent.getSource();
 ButtonModel buttonmodel = button.getModel();
 buttonmodel.setPressed(false);
 buttonmodel.setArmed(false);
}

public void stateChanged(ChangeEvent changeevent)
{
 Button button = (Button)changeevent.getSource();
 button.repaint();
}
(转载完)
通过这些相信大家能够感受到Swing的设计是MVC的典范,这是一点都不假的。下一节将要看看在基于B/S的应用中MVC模式是如何被应用的。
 
 
 
 

 

您认为本文应该得        共有6人参与打分打印|收藏|讨论|投诉

暂无图片

评论

CSDN技术中心团队官方Blog:http://blog.csdn.net/techcenter/,反馈邮箱:techcenter at csdn.net (注意:请把 at 换成@)


网站简介广告服务网站地图帮助联系方式诚聘英才English问题报告

北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号

世纪乐知(北京)网络技术有限公司 提供技术支持

Copyright © 2000-2008, CSDN.NET, All Rights Reserved