Interpret Pattern

Interpret Pattern

Java Sample Code

 

最近工作上又跟.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

interpret 隨手畫的Class diagram

 

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");
	}