本文选自NetBeans Platform 6.9 Developer's Guide第一章节内容
Product Version: Apache NetBeans IDE 11.3
第一章:Modules(模块)
在本章中,您将涵盖以下主题:
您将了解模块和模块化应用程序开发
您在创建第一个模块时检查模块在NetBeans Platform应用程序中扮演的角色
您将了解如何配置模块,尤其是如何定义模块依赖性和版本控制数据
您可以通过查看模块的生命周期以及如何以编程方式访问该生命周期来结束本主题。
1、创建一个应用程序
1.1、右键New Project,Java with Ant | Netbeans Modules | NetBeans Platform Application (或者在Filter中搜索NetBeans Platform Application),点击next。
1.2、输入TaskManager作为应用程序的名称,点击Finish
1.3、在Projects窗口中,右键单击应用程序的Modules节点,然后选择Add New,输入HelloService作为模块的名称。
1.4、点击next,输入模块的Code Name Base的值为com.netbeansrcp.helloservice
Code Name Base:自动创建package
Module Display Name是一个字符串,它定义了唯一的ID,应用程序其余部分通过该ID可以查找该模块
1.5、点击完成,模块源结构显示在Projects窗口中,双击HelloService
右键点击模块的包,New | Java class,创建一个名为HelloService的class
并在class添加方法,右键Format是代码格式化
public void hello(String name) {
System.out.println("Hello " + name + "!");
}
2、设置依赖关系
现在,如果希望能够使用来自另一个模块。
2.1、以前面说明相同的方式,创建第二个模块,命名为HelloClient,并向其添加名为HelloClient的类。添加以下方法
public static void main(String[] args) {
new HelloService().hello("NetBeans");
}
由于当前无法找到HelloService类,因此无法编译新类。 无法添加import语句,因为包含所需类的模块通过其特定于模块的类加载器与所有其他模块隔离。 因此,要使HelloClient模块中的类使用HelloService模块中的类,必须首先满足两个条件:
- HelloService类必须属于定义该模块的模块的公开接口
- HelloClient模块必须声明其对HelloService模块的依赖关系
2.2、首先,需要对HelloService类添加到模块的公开接口。右键点击HelloService模块属性,在API Versioning标签中,你会看到软件包列表,在这里,可以指定公开接口。
勾选它,点击OK。
您要公开的包是com.netbeansrcp.helloservice。除已公开的包以外的其他任何包中的类型,其他模块均无法访问。
2.3、现在,声明HelloClient对HelloService的依赖性。右键点击HelloClient模块的Properties,在Libraries选项卡中,添加依赖关系(Add Dependency),输入访问类的名称Hello
选择该模块,点击OK,关闭窗口。右键点击Fix import引入类。现在应该可以编译该类了。
3、版本控制
除了定义模块之间的依赖关系的信息外,您还需要确切指定所依赖的模块版本。 NetBeans平台在规范版本和模块实现版本之间进行了区分,如下所示:
- 规范版本使用杜威符号设置。 通常,它由主要版本号(即添加新功能时递增的版本号),次要版本号和补丁程序级别组成。
- 实现版本指示具体的开发状态,仅应在与模块所有者达成协议后使用。
例如,我们需要将HelloService模块设置为版本2.1.5
3.1、接下来,让我们配置HelloClient,使其要求将HelloService设置为版本2.1.5。 用鼠标右键单击HelloClient模块,然后单击Properties,在Libraries选项卡中,选择HelloService依赖项,然后单击Edit, 输入specification version 为2.1.5,点OK。
右键build项目时,应该看到一条消息,构建失败,版本大于2.1.5
Cannot compile against a module: C:\Users\HIGHGO\Documents\NetBeansProjects\TaskManager\TaskManager\build\cluster\modules\com-netbeansrcp-helloservice.jar because of dependency: com.netbeansrcp.helloservice > 2.1.5 found 1.0
BUILD FAILED (total time: 0 seconds)
3.2、为了是build成功,需要声明HelloService模块的specification version至2.1.5,在HelloService | Properyies | API Versioning | specification version至2.1.5,点击OK ,build HelloService,然后再build HelloClient构建成功,完成了版本对应。
应用案列
在接下来的章节中,您将逐步开发完整的应用程序。
示例应用程序是TaskManager,即用于管理各种活动的工具。出于本应用程序的目的,任务是一项活动,每个任务都需要简短说明和冗长说明,以向用户提供有关该活动的信息。每个任务还具有优先级,使用户可以按LOW, MEDIUM, HIGH类别对任务进行排序。每个任务都有截止日期,并且需要通过唯一的ID号进行识别。
在TaskManager应用程序中,创建一个名为TaskModel的模块。 使用com.netbeansrcp.taskmodel作为主程序包的名称。
创建一个名为api的子package,并定义Task界面
package com.netbeansrcp.taskmodel.api;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
public interface Task extends Serializable {
public java.lang.String getId();
public java.lang.String getParentId();
public java.lang.String getName();
public void setName(java.lang.String name);
public java.util.Date getDue();
public void setDue(java.util.Date due);
public enum Priority {
LOW, MEDIUM, HIGH
}
public Priority getPrio();
public void setPrio(Priority prio);
public int getProgr();
public void setProgr(int progr);
public java.lang.String getDescr();
public void setDescr(java.lang.String descr);
public void addChild(Task subTask);
public java.util.List<Task> getChildren();
public boolean remove(Task subTask);
public void addPropertyChangeListener(PropertyChangeListener listener);
public void removePropertyChangeListener(PropertyChangeListener listener);
public static final String PROP_NAME = "name";
public static final String PROP_DUE = "due";
public static final String PROP_PRIO = "prio";
public static final String PROP_PROGR = "progr";
public static final String PROP_DESCR = "descr";
public static final String PROP_CHILDREN_ADD = "children_add";
public static final String PROP_CHILDREN_REMOVE = "children_remove";
}
现在您已经有了一个接口,您需要实现它。 在实现中,您需要考虑为PropertyChangeListener类提供支持。
这样,您最终将获得以下实现,该实现是在com.netbeansrcp.taskmodel包中创建的:
package com.netbeansrcp.taskmodel;
import com.netbeansrcp.taskmodel.api.Task;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
public class TaskImpl implements Task {
private String id = "";
private String name = "";
private String parentId = "";
private Date due = new Date();
private Priority prio = Priority.MEDIUM;
private int progr = 0;
private String descr = "";
private List<Task> children = new ArrayList<Task>();
private PropertyChangeSupport pss;
public TaskImpl() {
this("", "");
}
public TaskImpl(String name, String parentId) {
this.id = "" + System.currentTimeMillis();
this.name = name;
this.parentId = parentId;
this.due = new Date();
this.prio = Priority.MEDIUM;
this.progr = 0;
this.descr = "";
this.children = new ArrayList<Task>();
this.pss = new PropertyChangeSupport(this);
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
String old = this.name;
this.name = name;
this.pss.firePropertyChange(PROP_NAME, old, name);
}
public String getParentId() {
return parentId;
}
public Date getDue() {
return due;
}
public void setDue(Date due) {
Date old = this.due;
this.due = due;
this.pss.firePropertyChange(PROP_DUE, old, due);
}
public Priority getPrio() {
return prio;
}
public void setPrio(Priority prio) {
Priority old = this.prio;
this.prio = prio;
this.pss.firePropertyChange(PROP_PRIO, old, prio);
}
public int getProgr() {
return progr;
}
public void setProgr(int progr) {
int old = this.progr;
this.progr = progr;
this.pss.firePropertyChange(PROP_PROGR, old, progr);
}
public String getDescr() {
return descr;
}
public void setDescr(String descr) {
String old = this.descr;
this.descr = descr;
this.pss.firePropertyChange(PROP_DESCR, old, descr);
}
public List<Task> getChildren() {
return Collections.unmodifiableList(this.children);
}
public void addChild(Task subTask) {
this.children.add(subTask);
this.pss.firePropertyChange(PROP_CHILDREN_ADD, null, this.children);
}
public boolean remove(Task subTask) {
boolean res = this.children.remove(subTask);
this.pss.firePropertyChange(PROP_CHILDREN_REMOVE, null, this.children);
return res;
}
public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
this.pss.addPropertyChangeListener(listener);
}
public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
this.pss.removePropertyChangeListener(listener);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TaskImpl other = (TaskImpl) obj;
return this.id.equals(other.getId());
}
@Override
public int hashCode() {
int hash = 7;
hash = 97 * hash + (this.id != null ? this.id.hashCode() : 0);
return hash;
}
@Override
public String toString() {
return this.getId() + " - " + this.parentId + " - " + this.getName() + " - " + DateFormat.getInstance().format(this.due) + " - " + this.prio + " - " + this.progr + " - " + this.descr;
}
}
摘要
尽管您还没有可以运行的代码,但是您现在有了一个Task接口及其实现。 您已经完成了应用程序的模型。
以后,您需要使这些类可用于应用程序中的其他模块。 您可以为此做好准备,方法是将API包暴露给应用程序的其余部分,如本章前面所述,它将“Task”接口添加到模块的公共接口。
在下一章中,您将继续学习NetBeans平台和示例应用程序的开发。