黃振帆 邱陽 陳偉 李帆 廖維鵬



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