Interpret Pattern
最近工作上又跟.NET 暫時分離了, 回到Java世界的第一個工作,
就是寫一個小小的Rule enginne 來做Data Transfer,
Rule 本身其實就像一個小小的compiler,
所以我選用Interpret Pattern 來實做這個需求.
因為很懶, 沒有將它轉成 C# , 有空再補...
需求動機:資料物件化後,希望能夠透過一個簡單的字串取得值。
設計文法:xxx::xxx::xxx
資料結構 : DataBlock contains a Head line and lot of Text lines. DataLine contains lot of DataField. DataField had a name and value.
物件導向 : Every DataXXX implements the Data. Data is a object wrapper.
-----------------------
Pattern 不詳述,請參考:Gossip@caterpillar dofactory oodesign
Context 即 rule string. 處理文法(詞, 字). Java是用StringTokenizer來實作, .NET 可用String.split() 即可
StringTokenizer st ;
final static String CTX_TOKEN = "::";
String currentToken;
Context(String context) {
st = new StringTokenizer(context,CTX_TOKEN);
}
String nextToken(){
currentToken = st.nextToken();
return currentToken;
}
String currentToken(){
return currentToken;
}
void skipToken(String token) {
if (!token.equals(currentToken)) {
System.err.println("Warning: " + token +
" is expected, but " +
currentToken + " is found.");
}
nextToken();
}
int countTokens(){
return st.countTokens();
}
}
DataExpression 處理文法之邏輯運算(取值)
abstract public Data interpret(Context context);
}
SelectorExpression 實作 DataExpression (單一詞)
因為第一個建立的Expression需要有Data物件當作Source, 之後Expression則只要把上層Expression拿來用即可{ interpret() 會回傳Data物件供操作 }, 故會有2個建構子
this.source = source;
}
public SelectorExpression(DataExpression exp){
this.exp = exp;
}
因Data本身有實作取值, 所以Expression的實作內容很簡單, 首先將Source處理好, 然後再由Source去取值即可 { object.get(name) }.
public Data interpret(Context context) {
Data object = null;
if(exp==null){
object = source;
}else{
object = exp.interpret(context);
}
String name = context.nextToken();
return object.get(name);
}
Data 實作的get碼, 是用影射的方式做.
String methodName = "get" + name.substring(0,1).toUpperCase() + name.substring(1);
try {
return (Data) this.getClass().getMethod(methodName,null).invoke(this, null);
} catch (Exception e) {
throw new InterpreterException(e);
}
}
另外要注意DataLine有重新定義get方法, 因為它的欄位數是不固定的
for(Iterator<DataField> i = fieldList.iterator();i.hasNext();){
DataField field = i.next();
if(field.getName().equals(name)){
return field;
}
}
throw new InterpreterException("No such name attribute : " + name);
}
RepeatSelectorExpression 實作 DataExpression (多個詞)
public Data interpret(Context context) {
SelectorExpression exp = null;
for(int i=0;i<context.countTokens();i++){
if(i==0)
exp = new SelectorExpression(source);
else
exp = new SelectorExpression(exp);
}
return exp.interpret(context);
}
完成囉~~~
Java Sample Code 裡InterpreterUT.java 是單位測試的類別, 亦可以看出怎麼使用此套件.
Context context = new Context("current::unit::value");
block.first();
RepeatSelectorExpression expression = new RepeatSelectorExpression(block);
this.assertEquals((expression.interpret(context).getString()),"$1,024");
}