通过重用已经测试并验证通过的代码,怎样才减少开发工作,所有开发团队都在为一问题而努力。一个久经考验的方法是通过有效地使用Java继承优化应用程序开发。
继承的从某种意义上讲,继承的短暂美就如同宇宙中所有事与其它事情都存在一种特殊的关系。教育者试图向门外汉们解释继承的概念,常常通过讨论相关动物群之间的关系来解释这一概念。例如,牧羊犬、吉娃娃、杜宾犬都是狗的品种。在Java和NET中,在某种程度上讲,所有事物都是对象类型的一种软件组件。然而,从那里开始,开发选择什么在子类和超类继承中进行关联是设计的重点。
使用Java进行桌面渲染中的问题是,过多的思想投入到把在一起的可视化项目进行分组。从亲子关系来看,所有地的知名的图形元素如JDialog和JFrame,虽然知名的方法不同,但都与一般的Window类有着极大的关系。所有我们选择的、继承于Window类的,与JDialog属性有关的东西,都与上一级的JFrame有关,因为他们有共同的父Window类。的确,编写可重用的代码来管理许多相关的子对象是优秀设计的标志。正如上文说的狗和窗户一样,伟大的多态设计都是关于抽象、分类、设计、和继承的。
Shareanote和Jackhammer的演变
我兼职做技术培训,实际上就是软件开发人员,享受着与他人分享我的知识的技术的机会。作为一个培训人员,我常常希望我有一个抽认卡工具提供给我的学生。除了拥有一系列国内学者,近期需要较多的是审查测试并分享笔记,以启发我编写一个抽认卡共享和管理项目。有趣的是,在编写同样的程序时,我还发现我无意中创造了一个相对不错的笔记录和文件共享程序。所以,虽然本质上是一个应用程序,发展成两个或三个不同的产品,出现了三个独立的产品,每个产品都有一个不同的名称、不同的版本号,对话框视图了有所不同,问题域控件也会有不同的GUI名称。例如,虽然在Shareanote应用中有“Create Note”标签按钮,这一相同的GUI元素在Jackhammer或能称为“Create Flash Cardin”。为了最小化编码工作,同时重用已开发的软件,该解决方案只给原始抽认卡软件提供一个字符串,为记录产品提供另一个字符串。
public enum Skinner {
ShareNote, // Note Taker Names & Features
Jackhammer; // Flash Card Names & Features
}
对于那些对现代化GUI设计工作有着实际经验的开发人员来说,只是改变产品的名称和版本将会过度浪费资源包,这是众所周知的。然而,有谁想编写所有代码,来更新每个JFrame或JDialog而且的控件?虽然颜色是高级父类功能,但在GUI亲子问题域中,文本设置却较低。
作为开发人员,我们想要更聪明地工作,而不是更辛苦。递归也是一个不错的选择,来管理产品名称、版本信息和其他的标记,不是吗?
public void skin(Window win) {
if (win == null) {
return;
}
Component[] parent = win.getComponents();
for (Component comp : parent) {
skin(comp);
}
}
就像闪电一样串接两次,分层递归技术效果很好,需要共享。这是实用的递归技术:
public enum Skinner {
ShareNote(Notebook, Note, Free, Shareanote, 1.0),
Jackhammer(Deck, Card, Free, Jackhammer, 1.0);
private String nameFile;
private String nameRecord;
private String nameEdition;
private String nameProduct;
private String version;
public static final String TOKEN_FILE = %file;
public static final String TOKEN_RECORD = %record;
public static final String TOKEN_PRODUCT = %product;
public static final String TOKEN_VERSION = %version;
public static final String TOKEN_EDITION = %edition;
private TitledBorder tborder;
Skinner(String nameFile, String nameRecord, String nameEdition, String nameProduct, String versionProduct) {
this.nameFile = nameFile;
this.nameRecord = nameRecord;
this.nameEdition = nameEdition;
this.nameProduct = nameProduct;
this.version = versionProduct;
}
public void skin(Frame win) {
if (win == null) {
return;
}
win.setTitle(skin(win.getTitle()));
skin((Window) win);
JDialog dlg = null;
}
public void skin(Dialog win) {
if (win == null) {
return;
}
win.setTitle(skin(win.getTitle()));
skin((Window) win);
}
public void skin(Window win) {
if (win == null) {
return;
}
Component[] parent = win.getComponents();
for (Component comp : parent) {
skin(comp);
}
}
public void skin(Component comp) {
if (comp == null) {
return;
}
if (comp instanceof AbstractButton) {
AbstractButton jcomp =(AbstractButton) comp;
jcomp.setText(skin(jcomp.getText()));
}
if (comp instanceof JMenuItem) {
JMenuItem ref = (JMenuItem)comp;
MenuElement[] ele = ref.getSubElements();
for(MenuElement eref : ele){
skin(eref.getComponent());
}
}
if (comp instanceof JComponent) {
JComponent jcomp = (JComponent)comp;
Border border =jcomp.getBorder();
if (border != null) {
if(border instanceof TitledBorder) {
tborder= (TitledBorder) border;
tborder.setTitle(skin(tborder.getTitle()));
}
}
Component[] set =jcomp.getComponents();
for (Component ref : set) {
skin(ref);
}
}
}
public String skin(String subject) {
if (subject == null) {
return ;
}
String result = com.soft9000.Text.ReplaceAll(subject,TOKEN_FILE, this.getNameFile());
result = com.soft9000.Text.ReplaceAll(result,TOKEN_RECORD, this.getNameRecord());
result = com.soft9000.Text.ReplaceAll(result,TOKEN_PRODUCT, this.getNameProduct());
result = com.soft9000.Text.ReplaceAll(result,TOKEN_VERSION, this.getVersion());
result = com.soft9000.Text.ReplaceAll(result,TOKEN_EDITION, this.getNameEdition());
return result;
}
/* Setters and getters removed */
}
递归的力量
回顾上面的代码,首先我们使用的是一个枚举,而不是一个类。而类和枚举的区别可能乍一看微不足道,但注意每一个枚举值是枚举结构本身的一个实例。每一个枚举实例之间的唯一不同是,自引用包含一个独特标记名称,以及顺序。
还要注意,我们使用的是全局常量如TOKEN_FILE(%file)和TOKEN_RECORD(%record),而不是任何枚举值。这些标记正是Skinner在GUI中所找寻的。
以上,正如它们的实体名所描述的,Skinner的任务是递归搜索所有我们已经嵌入这些常量的地方。对于Window、Frame和Dialog继承树之类的,一旦有一个标记被找到,它们将会被任何一个product-skin值的代替。
一旦第一个测试案例已经运行,那么判断也就开始了。在所有实例化的对象中使用Skinner,从AbstractButton到TitledBorder,我们很快就会有一个TOKEN标记的产品代码库。
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
GuiMainmain = new GuiMain(Skinner.ShareNote);
main.setVisible(true);
}
});
}
更好的是,要切换皮肤,所有要做的就是复制上面的一个主要方法到另一个项目,包括以前项目的JAR文件,然后把Skinner.ShareNote改成Skinner.Jackhammer。一旦进入程序,这些skin()操作就会重载,而且能过上述提供的枚举实例本身可以轻松地访问。
结束语
虽然大部分条目已经准备好转变成大父类,如Window、Component或JComponent,但基于接口的组件可以使用映射来参与任何skin ()重载的操作。基于接口和继承的范例意味着有些接口,如上面的代码中的MenuElement,它们必须有自己的getComponent()排列。随时定位,并随着需要的变化将它们添加到你的ownSkinners中。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
内存数据网格提供商一头扎进Java
10年的时间里,应用性能解决方案提供商Alachisoft一直在用NCache(针对N-Tier和网格计算.NET应用的内存计算和数据网格产品)为.NET社区服务。
-
遇到这样一个问题:通过java service wrapper部署应用,wrapper进程占用的内存会一直升高, 直到把内存吃完应用崩溃,但是这个wrapper
遇到这样一个问题:通过java service wrapper部署应用,wrapper进程占用的内存会一直升高 […]
-
Google App Engine for Java 对于目前中国需要学习吗?
-
前无古人后无来者的Java平台
开发人员一直在致力于保持Java的活力,经过20年后,我们感觉从来没有更好的、更令人激动的时刻如同Java社区一样。