黃振帆 邱陽 陳偉 李帆 廖維鵬
摘要:隨著當今互聯(lián)網(wǎng)產(chǎn)業(yè)的高速發(fā)展,智慧園區(qū),智慧交通,智慧物流各類概念層出不窮,所應(yīng)用的領(lǐng)域各不相同,其中卻不乏包含一些通用的功能模塊,若是能將這些通用的模塊封裝出來,成為一個基礎(chǔ)的平臺,則開發(fā)人員只需將精力投入在專業(yè)性定制化的功能模塊上,能極大地提高整體的工作效率。該文將從已有項目的平臺作為切入點,分析管廊、有軌電車、智慧交通的特點,并針對跨行業(yè)線智慧項目代碼復(fù)用性進行研究。
關(guān)鍵詞:代碼復(fù)用性;跨行業(yè)線;智慧項目;web;Java
中圖分類號:TP311? ? ? 文獻標識碼:A
文章編號:1009-3044(2021)17-0062-04
開放科學(xué)(資源服務(wù))標識碼(OSID):
1 代碼復(fù)用性
1.1 為什么要提出代碼復(fù)用性
市政業(yè)務(wù)種類繁多,不同的行業(yè)所涉及的內(nèi)容也不盡相同,若是每一個行業(yè)都開發(fā)一套屬于自己的管理平臺,固然是好事,但這其中所需投入的人員、時間、精力也是成倍地增加。若是有辦法讓一套代碼應(yīng)用于多個行業(yè)線,將繁雜的業(yè)務(wù)融合到一起,讓開發(fā)人員能集中精力放在新功能的迭代上,而不是編寫大量冗余的代碼,從而提升工作效率,由此代碼的復(fù)用性由此應(yīng)運而生。
1.2 什么是多行業(yè)線
本文要討論的多行業(yè)線是指多個不同或近似行業(yè),在擁有相同基礎(chǔ)功能的情況下,又針對各自行業(yè)線衍生出貼合自己專業(yè)性功能的平臺。
目前已有的行業(yè)線項目有:管廊,有軌電車,智慧交通。
通用的模塊包括事件管理,問題管理,發(fā)布管理,變更管理,知識庫管理,設(shè)備管理,組織管理,用戶管理,角色管理,菜單管理,設(shè)備類型,菜單管理,字典管理,操作日志。
管廊行業(yè)線特有功能:管廊管理,艙室管理,分區(qū)管理,系統(tǒng)總覽,綜合監(jiān)控,BIM仿真等。
有軌電車行業(yè)線特有功能:站點管理,檢測內(nèi)容管理,打卡任務(wù)管理等。
指揮交通行業(yè)線特有功能:站點管理,內(nèi)容管理,車輛管理,異常情況,路線管理等。
由上述描述我們可以發(fā)現(xiàn),不同的行業(yè)線,不僅有許多業(yè)務(wù)功能相同的模塊,有些行業(yè)線特有的功能也有著一定的相似程度,比如管廊行業(yè)線中的管廊,艙室,分區(qū),與有軌電車行業(yè)線中的站點,都是對地點進行描述的字段,區(qū)別點僅在于管廊的地點分為三級,有軌電車僅一級,那么,我們是不是可以根據(jù)這一特點,合理的設(shè)計數(shù)據(jù)庫,利用技術(shù)手段,將其也做到通用化,使一套代碼可以適應(yīng)多個行業(yè)線呢?答案是可以的。
2 代碼復(fù)用的優(yōu)點
代碼復(fù)用的初衷是為了提高效率,節(jié)約重復(fù)開發(fā)的時間。
當我們著手一個新的項目時,會發(fā)現(xiàn)有許多功能與我們之前的項目時相同的,若是能復(fù)用以前設(shè)計中的一些模塊,一方面是可以減少一些重復(fù)性的設(shè)計工作;另外一方面,以前的模塊多是經(jīng)過驗證了的,出問題的概率也比較小。
當然并不是所有模塊都可以不需改動很完美地復(fù)用到新項目中,不同行業(yè)的項目都會有些許改動,那么如何將這些模塊融入新項目,接下來我們就會進行跨行業(yè)代碼復(fù)用性的研究。
3 代碼復(fù)用的實現(xiàn)
3.1 三大特性
說到代碼的復(fù)用性,首先要了解Java的三大特性:封裝、繼承和多態(tài)。
封裝使得每個獨立的功能模塊化了。我們要學(xué)會養(yǎng)成“分類”的習(xí)慣。這樣的代碼不僅結(jié)構(gòu)清晰而且容易被復(fù)用。就算是熟練的程序員,也不能保證自己寫過的代碼沒有錯誤,代碼已經(jīng)封裝就可以保證它在功能范圍內(nèi)的正確性。這樣,我們就不用浪費時間去檢查和編寫那些已有的功能了。良好的封裝能夠大大地降低模塊間的耦合度。
繼承是從已有的類中派生出新的類,新的類能吸收已有類的數(shù)據(jù)屬性和行為,并能擴展新的能力。
多態(tài)是同一個行為具有多個不同表現(xiàn)形式或形態(tài)的能力。多態(tài)就是同一個接口,使用不同的實例而執(zhí)行不同操作。多態(tài)性是對象多種表現(xiàn)形式的體現(xiàn)。
這三個特性是實現(xiàn)代碼復(fù)用的基礎(chǔ),即我們應(yīng)該把更多的心思放在新的功能上,而不是反復(fù)地寫一些陳舊的代碼。
3.2 常量
在程序運行過程中,其值始終不變的量稱之為常量。常量又分為整型常量,浮點型常量,小數(shù)型常量,字符型常量,布爾型常量,字符串常量。這里我們著重介紹一下字符串常量。
字符串常量表示若干個Unicode字符組成的字符序列,使用兩個英文雙引號來標記,如“ABC” “管廊”都是字符串常量。要注意字符串常量與字符型常量的區(qū)別。
3.3 枚舉
Java 枚舉是一個特殊的類,一般表示一組常量。Java 枚舉類使用 enum 關(guān)鍵字來定義,各個常量使用逗號 , 來分割。
使用實例:
enum Color
{
RED, GREEN, BLUE;
}
public class Test
{
// 執(zhí)行輸出結(jié)果
public static void main(String[] args)
{
Color c1 = Color.RED;
System.out.println(c1);
}
}
相信有很多朋友想問為什么講解復(fù)用性要單獨介紹常量和枚舉,這又與多行業(yè)線有什么聯(lián)系。接下來我就為各位娓娓道來,在智慧運維管理平臺中,是如何實現(xiàn)跨行業(yè)線的代碼復(fù)用的。
4 智慧項目的代碼復(fù)用性研究
前面我們介紹了智慧運維管理平臺的三條行業(yè)線,管廊行業(yè),有軌電車行業(yè),智慧交通行業(yè),如果我們不考慮代碼的復(fù)用性,那么開發(fā)人員將會面臨開發(fā)三套系統(tǒng)的窘迫,若是開發(fā)三套系統(tǒng)其中通用功能需要修改,每一處改動都要改三個地方,又是增加了代碼出現(xiàn)錯誤的風(fēng)險性,所以將系統(tǒng)合理的設(shè)計,成為一套靈活可配置的系統(tǒng),節(jié)約開發(fā)人員的開發(fā)成本,提高開發(fā)效率,就顯得尤為重要。
首先我們來分析三條行業(yè)線共用一套代碼可能會出現(xiàn)的問題。
舉例一:
管廊的設(shè)備所屬位置是在分區(qū)中,而管廊位置定義有三級ID,管廊,艙室,分區(qū),也就是說如果要定位一個設(shè)備,需要有三級樹形結(jié)構(gòu)去定義它的位置。
有軌電車和智慧交通都是以站點定義位置,沒有管廊的三級結(jié)構(gòu)。
那么問題就出現(xiàn)了,在管廊項目中維護設(shè)備信息時,我們關(guān)聯(lián)了管廊表、艙室表、分區(qū)表,由于篇幅關(guān)系,我們只截取片段:
Map
Map
Map
……
List
IntStream.range(0, firstIdSize).forEach(index -> {
if (StringUtils.isNotBlank(thirdIds.get(index)) && cabinPartitionDataMap.containsKey(thirdIds.get(index))) {
Map dataMap = cabinPartitionDataMap.get(thirdIds.get(index));
returnStringList.add(new String[]{Objects.isNull(dataMap.get("gallery_name")) ? "" : dataMap.get("gallery_name").toString(),
Objects.isNull(dataMap.get("cabin_name")) ? "" : dataMap.get("cabin_name").toString(),
Objects.isNull(dataMap.get("cabin_part_name")) ? "" : dataMap.get("cabin_part_name").toString()});
} else if (StringUtils.isNotBlank(secondIds.get(index)) && cabinDataMap.containsKey(secondIds.get(index))) {
Map dataMap = cabinDataMap.get(secondIds.get(index));
returnStringList.add(new String[]{Objects.isNull(dataMap.get("gallery_name")) ? "" : dataMap.get("gallery_name").toString(),
Objects.isNull(dataMap.get("cabin_name")) ? "" : dataMap.get("cabin_name").toString(), ""});
} else if (StringUtils.isNotBlank(firstIds.get(index)) && galleryDataMap.containsKey(firstIds.get(index))) {
Map dataMap = galleryDataMap.get(firstIds.get(index));
returnStringList.add(new String[]{Objects.isNull(dataMap.get("gallery_name")) ? "" : dataMap.get("gallery_name").toString(), "", ""});
} else {
returnStringList.add(new String[]{"", "", ""});
}
});
return returnStringList;
接口返回三級ID和名稱,如下:
"firstId": "e6e4c2374dd74de89c1fd8d33b609830",
"firstName": "三亞管廊",
"secondId": "b8050b4ca6964438b078c7b8dc3e0a49",
"secondName": "綜合艙",
"thirdId": "3bdc3a940bf545db97961df79afcf689",
"thirdName": "01"
應(yīng)用到項目中的效果
而有軌電車項目和指揮交通項目中,我們只有一個站點表,不論將其主鍵放在firstId,secondId,thirdId中的哪一個,都無法用管廊獲取名稱和ID的代碼去獲取其相應(yīng)的名稱,如果用到項目中會無法正確顯示。
但是firstId,secondId,thirdId都是可以在不同項目中利用起來的字段,我們應(yīng)該如何將其與有軌電車項目和指揮交通項目聯(lián)系起來呢?這時候之前介紹的枚舉和常量就要發(fā)揮作用了。
首先我們選擇一個字段將有軌電車項目和智慧交通項目的站點ID存入,這里我們選擇secondId。
這樣我們在處理有軌電車項目和智慧交通項目時,獲取站點名稱就可以用secondId關(guān)聯(lián)站點表。
接下來我們建立一個包含三個行業(yè)線的枚舉,方便日后維護和切換行業(yè)線。
public enum SystemProjectEnum implements BaseStringEnum {
UTILITYTUNNEL("utilityTunnel", "管廊"),TRAFFIC("traffic", "交通"),TRAMCAR("tramcar", "有軌電車");
……
}
建立枚舉后,我們需要設(shè)置一個全局的常量類。
/**
* 當前項目行業(yè)線分支
*/
public final static SystemProjectEnum CURRENT_PROJECT_ENUM = SystemProjectEnum.UTILITYTUNNEL;
設(shè)置好常量類后,我們就可以在需要不同行業(yè)線展示不同數(shù)據(jù)的代碼部分,通過判斷當前系統(tǒng)所處行業(yè)線,進行不同的處理。
if (EnumsUtils.isRightProject(SystemProjectEnum.UTILITYTUNNEL)) {
……
} else {
……
List
secondIds.stream().forEach(secondId -> {
if (StringUtils.isBlank(secondId) || !dataListMap.containsKey(secondId)) {
returnStringList.add(new String[]{null, "", null});
return;
}
Map dataMap = dataListMap.get(secondId);
returnStringList.add(new String[]{null, Objects.isNull(dataMap.get("name")) ? "" : dataMap.get("name").toString(), null});
});
return returnStringList;
}
}
通過上面的代碼我們可以看到,if (EnumsUtils.isRightProject(SystemProjectEnum.UTILITYTUNNEL))判斷當前行業(yè)線,SystemProjectEnum.UTILITYTUNNEL? ? ?為管廊行業(yè)線,若當前行業(yè)線不時管廊則進入else判斷內(nèi)(因為有軌電車和智慧交通設(shè)計一致),最后將secondId對應(yīng)的站點名稱放入集合中,接口返回結(jié)果如下:
secondId: "1"
secondName: "杭州東站"
應(yīng)用到項目中的效果:
由圖4我們可以發(fā)現(xiàn),利用設(shè)置全局常量,很好地解決了管廊設(shè)備位置和其他行業(yè)線設(shè)備位置沖突的問題。
舉例二:
上面我們闡述了面對不同行業(yè)線,相同功能關(guān)聯(lián)數(shù)據(jù)庫表不同導(dǎo)致返回數(shù)據(jù)錯誤,利用全局常量來區(qū)分當前打包項目的行業(yè)線,從而返回各自行業(yè)線需要的數(shù)據(jù),接下來我們再通過一個案例來分析。
public void cabinPartAlarmInfoPush() {
if (EnumsUtils.isRightProject(SystemProjectEnum.UTILITYTUNNEL)) {
if (webSocketMap.isEmpty()) {
return;
}
WebSocketData webSocketData = new WebSocketData();
webSocketData.setType(WebSocketMessageTypeEnum.BB_MAP_GALLERY.getCode());
Response response = Response.okAndData(WebSocketMessageTypeEnum.REQUEST.getCode(), webSocketData);
String message = JSON.toJSONString(response, SerializerFeature.WriteMapNullValue);
sendMessage(message);
}
}
上述代碼是截取了一個定時任務(wù)的一部分,利用webSocket向前端發(fā)送數(shù)據(jù)的功能,該功能只在管廊行業(yè)線啟用,同舉例一,還是通過判斷當前系統(tǒng)的行業(yè)線是否為管廊,如果是,則進入if判斷,發(fā)送消息給前端,否則不發(fā)送消息。若是沒有個判斷當前行業(yè)線的條件在,開發(fā)人員就會面臨一個問題,需要開發(fā)多套系統(tǒng)代碼,若是使用一套代碼則開發(fā)管廊項目時,需要放開這個功能,開發(fā)有軌電車項目和智慧交通項目時,又要把這個功能注釋掉,當項目中有許多這樣的功能時,大量的注釋放開操作,無形之中降低了項目的容錯率,增加了時間成本,影響開發(fā)效率。而當我們使用了這個全局常量判斷了當前行業(yè)線后,在管廊以外行業(yè)線在開發(fā)又或是打包時就不需要將管廊的部分注釋,而當以后出現(xiàn)新的行業(yè)線或者老的行業(yè)線也需要發(fā)送,只需要往下添加if else即可,方便管理和維護代碼,增強了代碼的可擴展性,同時也讓多行業(yè)線可以并存,實現(xiàn)的代碼的復(fù)用性。
5 結(jié)束語
隨著市政業(yè)務(wù)的不斷增加,管廊,智慧交通,智慧園區(qū),各類項目層出不窮,如果還是按以往的開發(fā)模式,按項目為單位開發(fā),勢必會造成資源無法有效利用的情況,而且多套代碼對日后的維護,修改都會產(chǎn)生巨大的隱患,因此,開發(fā)一套成熟可復(fù)用的代碼就顯得尤為重要,針對具體行業(yè)線實現(xiàn)定制化的服務(wù),同時又不影響其他行業(yè)線功能的實現(xiàn)。本文就跨行業(yè)線情況下的智慧運維平臺代碼復(fù)用性提出了一個解決方案,就是利用設(shè)置全局常量,指定當前開發(fā)項目的行業(yè)線,在接口中對不同行業(yè)線進行不同的處理,并且設(shè)置一個配置行業(yè)線的枚舉,方便維護新舊行業(yè)線,由此一套代碼可復(fù)用與各個行業(yè)線,各個業(yè)務(wù)場景,實現(xiàn)了代碼的復(fù)用性,減少了冗余代碼的出現(xiàn),讓開發(fā)人員更加專注地投入新功能的開發(fā)上,而不是著力于老代碼的兼容,極大地提升了開發(fā)效率,節(jié)省了多行業(yè)項目的開發(fā)時間,同時具有極大的兼容性。
參考文獻:
[1] 菜鳥教程.Java繼承[EB/OL].[2020-08-24]. https://baike.baidu.com/reference/3532678/6647iBrb-WmCOqi8QzCNlFLkc-lFgPHNRAHS3J92hj2moOdnaWrz-AW3RJ3C5BBXIhSB82P6zdx7RXF16RCoAhyjjEQNkg-K9jrJ66Iv.
[2] 一騎輕塵-宮本.Java·代碼的復(fù)用之美[EB/OL].[2020-08-24].https://blog.csdn.net/qq_31428627/article/details/79125896.
[3] PHP中文網(wǎng).java 多態(tài)是什么-Java入門[EB/OL].[2020-08-24]. https://www.php.cn/java/guide/435428.html.
[4] 于清宗."常量"與"變量"[EB/OL].[2020-08-24].https://xueshu.baidu.com/usercenter/paper/show?paperid=2395d99dd63a5a0b d27efd89037674f5&tn=SE_baiduxueshu_c1gjeupa&ie=utf-8&site=baike.
[5] 菜鳥教程.Java枚舉[EB/OL].[2020-08-24].https://baike.baidu.com/reference/3532678/6647iBrb-WmCOqi8QzCNlFLkc-lFgPHNRAHS3J92hj2moOdnaWrz-AW3RJ3C5BBXIhSB82P6zdx 7RXF16RCoAhyjjEQNkg-K9jrJ66I v.
【通聯(lián)編輯:謝媛媛】