由于脚本语言通常提供了更为简洁的语法及Java所不具有的一些新的语言特性(如:闭包,元编程等),所以在一些情况下可以创造出比Java程序更具有可读性的代码。另外,众多基于JVM的脚本语言也为与Java程序整合带来了便利。
![](/images/blogjava_net/chaocai/dsl3.jpg)
Client: 语义模型实例的调用者
SemanticConcept: 语义模型定义,可以通过脚本语言或Java实现
ModelBuilder: 语义模型实例创建者,使用语义模型定义创建特定语义模型实例
相关基本概念可以参考:
DSL的实现要点(1)
以下还是以自动门状态机来作为实例:
语义概念定义:
Process.java
package org.ccsoft.statemachine;
import java.util.List;
publicclass Process {
private String name;
private List<State> states;
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public List<State> getStates() {
returnstates;
}
publicvoid setStates(List<State> states) {
this.states = states;
}
private State getStateByName(String name){
for (State state:states){
if (state.getName().equals(name)){
return state;
}
}
returnnull;
}
public State transit(String curState,String event){
for (State state:states){
if (state.getName().equals(curState)){
String nextS=state.getTransitions().get(event);
return getStateByName(nextS);
}
}
returnnull;
}
}
State.java
package org.ccsoft.statemachine;
import java.util.Map;
publicclass State {
private String name;
/**Map<state,event>**/
private Map<State,String> transitions;
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
public Map<State, String> getTransitions() {
returntransitions;
}
publicvoid setTransitions(Map<State, String> transitions) {
this.transitions = transitions;
}
@Override
publicboolean equals(Object obj) {
if (obj instanceof State){
State other=(State)obj;
if (other.getName().equals(this.name)){
returntrue;
}
}
returnfalse;
}
@Override
publicint hashCode() {
// TODO Auto-generated method stub
returnname.hashCode();
}
@Override
public String toString() {
// TODO Auto-generated method stub
returnname;
}
}
语义模型实例创建者
IStateMachineBuilder.java
package org.ccsoft.statemachine;
publicinterface IStateMachineBuilder {
public Process build(String processName);
}
package org.ccsoft.statemachine
publicclass StateMachineBuilder implements IStateMachineBuilder{
public Process build(String processName){
switch(processName){
case"service":
Process process =
new Process(
states:[
new State(
name:"open",
transitions:
[
"timeOut":"close",
"peopleClose":"close"
]
),
new State(
name:"close",
transitions:
[
"peopleOpen":"close"
]
)
]
);
return process;
default:
returnnull;
}
}
}
作者采用的是Groovy,可见语言特性(集合及对象创建)有效提高了代码的可读性。
连接脚本语言与Java
作者采用Spring来实现Java及脚本语言的连接,你可以采用其他方式(如:JDK6的Script Engine)。
Spring配置文件(stateMachine.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd">
<lang:groovy id="stateMachineBuilder" script-source="file:src/org/ccsoft/statemachine/StateMachineBuilder.groovy">
</lang:groovy>
</beans>
Java调用程序
package org.ccsoft.statemachine;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
publicclass Main {
/**
*@paramargs
*/
publicstaticvoid main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("stateMachine.xml");
IStateMachineBuilder builder=(IStateMachineBuilder) ctx.getBean("stateMachineBuilder");
Process process=builder.build("service");
State nextState = process.transit("open", "timeOut");
System.out.println(nextState);
}
}
由于脚本语言是解释执行的,所以可以用作配置文件一样,在部署后进行修改。同时脚本语言本身所具有的强大语法可以使其很容易地完成普通配置很难完成的功能。所以在很多时候我们都应该考虑使用脚本语言来进行配置。