您好,登錄后才能下訂單哦!
為解決工作中一些繁瑣的問(wèn)題, 寫(xiě)了一個(gè)GUI程序, 操作界面是這個(gè)樣子的
這個(gè)程序的實(shí)現(xiàn)起來(lái)并不是非常的繁瑣, 但在界面的交互操作上, 也不僅僅只是展示數(shù)據(jù)。 如上面圖片所見(jiàn),列表中的每一條記錄每一個(gè)數(shù)據(jù)項(xiàng)都需要可以填寫(xiě)和選擇; 需要添加和刪除記錄;還需要調(diào)整記錄的位置;向上移動(dòng)、向下移動(dòng);要實(shí)現(xiàn)這些操作, 控制UI的程序其實(shí)挺復(fù)雜的。
我哼哧哼哧的把這個(gè)程序?qū)懲辏?拿去給同事們演示使用方法, 同事們給我提出了不少的建議。 其中的一條是:把界面分割成上下兩部份的方式替代列表中類(lèi)型字段的選擇, 以簡(jiǎn)化交互操作, 也就是說(shuō)簡(jiǎn)化過(guò)后, 程序的操作界面要變成下面這個(gè)樣子
以寫(xiě)代碼為生的同學(xué)肯定知道, 需求更改后的實(shí)現(xiàn)并不是一件愉快的事, 雖然給我提建議的同事并不是需求方, 但是他們的一些意見(jiàn)我不得不考慮, 我也不得不承認(rèn), 在軟件操作的便利性上, 同事們給出的意見(jiàn)確實(shí)要比原來(lái)強(qiáng)上不少。 但是假如真的要以這種方式去修改程序, 大家可以設(shè)身處地的想想, 假如這個(gè)程序是由你開(kāi)發(fā)的, 要做這樣的修改, 會(huì)不會(huì)是一件很費(fèi)勁的事情? 大量的代碼邏輯變動(dòng)或者以復(fù)制代碼的方式讓界面上的兩個(gè)列表的UI交互操作互不沖突并且不影響結(jié)果的正確性是不可避免的,甚至于在極端情況下, 會(huì)讓整個(gè)程序的結(jié)構(gòu)產(chǎn)生變動(dòng)也未可知。 當(dāng)同事們建議的聲音鉆入我的耳朵的第一瞬間, 我就覺(jué)得這是一件不可能實(shí)現(xiàn)的事情, 第一反應(yīng)就是立馬反駁, 并表示這是一項(xiàng)無(wú)法完成的工作。
事后,我靜下心來(lái)思考這個(gè)事情。 首先, 同事們的建議是完全合理的, 除了程序的修改難度問(wèn)題,我找不到合適的理由拒絕; 其次, 我回憶我寫(xiě)這個(gè)程序時(shí)代碼邏輯的組織方式,我發(fā)現(xiàn)假如我要把程序修改的符合像同事們建議的那樣似乎也并不需要費(fèi)多少功夫, 而且可以說(shuō)是非常非常的簡(jiǎn)單, 簡(jiǎn)單到不可思議。 我照著我腦海中生成的方案去做, 只花了15分鐘左右時(shí)間就完成了任務(wù), 實(shí)現(xiàn)了指定的效果, 而且只修改了五六行核心業(yè)務(wù)邏輯代碼, 界面和操作的變動(dòng)與工作量以及代碼的修改完全不成正比,這讓我自己也覺(jué)得很驚。 修改的過(guò)程中我大致做了下面這些事情
界面部份的改動(dòng)
1. 調(diào)整界面中各個(gè)組件的尺寸, 騰出一塊空白的區(qū)域來(lái)放第二個(gè)列表
2. 把第一個(gè)列表的xaml代碼復(fù)制一份到剛剛騰出來(lái)的位置, 這段xaml代碼是一個(gè)ListView控件,所以需要給它命一個(gè)新的名稱(chēng)
3. 把界面右上角「添加一項(xiàng)」按扭也復(fù)制一份, 放在第二個(gè)ListView的上方位置, 并綁定一個(gè)新事件
程序部份的改動(dòng)
為新的ListView綁定一個(gè)數(shù)據(jù)源
2. 為新的「添加一項(xiàng)」綁定事件代碼
然后, 大功告成, 就這么簡(jiǎn)單的把這事給辦了
有同學(xué)可以會(huì)提出疑問(wèn):“不說(shuō)別的, 就說(shuō)第二個(gè)列表的刪除、上移、下移這三項(xiàng)功能的事件代碼寫(xiě)在哪了? 你這是當(dāng)我們是沒(méi)寫(xiě)過(guò)代碼的小白來(lái)忽悠嗎?”, 事實(shí)上, 這些代碼是有的, 都是復(fù)用前一個(gè)列表的事件代碼?!暗珵槭裁瘁槍?duì)前一個(gè)列表的事件代碼毫無(wú)變化的過(guò)渡到新的ListView上使用呢?這不符合常規(guī)編程邏輯”,這其實(shí)跟我程序代碼的設(shè)計(jì)方式有關(guān)
大家看到程序的界面中有許多界面交互操作的功能,如添加、刪除、上移、上移, 只要鼠標(biāo)點(diǎn)擊在這些按扭之上, 界面就會(huì)立刻發(fā)生變化, 這勢(shì)必需要通過(guò)程序去控制界面元素。 這個(gè)程序是用C#和XAML開(kāi)發(fā)了, 但考慮到受眾問(wèn)題, 我用JavaScript和html舉個(gè)例子, 假如我們需要移除一個(gè)表格中的一項(xiàng), 那么我們肯定要通過(guò)文檔對(duì)象模型去操控這張html表格,比如說(shuō)通過(guò)這樣的方式去移除
var ele = document.getElementById("表格行ID");
ele.parentNode.removeChild(ele);
為列表添加一也是同樣的道理, 上移下移列表項(xiàng)也是一樣, 只是實(shí)現(xiàn)起來(lái)更加的困難復(fù)雜, 但這都是常規(guī)的實(shí)現(xiàn)思路。
然而,我卻不是以這種方式去實(shí)現(xiàn)這個(gè)WPF GUI程序的。 再舉個(gè)例子, 在我們開(kāi)發(fā)Web應(yīng)用程序時(shí)以列表的方式展示數(shù)據(jù)最常見(jiàn)不過(guò),當(dāng)我們要?jiǎng)h除某一條數(shù)據(jù)時(shí), 不使用ajax進(jìn)行無(wú)刷新刪除的做法是,先刪除數(shù)據(jù),再刷新頁(yè)面,那條需要?jiǎng)h除的數(shù)據(jù)就被去除掉了, 數(shù)據(jù)庫(kù)和界面, 雙重的。 這種方法的優(yōu)點(diǎn)就是邏輯簡(jiǎn)單, 以刷新頁(yè)面替代JavaScript操作DOM來(lái)進(jìn)行界面更新; 缺點(diǎn)就是體驗(yàn)差,沒(méi)有辦法做到無(wú)刷新更新頁(yè)面。 對(duì)頁(yè)面的其它操作也可以相同的方式更新UI, 將記錄插入數(shù)據(jù)庫(kù)后刷新頁(yè)面,界面上顯示的數(shù)據(jù)也會(huì)隨之增加;修改數(shù)據(jù)庫(kù)中記錄的排序號(hào)碼,刷新頁(yè)面后界上對(duì)應(yīng)的數(shù)據(jù)項(xiàng)也會(huì)轉(zhuǎn)移到相應(yīng)的位置;
我正是借用了這種瀏覽器/服務(wù)器架構(gòu)的程序設(shè)計(jì)思路,才把問(wèn)題簡(jiǎn)單化,省略了各種動(dòng)態(tài)更新UI的程序操作, 對(duì)UI的更新只在ListView綁定數(shù)據(jù)的時(shí)候進(jìn)行了。 我設(shè)計(jì)這個(gè)的核心思路大致如下
1. 新建一個(gè)列表數(shù)據(jù)結(jié)構(gòu), 用來(lái)存放顯示在ListView控件中的內(nèi)容
2. 執(zhí)行添加操作時(shí)往這個(gè)列表結(jié)構(gòu)中插入一條數(shù)據(jù), 然后重新把數(shù)據(jù)綁定至ListView, 使其重新渲染界面。 所有添加操作都是以這種方式執(zhí)行, 先更新數(shù)據(jù)結(jié)構(gòu), 再渲染ListView
3. 刪除操作與添加操作相似, 先將數(shù)據(jù)項(xiàng)從列表數(shù)據(jù)結(jié)構(gòu)中刪除, 再讓ListView根據(jù)數(shù)據(jù)源重繪UI
4. 其它對(duì)UI的操作亦都是如此
將所有原本需要對(duì)UI進(jìn)行的操作都轉(zhuǎn)移至對(duì)數(shù)據(jù)進(jìn)行操作, 再根據(jù)被操作后的數(shù)據(jù)結(jié)果重繪UI, 這樣做的好處是代碼的邏輯變的清晰簡(jiǎn)單了,除了將數(shù)據(jù)映射成界面的時(shí)候需要關(guān)注UI相關(guān)的邏輯, 其它時(shí)候只關(guān)心數(shù)據(jù)就可以了, 操縱數(shù)據(jù)結(jié)構(gòu)的難度顯然是低于操作界面元素的。缺點(diǎn)就是每一次交互操作導(dǎo)致數(shù)據(jù)產(chǎn)生變化后, 都需要完全重繪UI,影響用戶(hù)體驗(yàn)。對(duì)于Web應(yīng)用程序這種影響很明顯,因?yàn)樾枰獔?zhí)行一次http請(qǐng)求,在瀏覽器內(nèi)刷新頁(yè)面。 而對(duì)于windows GUI應(yīng)用程序,這種體驗(yàn)上的差距用肉眼幾乎難以觀察的到, 數(shù)據(jù)是從內(nèi)存中讀取的, 沒(méi)有任何網(wǎng)絡(luò)開(kāi)銷(xiāo);而重繪界面的時(shí)間只需要幾毫秒甚至更少,因此完全沒(méi)有理由去關(guān)注這些根本不會(huì)影響到軟件使用的問(wèn)題, 我們應(yīng)該關(guān)注的是如何簡(jiǎn)化代碼,如何提升軟件可用性等實(shí)質(zhì)性的問(wèn)題。
我的程序以這種設(shè)計(jì)思路實(shí)現(xiàn), 在應(yīng)用同事們提升出建議修改程序時(shí),概括來(lái)說(shuō)我就做了兩件事
1. 修改界面, 多加了一個(gè)ListView控件, 兩個(gè)控件的結(jié)構(gòu)完全一樣
2. 把原來(lái)的一大份數(shù)據(jù),拆成了兩份,分別綁定至兩個(gè)ListView
修改成
就這么任性的搞定了
很多時(shí)候我們總是抱怨需求的變化導(dǎo)致我們工作量加大, 每當(dāng)聽(tīng)到需求有變化需要把程序大改特改的消息時(shí)就像聽(tīng)到了自己的女朋友跟別的男人跑了一樣激動(dòng), 認(rèn)為一切都需要推倒重來(lái), 所有的努力的付出都浪費(fèi)了。 然而, 事實(shí)上, 代碼邏輯組織的有足夠的技巧, 完全可以將需求變化帶來(lái)的對(duì)代碼改動(dòng)的影響降至最低。每一個(gè)專(zhuān)業(yè)的程序員都應(yīng)該具備“應(yīng)對(duì)變化”的能力。我們的時(shí)間是有限且寶貴的, 寫(xiě)出愚蠢的需要花大量時(shí)間去維護(hù)以及無(wú)法應(yīng)對(duì)變化的代碼是一種浪費(fèi)時(shí)間、浪費(fèi)生命的慢性自殺,所以,寫(xiě)代碼時(shí)注意技巧,永遠(yuǎn)不會(huì)錯(cuò)
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。