的地方爱的规格爱你啊好文章可视编程和Beans
迄今为止,我们已看到Java对创建可重复使用的代码片工作而言是多么的有价值。"最大限度地可重复使用"的代码单元拥有类,因为它包含一个紧密结合在一起的单元特性(字段)和单元动作(方法),它们可以直接经过混合或通过继承被重复使用。
继承和多形态性是面向对象编程的精华,但在大多数情况下当我们创建一个应用程序时,我们真正最想要的恰恰是我们最需要的组件。我们希望在我们的设计中设置这些部件就像电子工程师在电路板上创造集成电路块一样(在使用Java的情况下,就是放到WEB页面上)。这似乎会成为加快这种"模块集合"编制程序方法的发展。
"可视化编程"最早的成功--非常的成功--要归功于微软公司的Visual Basic(VB,可视化Basic语言),接下来的第二代是Borland公司Delphi(一种客户/服务器数据库应用程序开发工具,也是Java Beans设计的主要灵感)。这些编程工具的组件的像征就是可视化,这是不容置疑的,因为它们通常展示一些类型的可视化组件,例如:一个按惯或一个TextField。事实上,可视化通常表现为组件可以非常精确地访问运行中程序。因此可视化编程方法的一部分包含从一个调盘从拖放一个组件并将它放置到我们的窗体中。应用程序创建工具像我们所做的一样编写程序代码,该代码将导致正在运行的程序中的组件被创建。
简单地拖放组件到一个窗体中通常不足以构成一个完整的程序。一般情况下,我们需要改变组件的特性,例如组件的彩,组件的文字,组件连结的数据库,等等。特性可以参照属性在编程时进行修改。我们可以在应用程序构建工具中巧妙处置我们组件的属性,并且当我们创建程序时,构建数据被保存下来,所以当该程序被启动时,数据能被重新恢复。
到如今,我们可能习惯于使用对象的多个特性,这也是一个动作集合。在设计时,可视化组件的动作可由事件部分地代表,意味着"任何事件都可以发生在组件上"。通常,由我们决定想发生的事件,当一个事件发生时,对所发生的事件连接代码。
这是关键性的部分:应用程序构建工具可以动态地询问组件(利用映象)以发现组件支持的事件和属件。一旦它知道它们的状态,应用程序构建工具就可以显示组件的属性并允许我们修改它们的属性(当我们构建程序时,保存它们的状态),并且也显示这些事件。一般而言,我们做一些事件像双击一个事件以及应用程序构建工具创建一个代码并连接到事件上。当事件发生时,我们不得不编写执行代码。应用程序构建工具累计为我
们做了大量的工作。结果我们可以注意到程序看起来像它所假定的那样运行,并且依赖应用程序构建工具去为我们管理连接的详细资料。可视化的编程工具如此成功的原因是它们明显加快构建的应用程序的处理过程--当然,用户接口作为应用程序的一部分同样的好。
什么是Bean
在经细节处理后,一个组件在类中被独特的具体化,真正地成为一块代码。关键的争议在于应用程序构建工具发现组件的属性和事件能力。为了创建一个VB组件,程序开发者不得不编写正确的同时也是复杂烦琐的代码片,接下来由某些协议去展现它们的事件和属性。Delphi是第二代的可视化编程工具并且这种开发语言主动地围绕可视化编程来设计因此它更容易去创建一个可视化组件。但是,Java带来了可视化的创作组件做为Java Beans最高级的"装备",因为一个Bean就是一个类。我们不必再为制造任何的Bean而编写一些特殊的代码或者使用特殊的编程语言。事实上,我们唯一需要做的是略微地修改我们对我们方法命名的办法。方法名通知应用程序构建工具是否是一个属性,一个事件或是一个普通的方法。
在Java的文件中,命名规则被错误地曲解为"设计范式"。这十分的不幸,因为设计范式惹来不少的麻烦。命名规则不是设计范式,它是相当的简单:
(1) 因为属性被命名为xxx,我们代表性的创建两个方法:getXxx()和setXxx()。注意get或set后的第一个字母小写以产生属性名。"get"和"set"方法产生同样类型的自变量。"set"和"get"的属性名和类型名之间没有关系。
(2) 对于布尔逻辑型属性,我们可以使用上面的"get"和"set"方法,但我们也可以用"is"代替" get"。
(3) Bean的普通方法不适合上面的命名规则,但它们是公用的。
4.对于事件,我们使用"listener(接收器)"方法。这种方法完全同我们看到过的方法相同:(addFooBarListener(FooBarListener)和removeFooBarListener(FooBarListener)方法用来处理FooBar事件。大多数时候内建的事件和接收器会满足我们的需要,但我们可以创建自己的事件和接收器接口。
上面的第一点回答了一个关于我们可能注意到的从Java 1.0到Java 1.1的改变的问题:一些方法的名字太过于短小,显然改写名字毫无意义。现在我们可以看到为了制造Bean中的特殊的组件,大多数的这些修改不得不适合于"get"和"set"命名规则。
首先,我们可看到Bean就是一个类。通常,所有我们的字段会被作为专用,并且可以接近的唯一办法是通过方法。紧接着的是命名规则,属性是jump,color,jumper,spots(注意这些修改是在第一个字母在属性名的情况下进行的)。虽然内部确定的名字同最早的三个例子的属
性名一样,在jumper中我们可以看到属性名不会强迫我们使用任何特殊的内部可变的名字(或者,真的拥有一些内部的可变的属性名)。
Bean事件的句柄是ActionEvent和KeyEvent,这是根据有关接收器的"add"和"remove"命名方法得出的。
最后我们可以注意到普通的方法croak()一直是Bean的一部分,仅仅是因为它是一个公共的方法,而不是因为它符合一些命名规则。
用Introspector提取BeanInfo
当我们拖放一个Bean的调板并将它放入到窗体中时,一个Bean的最关键的部分的规则发生了。应用程序构建工具必须可以创建Bean(如果它是默认的构建器的话,它就可以做)然后,在此范围外访问Bean的源代码,提取所有的必要的信息以创立属性表和事件处理器。
Java 1.1版的映象允许一个匿名类的所有方法被发现。这完美地解决了Bean的难题而无需我们使用一些特殊的语言关键字像在其它的可视化编程语言中所需要的那样。事实上,一个主要的原因是映象增加到Java 1.1版中以支持Beans(尽管映象同样支持对象串联和远程方法调用)。因为我们可能希望应用程序构建工具的开发者将不得不映象每个Bean并且通过它们的方法搜索以到Bean的属性和事件。
这当然是可能的,但是Java的研制者们希望为每个使用它的用户提供一个标准的接口,而不仅仅是使Bean更为简单易用,不过他们也同样提供了一个创建更复杂的Bean的标准方法。这个接口就是Introspector类,在这个类中最重要的方法静态的getBeanInfo()。我们通过一个类处理这个方法并且getBeanInfo()方法全面地对类进行查询,返回一个我们可以进行详细研究以发现其属性、方法和事件的BeanInfo对象。
BeanDumper.dump()是一个可以做任何工作的方法。首先它试图创建一个BeanInfo对象,如果成功地调用BeanInfo的方法,就产生关于属性、方法和事件的信息。在BeanInfo()中,我们会注意到有一个另外的自变量。由它来通知Introspector访问继承体系的地点。在这种情况下,它在分析所有对象方法前停下,因为我们对看到那些并不感兴趣。
因为属性,getPropertyDescriptors()返回一组的属性描述符号。对于每个描述符号我们可以调用getPropertyType()方法彻底的通过属性方法发现类的对象。这时,我们可以用getName()方法得到每个属性的假名(从方法名中提取),getname()方法用getReadMethod()和getWriteMethod()完成读和写的操作。最后的两个方法返回一个可以真正地用来调用在对象上调用相应的方法方法对象(这是映象的一部分)。对于公共方法(包括属性方法),getMethodDescriptors( )返回一组方法描述字符。每一个我们都可以得到相当的方法对
象并可以显示出它们的名字。
对于事件而言,getEventSetDescriptors()返回一组事件描述字符。它们中的每一个都可以被查询以出接收器的类,接收器类的方法以及增加和删除接收器的方法。BeanDumper程序打印出所有的这些信息。
java开发可视化界面如果我们调用BeanDumper在Frog类中,就像这样:
java BeanDumper frogbean.Frog
通用方法列表包含了不相关的事件或者属性,例如croak()。列表中所有的方法都是我们可以有计划的为Bean调用,并且应用程序构建工具可以选择列出所有的方法,当我们调用方法时,减轻我们的任务。
最后,我们可以看到事件在接收器中完全地分析研究它的方法、增加和减少接收器的方法。基本上,一旦我们拥有BeanInfo,我们就可以出对Bean来说任何重要的事物。我们同样可以为Bean调用方法,即使我们除了对象外没有任何其它的信息(此外,这也是映象的特点)。
当我们按下鼠标键时,文字被安入BangBean中间,并且如果动作接收器字段存在,它的actionPerformed()方法就被调用,创建一个新的ActionEvent对象在处理过程中。无论何时鼠标移动,它的新座标将被捕捉,并且画布会被重画(像我们所看到的抹去一些画布上的文字)。
main()方法增加了允许我们从命令行中测试程序的功能。当一个Bean在一个开发环境中,main()方法不会被使用,但拥有它是绝对有益的,因为它提供了快捷的测试能力。无论何时一个ActionEvent发生,main()方法都将创建了一个帧并安置了一个BangBean在它里面,还在BangBean中附上了一个简单的动作接收器以打印到控制台。当然,一般来说应用程序构建工具将创建大多数的Bean的代码。当我们通过BeanDumper或者安放BangBean到一个可激活Bean的开发环境中去运行BangBean时,我们
会注意到会有很多额外的属性和动作明显超过了上面的代码。那是因为BangBean从画布中继承,并且画布就是一个Bean,因此我们看到它的属性和事件同样的合适。
Bean的封装
在我们可以安放一个Bean到一个可激活Bean的可视化构建工具中前,它必须被放入到标准的Bean容器里,也就是包含Bean类和一个表示"这是一个Bean"的清单文件的JAR(Java ARchive,Java文件)文件中。清单文件是一个简单的紧随事件结构的文本文件。对于BangBean而言,清单文件就像下面这样:
Manifest-Version: 1.0
Name: bangbean/BangBean.class
Java-Bean: True
其中,第一行指出清单文件结构的版本,这是SUN公司在很久以前公布的版本。第二行(空行忽略)对文件命名为BangBean.class。第三行表示"这个文件是一个Bean"。没有第三行,程序构建工具不会将类作为一个Bean来认可。
唯一难以处理的部分是我们必须肯
定"Name:"字段中的路径是正确的。如果我们回顾BangBean.java,我们会看到它在package bangbean(因为存放类路径的子目录称为"bangbean")中,并且这个名字在清单文件中必须包括封装的信息。另外,我们必须安放清单文件在我们封装路径的根目录上,在这个例子中意味着安放文件在bangbean子目录中。这之后,我们必须从同一目录中调用Jar来作为清单文件,如下所示:
jar cfm BangBean.jar BangBean.mf bangbean
这个例子假定我们想产生一个名为BangBean.jar的文件并且我们将清单放到一个称为BangBean.mf文件中。
我们可能会想"当我编译BangBean.java时,产生的其它类会怎么样呢?"哦,它们会在bangbean子目录中被中止,并且我们会注意到上面jar命令行的最后一个自变量就是bangbean子目录。当我们给jar子目录名时,它封装整个的子目录到jar文件中(在这个例子中,包括BangBean.java的源代码文件--对于我们自己的Bean我们可能不会去选择包含源代码文件。)另外,如果我们改变主意,解开打包的JAR文件,我们会发现我们清单文件并不在里面,但jar创建了它自己的清单文件(部分根据我们的文件),称为MAINFEST.MF并且安放它到META-INF子目录中(代表"meta-information")。如果我们打开这个清单文件,我们同样会注意到jar为每个文件加入数字签名信息,其结构如下:
Digest-Algorithms: SHA MD5
SHA-Digest: pDpEAG9NaeCx8aFtqPI4udSX/O0=
MD5-Digest: O4NcS1hE3Smnzlp2hj6qeg==
一般来说,我们不必担心这些,如果我们要做一些修改,可以修改我们的原始的清单文件并且重新调用jar以为我们的Bean创建了一个新的JAR文件。我们同样也可以简单地通过增加其它的Bean的信息到我们清单文件来增加它们到JAR文件中。
值得注意的是我们或许需要安放每个Bean到它自己的子目录中,因为当我们创建一个JAR文件时,分配JAR应用目录名并且JAR放置子目录中的任何文件到JAR文件中。我们可以看到Frog和BangBean都在它们自己的子目录中。
一旦我们将我们的Bean正确地放入一个JAR文件中,我们就可以携带它到一个可以激活Bean的编程环境中使用。使用这种方法,我们可以从一种工具到另一种工具间交替变换,但SUN公司为Java Beans提供了免费高效的测试工具在它们的"Bean Development Kit,Bean开发工具"(BDK)称为"beanbox"。(我们可以从www.javasoft处下载。)在我们启动beanbox前,放置我们的Bean到beanbox中,复制JAR文件到BDK的"jars"子目录中。
更复杂的Bean支持
我们可以看到创建一个Bean显然多么的简单。在程序设计中我们几乎不受到任何的限制。Java Bean的设计提供了一个简单的输入点,这样可以提高到更复杂的层次上。这些高层次的问
题超出了这所要讨论的范围,但它们会在此做简要的介绍。我们可以在java.sun/beans上到更多的详细资料。
我们增加更加复杂的程序和它的属性到一个位置。上面的例子显示一个独特的属性,当然它也可能代表一个数组的属性。这称为索引属性。我们简单地提供一个相应的方法(再者有一个方法名的命名规则)并且Introspector认可索引属性,因此我们的应用程序构建工具相应的处理。
属性可以被捆绑,这意味着它们将通过PropertyChangeEvent通知其它的对象。其它的对象可以随后根据对Bean的改变选择修改它们自己。
属性可以被束缚,这意味着其它的对象可以在一个属性的改变不能被接受时,拒绝它。其它的对象利用一个PropertyChangeEvent来通知,并且它们产生一个ProptertyVetoException去阻止修改的发生,并恢复为原来的值。
我们同样能够改变我们的Bean在设计时的被描绘成的方法:
(1) 我们可以为我们特殊的Bean提供一个定制的属性表。这个普通的属性表将被所有的Bean所使用,
但当我们的Bean被选择时,它会自动地调用这张属性表。
(2) 我们可以为一个特殊的属性创建一个定制的编辑器,因此普通的属性表被使用,但当我们指定的属性被调用时,编辑器会自动地被调用。
(3)我们可以为我们的Bean提供一个定制的BeanInfo类,产生的信息不同于由Introspector默认产生的。
(4) 它同样可能在所有的FeatureDescriptors中改变"expert"的开关模式,以辨别基本特征和更复杂的特征。
Bean更多的知识
另外有关的争议是Bean不能被编址。无论何时我们创建一个Bean,都希望它会在一个多线程的环境中运行。这意味着我们必须理解线程的出口。我们会发现有一段称为"Java Beans的回顾"的节会注意到这个问题和它的解决方案。
Swing入门(注释⑦)。
⑦:写作本节时,Swing库显然已被Sun"固定"下来了,所以只要你下载并安装了Swing库,就应该能
正确地编译和运行这里的代码,不会出现任何问题(应该能编译Sun配套提供的演示程序,以检测安装是否正确)。若遇到任何麻烦,请访问www.BruceEckel,了解最近的更新情况。
而这就是Swing将要占领的领域。Swing库在Java 1.1之后面世,因此我们可以自然而然地假设它是Java 1.2的一部分。可是,它是设计为作为一个补充在Java 1.1版中工作的。这样,我们就不必为了享用好的UI组件库而等待我们的平台去支持Java 1.2版了。如果Swing库不是我们的用户的Java 1.1版所支持的一部分,并且产生一些意外,那他就可能真正的需要去下载Swing库了。
Swing包含所有我们缺乏的组件,在余下的部分中:我们期望领会现代化的UI,来自

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。