J2EE之巔

           

          DSL的實現要點(1)

           

          引言

          DSL(domain-specific language)并不是什么新的概念和技術,但是目前它已成為了一個技術熱點,近期各種類型的技術交流或研討會上你都可以看到關于DSL的主題。DSL似乎也在一夜間成為了大師們關注的焦點(Martin FowlerEric Evans等等)。

          應用DSL可以有效的提高系統的可維護性(縮小了實現模型和領域模型的距離,提高了實現的可讀性)和靈活性,并且提供開發的效率。

          那么如何在我們的實踐中引入DSL呢,Martin FowlerDSL實現模式做了全面的闡釋;在實際工作中作者實踐了部分Martin Fowler的模式,下文是作者對這些實踐的經驗總結,愿與大家分享。

          根據實現方式的分類DSL可以大致分為內部DSLInternal DSL)和外部DSL(Extern DSL), 作者在實際項目中實踐了這兩大類DSL,在系列文章中將分別共享各類型DSL的實現經驗。

          示例涉及的模型

          為了便于說明問題,系列文章講圍繞一個簡單得示例展開,將以不同方式實現一個關于狀態機描述的DSL


          Figure 1狀態機


          Figure 2 領域模型

          實現DSL的本質任務


          無論是實現內部DSL或是外部DSL,要完成的本質任務就是將DSL API調用及DSL語言腳本解析為應用中的語義模型(通常為應用中領域模型的部分)。

          實現DSL

          實現內部DSL

          內部DSL實際上就是一組精心設計的API,同時這種API及其對他的調用有著某些特定領域中自然語言的特性。

          以下分享兩種內部DSL實現方法的實現經驗。

          實現要點

          不要將這種DSL API直接放置在領域模型中,這不符合關注點分離的思想,并且導致代碼難以維護,應該引入一個新的層次——Builder層,由Builder層來解析調用并創建為系統中的語義模型對象。

          幾種模式的實現要點

          方法鏈(Method Chain

          調用示例

          publicclass Client {

                publicstaticvoid main(String [] args){

                      Process p=new Process();

                      ProcessBuilder process=new ProcessBuilder(p);

                      process.name("Auto-Door")

                      .state("Open")

                            .transition()

                                  .event("timeout")

                                  .nextState("close")                

                      .state("Close")

                            .transition()

                                  .event("people-closer")

                                  .nextState("open");

                      System.out.println(p);

                }

          }

          實現

          ProcessBuilder.java:

          publicclass ProcessBuilder {

                protected Process process;

                public ProcessBuilder(Process process2){

                      this.process=process2;

                }

                public ProcessBuilder name(String name){

                      process.setName(name);

                      returnthis;

                }

                public StateBuilder state(String name){              

                      State newState=new State();  

                      StateBuilder sb= new StateBuilder(process,newState);

                      sb.name(name);

                      process.getStates().add(newState);

                      return sb;

                }    

          }

          StateBuilder.java:

          public class StateBuilder extends ProcessBuilder{

                protected State state=new State(); 

                public StateBuilder(Process p,State state){

                      super(p);        

                      this.state=state;

                     

                }

                public StateBuilder name(String name){

                       state.setName(name);

                       returnthis;

                }

                public TransitionBuilder transition(){

                      Transition t=new Transition();

                      TransitionBuilder tb= new TransitionBuilder(process,state,t);           

                      state.getTransitions().add(t);           

                      return tb;

                }    

          }

          TransitionBuilder.java

          publicclass TransitionBuilder extends StateBuilder {

                private Transition transition;

                public TransitionBuilder(Process process,State state,Transition transition){

                      super(process,state);

                      this.transition=transition;

                     

                }

                public TransitionBuilder event(String event){

                      transition.setEvent(new Event(event));

                      returnthis;

                }

                public TransitionBuilder nextState(String state){

                      returnthis;

                     

                }

               

          }

          實現要點

          1 返回值

          每個方法的返回都是Builder,這是為了可以實現這種鏈式調用。

          2 繼承

          可以發現下一層次的Builder仍需可以提供上面層次Builder中的方法,我們把方法鏈拉直你便一目了然了。

                       

          由此可見為了避免代碼重復,可以采用繼承機制,讓下層的Builder繼承自上層的Builder

          3 上下文變量(context variable

          從代碼中我們可以發現這些變量(各個Builder中的成員變量,process,state,tranistion,他們用來保證我們的Builder是在正確的上下文上工作,如把生成的transition加入到正確的state中。

          這些上文變量在不同Builder將是通過構造函數進行傳遞的。

          嵌套方法(Nested function)

          調用示例

          publicstaticvoid main(String[] args) {

                      Process p=process("Auto-Door", new State []{

                            state("Open",new Transition[]{

                                  transition(

                                        event("timeour"),

                                        nextState("Close")

                                  )    

                                 

                            }),

                            state("Close",new Transition[]{

                                  transition(

                                        event("people-closer "),

                                        nextState("Open")

                                  )    

                                 

                            })

                           

                      });  

          }

          實現

          Builder.java

          publicclass Builder { 

                publicstatic Process process(String name, State [] states){

                      Process process=new Process();

                      process.setName(name);

                      List<State> sts=new ArrayList<State>();

                      for (State s:states){

                            sts.add(s);

                      }

                      process.setStates(sts);

                      return process;

                }

                publicstatic State state(String name,Transition [] transitions){

                      State state=new State();

                      state.setName(name);

                      List<Transition> ts=new ArrayList<Transition>();

                      for (Transition t: transitions){

                            ts.add(t);

                      }

                      state.setTransitions(ts);

                      return state;

                }

                publicstatic Transition transition(Event event,String nextState){

                      Transition t=new Transition ();

                      t.setEvent(event);           

                      return t;

                }

                publicstatic Event event(String event){

                      returnnew Event(event);

                }

                publicstatic String nextState(String nextState){

                      return nextState;

                }

          }

          實現要點

          由源碼可以看出嵌套方法的實現比方法鏈要簡單得多。

          1 方法及返回值

          由于無需維護對象狀態,所以方法均為靜態,返回值則直接是方法所要創建的模型對象。

          2 方法及方法的參數來表明語義

          通過Builder中的方法來定義語法中的詞匯,方法的參數表明層次與包含的語義關系。

          3 無需上下文變量

          由于嵌套方法實現DSL巧妙的利用了系統中的方法調用棧,所以無需采用上下文變量來進行上下文的維護。



          蔡超
          HP 軟件架構師
          軟件架構顧問
          SCEA
          IBM Certified Solution Designer for OOA&D vUML2
          Chaocai2001@yahoo.com.cn

          posted on 2009-08-24 15:45 超越巔峰 閱讀(2083) 評論(2)  編輯  收藏 所屬分類: DSL

          評論

          # re: DSL的實現要點(1) 2009-08-24 17:10 99書城

          不錯啊!  回復  更多評論   

          # re: DSL的實現要點(1) 2009-08-24 22:53 vg

          camel  回復  更多評論   


          只有注冊用戶登錄后才能發表評論。


          網站導航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           

          導航

          統計

          常用鏈接

          留言簿(12)

          隨筆分類(54)

          隨筆檔案(59)

          文章分類(2)

          文章檔案(1)

          相冊

          搜索

          積分與排名

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 周口市| 息烽县| 囊谦县| 公安县| 乌拉特中旗| 丘北县| 博野县| 紫金县| 灌南县| 新津县| 宁蒗| 永城市| 镇安县| 阿拉善右旗| 金溪县| 鹤山市| 格尔木市| 白朗县| 游戏| 乐都县| 墨江| 钟山县| 宁乡县| 龙岩市| 克东县| 麦盖提县| 江源县| 临潭县| 广水市| 宁城县| 安顺市| 黄骅市| 台前县| 保亭| 思南县| 乳源| 霍邱县| 中牟县| 白水县| 莫力| 容城县|