国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

基于Java的界面布局DSL的設(shè)計(jì)與實(shí)現(xiàn)

2019-11-17 05:54:15
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
  java界面設(shè)計(jì)應(yīng)該是一項(xiàng)布滿創(chuàng)造性、富有樂(lè)趣的工作,但是卻往往被認(rèn)為非常的枯燥和繁瑣。究其原因,是因?yàn)榻缑娌季诸I(lǐng)域所采用的描述概念和具體的實(shí)現(xiàn)語(yǔ)言之間存在很大的語(yǔ)義隔閡。而一般的界面開(kāi)發(fā)工具提供的所見(jiàn)即所得以及界面布局治理器等方案也無(wú)法很好地解決這個(gè)問(wèn)題。

  在本文中,我們會(huì)給出一種更好的解決方案,我們不是去試圖把界面設(shè)計(jì)者頭腦中的設(shè)計(jì)概念和樣式逐步降級(jí)、分解成所使用的實(shí)現(xiàn)語(yǔ)言能夠理解的低層概念,也不是提供一些已經(jīng)完成的、確定的但難以擴(kuò)充和更改的布局樣式庫(kù)供界面設(shè)計(jì)者使用。我們所提供的是一種專門用于描述高層界面設(shè)計(jì)樣式的語(yǔ)言。通過(guò)這種語(yǔ)言,界面設(shè)計(jì)者可以直接、明確地描述出他們頭腦中的布局設(shè)計(jì)樣式;通過(guò)這種語(yǔ)言,界面設(shè)計(jì)者可以自己方便地、靈活地制定自己需要的布局樣式。此外,本文中給出的設(shè)計(jì)思想對(duì)于其他領(lǐng)域的設(shè)計(jì)也有很好的借鑒作用。

  創(chuàng)造性,還是乏味?

  界面設(shè)計(jì)是一項(xiàng)非常有創(chuàng)造性,甚至富有藝術(shù)性的工作,一個(gè)簡(jiǎn)潔、易用、漂亮的界面在帶給使用者方便的同時(shí),也會(huì)給界面設(shè)計(jì)者帶來(lái)極大的成就感。但是,在現(xiàn)實(shí)中,情況似乎并非如此,很多人都認(rèn)為做界面是一項(xiàng)非常繁瑣、機(jī)械、乏味的工作,并千方百計(jì)地去逃避界面相關(guān)的工作。這是為什么呢?

  原因很簡(jiǎn)單,因?yàn)樽鼋缑嫫鋵?shí)涉及兩項(xiàng)工作,一項(xiàng)是界面的一些設(shè)計(jì)創(chuàng)意,包括界面的布局樣式以及和使用者的交互方式,這項(xiàng)工作布滿挑戰(zhàn)和樂(lè)趣。但是,這些設(shè)計(jì)創(chuàng)意最終是要落實(shí)到實(shí)現(xiàn)上的,這就是第二項(xiàng)工作。此時(shí),你頭腦中那些清楚、完整的設(shè)計(jì)概念開(kāi)始變得瑣碎,你不得不和那些低層次的坐標(biāo)位置打交道。更糟糕的是,當(dāng)你好不輕易做好了一個(gè)界面,但是發(fā)現(xiàn)其中某些元素的布局需要一些調(diào)整時(shí),這個(gè)你本應(yīng)認(rèn)為是一個(gè)很簡(jiǎn)單的改變卻造成大量重復(fù)的低層次坐標(biāo)位置更改時(shí),你肯定會(huì)認(rèn)為做界面是多么的機(jī)械和乏味呀!

  其實(shí),造成這種熟悉的根源在于界面設(shè)計(jì)創(chuàng)意和實(shí)現(xiàn)這些創(chuàng)意概念的語(yǔ)言之間存在很大的斷層。這樣,在具體實(shí)現(xiàn)時(shí),你就必須得把這些清楚、完整的布局樣式降級(jí)成一些瑣碎、沒(méi)有什么意義的低層次的坐標(biāo)值,使得實(shí)現(xiàn)語(yǔ)言能夠理解。這項(xiàng)工作不僅乏味,而且最終的實(shí)現(xiàn)也非常的脆弱 —— 一個(gè)在布局樣式層面非常簡(jiǎn)單的更改,就會(huì)造成實(shí)現(xiàn)層面的巨大變動(dòng)。比如:我們可以說(shuō)把一組元素同時(shí)按比例縮小 10%,做過(guò)界面的朋友肯定知道這個(gè)更改意味著什么。

  為了應(yīng)對(duì)這個(gè)斷層的問(wèn)題,目前幾乎所有的涉及界面制作的開(kāi)發(fā)工具都提供了相同的解決方法:可視化的界面設(shè)計(jì)工具以及布局治理器。但是這兩種方法都沒(méi)有從根本上解決這個(gè)問(wèn)題。

  可視化界面設(shè)計(jì)工具確實(shí)避免了不少繁瑣的界面元素?cái)[放工作,但是對(duì)于專業(yè)的界面設(shè)計(jì)來(lái)說(shuō),通過(guò)拖放設(shè)計(jì)出來(lái)的界面在準(zhǔn)確度和規(guī)范性上都有待提高,此外還有更為重要的一點(diǎn),那就是存在于設(shè)計(jì)者頭腦中的布局樣式仍然沒(méi)有被明確地描述出來(lái),而是被降級(jí)成一個(gè)個(gè)擺放在一起的零散的組件,雖然這些組件本身是可視的。這個(gè)語(yǔ)義斷層的存在同樣會(huì)使得通過(guò)可視化界面設(shè)計(jì)工具設(shè)計(jì)出來(lái)的界面非常脆弱。

  布局治理器試圖通過(guò)提供一些常用的布局樣式來(lái)解決這個(gè)問(wèn)題。但是,這種做法非常僵化,也就是說(shuō)你只能使用現(xiàn)有的布局治理器,假如它們無(wú)法滿足你的要求,你也無(wú)法自己定制。此外,這些布局治理器僅僅適合于一些簡(jiǎn)單的情況。對(duì)于一些復(fù)雜的布局樣式來(lái)說(shuō),它們的描述能力就顯得非常的不足。那些曾經(jīng)和 GridBagLayOut 斗爭(zhēng)過(guò)的朋友對(duì)此肯定深有體會(huì)。

  在本文中,我們會(huì)給出一種更好的解決方案,我們不是去試圖把界面設(shè)計(jì)者頭腦中的設(shè)計(jì)概念和樣式逐步降級(jí)、分解成所使用的實(shí)現(xiàn)語(yǔ)言能夠理解的低層概念,也不是提供一些已經(jīng)完成的、確定的但難以擴(kuò)充和更改的布局樣式庫(kù)供界面設(shè)計(jì)者使用。我們所提供的是一種專門用于描述高層界面設(shè)計(jì)樣式的語(yǔ)言。通過(guò)這種語(yǔ)言,界面設(shè)計(jì)者可以直接、明確地描述出他們頭腦中的布局設(shè)計(jì)樣式,通過(guò)這種語(yǔ)言,界面設(shè)計(jì)者可以自己方便地、靈活地制定自己需要的布局樣式。也就是說(shuō),本來(lái)僅存在于界面設(shè)計(jì)者頭腦中的抽象布局樣式,現(xiàn)在也變得可描述,可編程了。

  界面布局語(yǔ)言介紹

  在學(xué)習(xí)界面布局語(yǔ)言的設(shè)計(jì)之前,先來(lái)了解一下該語(yǔ)言的使用是非常有幫助的。我們的界面布局語(yǔ)言非常簡(jiǎn)單,簡(jiǎn)單到只有一種原子:Component。Component 是一種基本的布局元素,可以對(duì) Component 進(jìn)行平移和伸縮,使其和給定的一個(gè)布局空間 Rectangle 匹配。比如對(duì)于 Button 這個(gè) Component 來(lái)講,它具有傳統(tǒng)按鈕的外觀,但是它在布局上所占的實(shí)際空間則是由為其指定的 Rectangle 決定的。此外,Component 要最終在界面上顯示出來(lái),就必須有一個(gè)物理上的 Container。也就是說(shuō),界面設(shè)計(jì)應(yīng)該是一項(xiàng)布滿創(chuàng)造性、富有樂(lè)趣的工作,但是卻往往被認(rèn)為非常的枯燥和繁瑣。究其原因,是因?yàn)榻缑娌季诸I(lǐng)域所采用的描述概念和具體的實(shí)現(xiàn)語(yǔ)言之間存在很大的語(yǔ)義隔閡。而一般的界面開(kāi)發(fā)工具提供的所見(jiàn)即所得以及界面布局治理器等方案也無(wú)法很好地解決這個(gè)問(wèn)題。

  在本文中,我們會(huì)給出一種更好的解決方案,我們不是去試圖把界面設(shè)計(jì)者頭腦中的設(shè)計(jì)概念和樣式逐步降級(jí)、分解成所使用的實(shí)現(xiàn)語(yǔ)言能夠理解的低層概念,也不是提供一些已經(jīng)完成的、確定的但難以擴(kuò)充和更改的布局樣式庫(kù)供界面設(shè)計(jì)者使用。我們所提供的是一種專門用于描述高層界面設(shè)計(jì)樣式的語(yǔ)言。通過(guò)這種語(yǔ)言,界面設(shè)計(jì)者可以直接、明確地描述出他們頭腦中的布局設(shè)計(jì)樣式;通過(guò)這種語(yǔ)言,界面設(shè)計(jì)者可以自己方便地、靈活地制定自己需要的布局樣式。此外,本文中給出的設(shè)計(jì)思想對(duì)于其他領(lǐng)域的設(shè)計(jì)也有很好的借鑒作用。

  創(chuàng)造性,還是乏味?

  界面設(shè)計(jì)是一項(xiàng)非常有創(chuàng)造性,甚至富有藝術(shù)性的工作,一個(gè)簡(jiǎn)潔、易用、漂亮的界面在帶給使用者方便的同時(shí),也會(huì)給界面設(shè)計(jì)者帶來(lái)極大的成就感。但是,在現(xiàn)實(shí)中,情況似乎并非如此,很多人都認(rèn)為做界面是一項(xiàng)非常繁瑣、機(jī)械、乏味的工作,并千方百計(jì)地去逃避界面相關(guān)的工作。這是為什么呢?

  原因很簡(jiǎn)單,因?yàn)樽鼋缑嫫鋵?shí)涉及兩項(xiàng)工作,一項(xiàng)是界面的一些設(shè)計(jì)創(chuàng)意,包括界面的布局樣式以及和使用者的交互方式,這項(xiàng)工作布滿挑戰(zhàn)和樂(lè)趣。但是,這些設(shè)計(jì)創(chuàng)意最終是要落實(shí)到實(shí)現(xiàn)上的,這就是第二項(xiàng)工作。此時(shí),你頭腦中那些清楚、完整的設(shè)計(jì)概念開(kāi)始變得瑣碎,你不得不和那些低層次的坐標(biāo)位置打交道。更糟糕的是,當(dāng)你好不輕易做好了一個(gè)界面,但是發(fā)現(xiàn)其中某些元素的布局需要一些調(diào)整時(shí),這個(gè)你本應(yīng)認(rèn)為是一個(gè)很簡(jiǎn)單的改變卻造成大量重復(fù)的低層次坐標(biāo)位置更改時(shí),你肯定會(huì)認(rèn)為做界面是多么的機(jī)械和乏味呀!


  其實(shí),造成這種熟悉的根源在于界面設(shè)計(jì)創(chuàng)意和實(shí)現(xiàn)這些創(chuàng)意概念的語(yǔ)言之間存在很大的斷層。這樣,在具體實(shí)現(xiàn)時(shí),你就必須得把這些清楚、完整的布局樣式降級(jí)成一些瑣碎、沒(méi)有什么意義的低層次的坐標(biāo)值,使得實(shí)現(xiàn)語(yǔ)言能夠理解。這項(xiàng)工作不僅乏味,而且最終的實(shí)現(xiàn)也非常的脆弱 —— 一個(gè)在布局樣式層面非常簡(jiǎn)單的更改,就會(huì)造成實(shí)現(xiàn)層面的巨大變動(dòng)。比如:我們可以說(shuō)把一組元素同時(shí)按比例縮小 10%,做過(guò)界面的朋友肯定知道這個(gè)更改意味著什么。

  為了應(yīng)對(duì)這個(gè)斷層的問(wèn)題,目前幾乎所有的涉及界面制作的開(kāi)發(fā)工具都提供了相同的解決方法:可視化的界面設(shè)計(jì)工具以及布局治理器。但是這兩種方法都沒(méi)有從根本上解決這個(gè)問(wèn)題。

  可視化界面設(shè)計(jì)工具確實(shí)避免了不少繁瑣的界面元素?cái)[放工作,但是對(duì)于專業(yè)的界面設(shè)計(jì)來(lái)說(shuō),通過(guò)拖放設(shè)計(jì)出來(lái)的界面在準(zhǔn)確度和規(guī)范性上都有待提高,此外還有更為重要的一點(diǎn),那就是存在于設(shè)計(jì)者頭腦中的布局樣式仍然沒(méi)有被明確地描述出來(lái),而是被降級(jí)成一個(gè)個(gè)擺放在一起的零散的組件,雖然這些組件本身是可視的。這個(gè)語(yǔ)義斷層的存在同樣會(huì)使得通過(guò)可視化界面設(shè)計(jì)工具設(shè)計(jì)出來(lái)的界面非常脆弱。

  布局治理器試圖通過(guò)提供一些常用的布局樣式來(lái)解決這個(gè)問(wèn)題。但是,這種做法非常僵化,也就是說(shuō)你只能使用現(xiàn)有的布局治理器,假如它們無(wú)法滿足你的要求,你也無(wú)法自己定制。此外,這些布局治理器僅僅適合于一些簡(jiǎn)單的情況。對(duì)于一些復(fù)雜的布局只要給定了一個(gè) Rectangle 和一個(gè) Container,一個(gè) Component 就可以在界面上指定的布局位置呈現(xiàn)出來(lái)。

  例如,當(dāng)我們使用布局語(yǔ)言在一個(gè) JFrame 上坐標(biāo)位置為 (0,0) 展示一個(gè) width 為 200,height 為 60 的按鈕時(shí),我們可以這樣來(lái)描述(為了簡(jiǎn)潔起見(jiàn),后面的代碼實(shí)例中均略去 Layout 名字空間前綴):

Button().title(“button1”).at(0,0,200,60).in(this.getContentPane());
  僅僅提供這樣一種原子元素的語(yǔ)言顯然無(wú)法滿足我們前面提到的目標(biāo)。在我們的界面布局語(yǔ)言中,還提供了兩種在布局中非經(jīng)常用的兩種從已有組件構(gòu)造新組件的組合手段:above 和 beside。其中 above 組合子接收 3 個(gè)參數(shù):兩個(gè)現(xiàn)有 Component 以及一個(gè)比例,它會(huì)產(chǎn)生出一個(gè)新的復(fù)合 Component,其中按照給定的比例把第一個(gè) Component 擺放在第二個(gè) Component 之上。Beside 組合子接收同樣的 3 個(gè)參數(shù),并且也產(chǎn)生出一個(gè)新的復(fù)合 Component,其中按照給定的比例把第一個(gè) Component 擺放在第二個(gè)Component左邊。

  例如,假如我們希望在一個(gè)給定的 Container C 上的 Rectangle(0,0,300,40) 中,平行擺放一個(gè) TextField 和一個(gè) Button,且希望 TextField 占據(jù) 80% 的比例時(shí),可以這樣來(lái)描述:

beside(TextField(), Button().title(“ok”), 0.8).at(0,0,300,40).in(C)
  同樣,我們可以使用 above 來(lái)進(jìn)行如下描述:

above(TextField(), Button().title(“ok”), 0.5).at(0,0,300,60).in(C)
  值得注重的是,在我們的界面布局語(yǔ)言中,Component 在 beside 和 above 操作下是封閉的,也就是說(shuō) beside 和 above 操作的結(jié)果同樣也是 Component,并完全可以作為基本的 Component 來(lái)再次進(jìn)行 beside 和 above 組合。這樣我們就可以使用這兩個(gè)簡(jiǎn)單的操作生成更加復(fù)雜的 Component 來(lái),從而完成復(fù)雜的界面布局。比如,我們可以這樣來(lái)進(jìn)行描述:

Component L = beside(TextField (), Button().title(“…”), 0.8);
above(L, Button().title(“ok”), 0.5). at(0,0,300,60).in(C)
  為了保證界面布局語(yǔ)言的完備性,我們?cè)黾恿艘环N非凡的原子元素:Empty。它的作用只是占據(jù)一定的布局空間。比如,假如我們希望在一個(gè)布局空間中右半邊放置一個(gè) Button,左半邊空置,就可以這些描述:

beside(Empty(), Button(), 0.5).at(0,0,200,40).in(C)
  讀者在后面可以看到,正是這個(gè) Empty 以及 beside 和 above 操作的閉包性質(zhì)為我們描述任意復(fù)雜的布局樣式提供了可能。

  在有了這些基礎(chǔ)的布局元素和組合手段后,我們就可以通過(guò)組合手段來(lái)把一些典型的布局樣式抽象出來(lái)。在下一小節(jié)中讀者將會(huì)看到,布局語(yǔ)言中的 beside 和 above 組合操作其實(shí)就是 Java 中的普通方法,因此我們的布局語(yǔ)言中不需要什么非凡的抽象手段。也就是說(shuō),我們可以直接使用 Java 中已有的抽象手段。

  例如,假如我們希望抽象出這樣一種布局樣式,其中給定一個(gè)布局空間和一個(gè)布局組件,我們期望該組件能夠按照指定的縱、橫留白比例位于該布局空間的中心地帶。我們可以把該布局樣式抽象出來(lái),并命名它為 center。并可以在更復(fù)雜的布局樣式中把 center 當(dāng)作一個(gè)基本語(yǔ)素使用。center 的實(shí)現(xiàn)如下:

public Component center(Component cp, float hRatio, float vRatio) {
float s1 = (1-2.0* hRatio)/ (1.0 - hRatio);
float s2 = (1-2.0*vRatio)/ (1.0-vRatio);
Component u = above(Empty(), above(cp, Empty(), s2), vRatio);
return beside(Empty(), beside(u,Empty(), s1), hRatio);
}
  當(dāng)我們想把一個(gè)按鈕放置按照在橫向 0.2,縱向 0.1 的留白比例放在布局空間 (0,0,100,30) 中時(shí),我們可以簡(jiǎn)單的進(jìn)行如下描述:

center(Button().title(“I am at center.”), 0.1,0.1).at(0,0,300,60).in(C)
  我們還可以構(gòu)建出 h_seq 和 v_seq 這樣的布局樣式,它們分別為把一組給定的布局元素橫向順序排列和縱向順序排列,其實(shí)現(xiàn)如下:


public Component h_seq(Component[] cps) {
int len = cps.length;
if(len == 1) return cps[0];
return beside(cps[0], h_seq(slice(cps, 1, len)), 1.0/len);
}

public Component v_seq(Component[] cps) {
int len = cps.length;
if(len == 1) return cps[0];
return above(cps[0], v_seq(slice(cps, 1, len)), 1.0/len);
}
  其中 slice 方法有 3 個(gè)參數(shù),一個(gè)為布局元素?cái)?shù)組,另外兩個(gè)為區(qū)間的起止位置,該方法把給定布局元素?cái)?shù)組中指定起止位置的區(qū)間部分作為一個(gè)新的布局元素?cái)?shù)組返回。這兩個(gè)方法的實(shí)現(xiàn)都比較簡(jiǎn)單直接。下面是兩個(gè)應(yīng)用例子:

Component[] cps = new Component[]
{ Button().title(“1”), Button().title(“2”), Button().title(“3”) };
h_seq(cps).at(0,0,300,60).in(C)
v_seq(cps).at(0,0,150,200).in(C)
  在 center、h_seq、v_seq 這些布局樣式的基礎(chǔ)上,我們可以定義出更加高階的樣式來(lái),比如,給定一布局元素序列,我們希望它們?cè)诮o定的布局空間中按照 N 行、M 列排列。我們稱之為 block,其實(shí)現(xiàn)如下:

public Component block (Component[] cps, int N, int M) {
Component[][] fcps = formalize(cps, N, M);
Component[] rows = new Component[fcps.length];
for(int i = 0; i < fcps.length; i++) {
rows[i] = h_seq(fcps[i]);
}
return v_seq(rows);
}
  其中 formalize 是一個(gè)工具方法,它把一個(gè)給定的布局元素?cái)?shù)組規(guī)范化為 N 行 M 列的形式,假如不足則用 Empty 組件補(bǔ)齊。

  假如希望在 block 中,每個(gè)元素都可以指定一些橫向和縱向的留白,則可以定義一個(gè) block_with_margin 布局樣式,其實(shí)現(xiàn)如下:

public Component block_with_margin(Component[] cps, int N, int M,
float hRatio, float vRatio) {
Component[] ncps = new Component[cps.length];
for(int i=0; i<cps.length; i++) {
ncps[i] = center(cps[i], hRatio, vRatio);
}
return block(ncps, N, M);
}
  好了,現(xiàn)在我們來(lái)看一個(gè)稍微復(fù)雜一些的例子,我們將使用前面制作的一些布局樣式構(gòu)建一個(gè)迷你計(jì)算器的外觀,如下圖所示:

  對(duì)應(yīng)的描述代碼如下:

Component[] cs = new Component[]{
Button().title("0"),
Button().title("1"),
Button().title("2"),
Button().title("+"),
Button().title("3"),
Button().title("4"),
Button().title("5"),
Button().title("-"),
Button().title("6"),
Button().title("7"),
Button().title("8"),
Button().title("*"),
Button().title("9"),
Button().title("="),
Button().title("%"),
Button().title("/")
};
Component opLayout = block(cs,4,4);
above( above( TextField(),
beside( Button().title("Backspace"), Button().title("C"),0.5), 0.5),
block(cs,4,4), 0.3).at(0,0,300,200).in(C);
  假如我們現(xiàn)在希望將所有數(shù)字以及操作按鈕按照橫向和縱向各 2% 進(jìn)行留白,我們所要做的僅僅是一行的改動(dòng),就是把:

Component opLayout = block(cs,4,4);
  更改為:

Component opLayout = block_with_margin(cs, 4, 4, 0.02, 0.02);


  這意味著什么呢?這意味著我們可以直接使用布局語(yǔ)言進(jìn)行界面制作,我們可以直接針對(duì)布局進(jìn)行編程,我們所寫出來(lái)的界面代碼就是我們的布局規(guī)格說(shuō)明。

  從上面的介紹中,讀者可以看出,我們的界面布局語(yǔ)言可以非常方便地定義出一些常見(jiàn)的布局樣式,還可以把這些樣式組合成更為復(fù)雜的一些高階布局樣式,并且這種組合是沒(méi)有任何限制的。此外,這些布局樣式的定義描述方式是和界面設(shè)計(jì)者頭腦中所使用的一些布局詞匯和規(guī)則貼近的。通過(guò)使用界面布局語(yǔ)言,界面設(shè)計(jì)者完全可以擺脫那些呆板、機(jī)械又難以定制和擴(kuò)展的布局治理器,可以輕松地把頭腦中的布局創(chuàng)意直接描述出來(lái),逐步形成自己的布局樣式庫(kù),充分享受這種創(chuàng)造性的工作所帶來(lái)的樂(lè)趣。

  界面布局語(yǔ)言設(shè)計(jì)與實(shí)現(xiàn)

  在本小節(jié)中,我們會(huì)對(duì)上面介紹的界面布局語(yǔ)言的一些設(shè)計(jì)和實(shí)現(xiàn)細(xì)節(jié)進(jìn)行介紹。我們這里所講解的是基于 Java Swing 的實(shí)現(xiàn)。讀者可以根據(jù)自己的需要在其他的語(yǔ)言和界面開(kāi)發(fā)工具包上去實(shí)現(xiàn)該界面布局語(yǔ)言。

  界面布局語(yǔ)言的主要設(shè)計(jì)思路有兩點(diǎn):

   在接口中遵循《Domain Driven Desing》作者 Eric Evans 提出的 FluentInterface 的概念;

   語(yǔ)言的層次化設(shè)計(jì)。

  界面布局語(yǔ)言所提供的接口不是 Java 語(yǔ)言層面上的對(duì)象接口,也不是使用基于 Java 的語(yǔ)法來(lái)使用這些接口構(gòu)建復(fù)雜的界面。相反,我們提供了一個(gè)面向界面設(shè)計(jì)規(guī)格描述的接口,接口的語(yǔ)義、規(guī)則以及命名完全和界面設(shè)計(jì)中的規(guī)則、概念相符,這樣就可以直接使用代碼來(lái)清楚、直接地表達(dá)出界面設(shè)計(jì)中的布局概念。

  在界面布局語(yǔ)言的設(shè)計(jì)上,我們沒(méi)有采用定制的面向?qū)ο蟮脑O(shè)計(jì),而是由一組處于不同層次的語(yǔ)言組成,每個(gè)層次都是通過(guò)對(duì)該層的基本原子進(jìn)行組合構(gòu)造而來(lái),每個(gè)層次所構(gòu)造出來(lái)的實(shí)體,則可以作為上一層語(yǔ)言的基本原子使用。這樣,我們就在通用的 Java 語(yǔ)言之上,逐步構(gòu)建出了一種專用于表達(dá)界面布局的語(yǔ)言。比起傳統(tǒng)的對(duì)象設(shè)計(jì),這種方法具有更高的抽象層次和通用性。

  我們來(lái)看一下界面布局語(yǔ)言中基本原子的實(shí)現(xiàn)細(xì)節(jié),先來(lái)看一下 Component 的定義:

public interface Component {
public Component at(int x, int y, int width, int height);
public Component in(Container);
……
}
  Button 的實(shí)現(xiàn)如下:

public class Button implements Component{
public JButton BTn = new JButton();
public Component title(String t){
btn.setText(t);
return this;
}
public Component at(int x, int y, int width, int height) {
Rectangle rect = new Rectangle(x,y,width,height);
btn.setBounds(rect);
return this;
}
public Component in(Container parent){
parent.add(btn);
return this;
}
……
}
  從上面的代碼中,讀者會(huì)發(fā)現(xiàn)這種寫法和傳統(tǒng)的 API 寫法風(fēng)格的不同。在這種風(fēng)格中,為了能夠?qū)⒄{(diào)用形成一個(gè)句子,每個(gè)調(diào)用在結(jié)束時(shí)都返回了 this。另外,在給方法起名時(shí)也有不同的考慮,不只是關(guān)注于該方法的職責(zé)和功能,而是更關(guān)注于該方法名在整個(gè)句子這個(gè)上下文中是否通順、是否更富表達(dá)力。

  隨著更多基本原子組件的編寫,會(huì)發(fā)現(xiàn) in 和 at 方法在很多組件中都重復(fù)出現(xiàn),此時(shí)可以把它們提取到一個(gè)抽象基類中。這里這樣寫是為了清楚起見(jiàn)。

  下面我們來(lái)看看 Empty 組件,beside 和 above 組合子的實(shí)現(xiàn)方法,它們都很簡(jiǎn)單。

public class Empty implements Component {
public Component at(int x,int y,int width,int height) {
return this;
}
public Component in(Container {
return this;
}
}
  Empty 只是起到了一個(gè)布局空間占位的作用。beside 和 above 的實(shí)現(xiàn)如下:

public class beside implements Component {
PRivate Component left,right;
private float ratio;
public beside(Component left,Component right,float ratio){
this.left = left;
this.right = right;
this.ratio = ratio;
}
public Component at(int x,int y,int width,int height) {
left.at(x, y, width*ratio,height);
right.at(x+ width*ratio, y, width*(1-ratio),height);
return this;
}
public Component in(Container parent) {
left.in(parent);
right.in (parent);
return this;
}
……
}
public class above implements Component {
private Component up,low;
private float ratio;
public above(Component up, Component low, float ratio){
this.up = up;
this.low = low;
this.ratio = ratio;
}
public Component at(int x,int y,int width,int height) {
up.at(x, y, width,height*ratio);
low.at(x, y+height*ratio, width,height*(1-ratio));
return this;
}
public Component in(Container parent) {
up.in(parent);
low.in (parent);
return this;
}
……
}
  為了保證組合操作的閉包性質(zhì),這兩個(gè)組合子都實(shí)現(xiàn)了 Component 接口,并且把組合的結(jié)果當(dāng)作一個(gè) Component 返回。這兩個(gè)組合子的主要功能就是把給定的布局空間按照指定的比例進(jìn)行分隔,并把給定的組件放到分隔好的布局空間中去。其中的算法比較簡(jiǎn)單,就不再贅述。

  基于這些基本的原子元素和組合子,就可以構(gòu)建出任意復(fù)雜程度的布局樣式。在前面語(yǔ)言介紹小節(jié)中,我們給出了一些如:center、h_seq、v_seq、block 以及 block_with_margin 等簡(jiǎn)單布局樣式的實(shí)現(xiàn)。讀者可以根據(jù)自己的需要定義并積累自己的布局樣式庫(kù)。


  前面提到過(guò),我們的界面布局語(yǔ)??敮?楆敬搨捯????????言是分層的,大家可以看出,在最底層是我們的 Java Swing 界面開(kāi)發(fā)語(yǔ)言,我們?cè)谄渖蠘?gòu)建出了界面布局位置描述語(yǔ)言,使用該布局位置描述語(yǔ)言中的組合子:beside 和 above,我們?cè)谄渖嫌謽?gòu)建出了用來(lái)定義和表達(dá)各種布局樣式的布局樣式描述語(yǔ)言。

  敏銳的讀者會(huì)發(fā)現(xiàn),在前面講述的界面布局語(yǔ)言中僅僅涉及了界面布局元素的顯示樣式方面的內(nèi)容,但是一個(gè)完整的界面是需要和后端的應(yīng)用邏輯交互的,因此還需要一個(gè)粘合界面顯示和應(yīng)用模型的層次。

  確實(shí)是這樣的,我們?cè)谶@里之所以沒(méi)有提這項(xiàng)內(nèi)容主要是為了避免陷入其實(shí)現(xiàn)的瑣碎細(xì)節(jié)中,從而可以集中介紹界面布局語(yǔ)言本身。為了能夠?qū)缑娌季衷剡M(jìn)行編程控制,我們讓每個(gè)布局元素都有一個(gè)“擁有者”。和布局元素在物理上的包含關(guān)系不同,“擁有者”是編程語(yǔ)義上的。也就是說(shuō),對(duì)布局元素在編程意義上的所有控制操作都在其“擁有者”中完成,這種思路完全隔離了顯示和控制,其實(shí)就是 MVP 模式的一種實(shí)現(xiàn)。

  比如,我們可以這樣描述一個(gè) Button:

Button().title(“button1”).ownby(btn1Controller);
  關(guān)于 Button 的所有事件處理和操控都在 btn1Controller 中完成。有機(jī)會(huì)的話,我們會(huì)在后續(xù)的文章中對(duì)此進(jìn)行具體的介紹,現(xiàn)在我們將其實(shí)現(xiàn)作為一個(gè)練習(xí)留給讀者來(lái)完成。

  關(guān)于設(shè)計(jì)的幾點(diǎn)思考

  在本文中,我們介紹了一種界面布局語(yǔ)言以及它的設(shè)計(jì)和實(shí)現(xiàn)。在此,我們有必要對(duì)其中的設(shè)計(jì)思路進(jìn)行一個(gè)回顧。

  在設(shè)計(jì)中,我們沒(méi)有采用對(duì)象技術(shù)中常用的一些設(shè)計(jì)手段,我們沒(méi)有對(duì)界面布局本身進(jìn)行抽象,也不是設(shè)計(jì)出一些特定的界面布局治理器。相反,我們把對(duì)象技術(shù)當(dāng)成一種低層的抽象工具,并基于它來(lái)構(gòu)建更高層次的抽象,創(chuàng)建出更加接近我們所工作的問(wèn)題領(lǐng)域的語(yǔ)言,從而獲得更高的生產(chǎn)力、表達(dá)力以及可重用性(還有什么比語(yǔ)言更加易于重用),這就是目前探討的比較熱烈的面向語(yǔ)言編程(Language-Oriented Programming)。

  前面已經(jīng)介紹過(guò),我們的界面布局語(yǔ)言是分層的,這種設(shè)計(jì)非常有助于構(gòu)建健壯的程序。這里健壯的含意是指:?jiǎn)栴}領(lǐng)域中的一個(gè)小的更改,所導(dǎo)致的程序更改也應(yīng)當(dāng)是相應(yīng)地小的。比如,我們?cè)跇?gòu)建迷你計(jì)算器時(shí),希望所有數(shù)字以及運(yùn)算符按鈕都在橫向和縱向留一些空白,這個(gè)問(wèn)題領(lǐng)域中的一個(gè)小的更改,所對(duì)應(yīng)的程序更改就是把 block 更改為 block_with_margine 而已。此外,由于分層的存在,我們可以自由地修改不同層次的表達(dá)細(xì)節(jié)而對(duì)其他層次不會(huì)造成任何影響。也就是說(shuō),每一層提供了用于表達(dá)系統(tǒng)特征的不同詞匯以及不同的更改方式和能力。

  由于動(dòng)態(tài)語(yǔ)言提供了更高的動(dòng)態(tài)性和元編程能力,因此在動(dòng)態(tài)語(yǔ)言中更輕易實(shí)現(xiàn)這種設(shè)計(jì)思路,我們也用 Python 語(yǔ)言基于 wXPython 界面工具庫(kù)實(shí)現(xiàn)了本文中講解的界面布局語(yǔ)言,相比 Java,它的實(shí)現(xiàn)確實(shí)要輕易和清楚地多。


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 诏安县| 济南市| 贡觉县| 阜平县| 肥西县| 左云县| 阿克| 阳江市| 太和县| 赫章县| 临汾市| 惠安县| 安溪县| 穆棱市| 汶川县| 岐山县| 瓮安县| 从化市| 邹城市| 漳州市| 贵南县| 桃源县| 甘孜县| 石林| 县级市| 宝山区| 富民县| 鸡东县| 德化县| 海宁市| 六枝特区| 沿河| 平顺县| 亳州市| 新巴尔虎左旗| 南木林县| 公安县| 海原县| 铜陵市| 临泽县| 航空|