摘要:以下這些場(chǎng)景都需要我們對(duì)一個(gè)對(duì)象進(jìn)行比較數(shù)據(jù)比對(duì)做單元測(cè)試斷言對(duì)象是否相等前端要求對(duì)不相等的字段進(jìn)行高亮顯示這種需求其實(shí)是非常簡(jiǎn)單的,但是如何優(yōu)雅地解決這一類(lèi)需求呢通常的做法是重寫(xiě)對(duì)象的方法。
聲明:本文屬原創(chuàng)文章,始發(fā)于 https://blog.csdn.net/dadiyan...。特此,同步發(fā)布到 sf,轉(zhuǎn)載請(qǐng)注明出處。
寫(xiě)在前面在工作中,我們經(jīng)常會(huì)遇到這樣的需求——比較兩個(gè)對(duì)象是否相等,如果不相等的話,取出不相等的字段。
以下這些場(chǎng)景都需要我們對(duì)一個(gè)對(duì)象進(jìn)行比較:
數(shù)據(jù)比對(duì)
做單元測(cè)試斷言對(duì)象是否相等
前端要求對(duì)不相等的字段進(jìn)行高亮顯示
這種需求其實(shí)是非常簡(jiǎn)單的,但是如何優(yōu)雅地解決這一類(lèi)需求呢?
通常的做法是重寫(xiě)對(duì)象的 equals 方法。但是重寫(xiě) equals 方法有很多缺點(diǎn),例如:
每次對(duì)象屬性有變更,一定要記得再重寫(xiě)(放心,你一定會(huì)忘記的)
每個(gè)對(duì)象只能有一個(gè) equals 方法,但是可能你會(huì)需要不同的比對(duì)規(guī)則
只能對(duì)比兩個(gè)對(duì)象是否相等,無(wú)法具體知道哪個(gè)屬性不等
自動(dòng)生成的 equals 方法無(wú)法基于 getter 方法進(jìn)行比對(duì)
對(duì)象來(lái)自第三方依賴(lài),無(wú)法重寫(xiě) equals 方法
因此,實(shí)現(xiàn)一個(gè)通用的比對(duì)器可以減少很多不必要的麻煩,幫助我們很好地完成這一類(lèi)的需求。
緣起我是在做數(shù)據(jù)同步的時(shí)候有這個(gè)需求,我要將數(shù)據(jù)庫(kù)的數(shù)據(jù)通過(guò)一定的規(guī)則導(dǎo)入到 ES 中,導(dǎo)入完成之后,如何比對(duì)兩邊的數(shù)據(jù)是否一致呢?這時(shí)候一個(gè)好用的比對(duì)器就是我非常好的幫手。
另外,我在做單元測(cè)試的時(shí)候發(fā)現(xiàn),經(jīng)常會(huì)需要將被測(cè)方法的返回值和期望的結(jié)果做 assertEquals 斷言這時(shí)這個(gè)比對(duì)器也非常有幫助。我發(fā)現(xiàn)很多同事經(jīng)常會(huì)遇到類(lèi)似的需求。
于是,我找時(shí)間自己實(shí)現(xiàn)了一下。
實(shí)現(xiàn)使用反射對(duì)傳入的對(duì)象進(jìn)行比對(duì),提供了基于字段的比較器和基于 Getter 方法的對(duì)比器,并且充分考慮擴(kuò)展性,使用者可以重寫(xiě)字段的比對(duì)規(guī)則。功能相對(duì)簡(jiǎn)單,代碼實(shí)現(xiàn)也不難,而且做了很多注釋?zhuān)唧w實(shí)現(xiàn)可以直接查看源碼。
項(xiàng)目地址:https://github.com/dadiyang/e...
UML圖:
因?yàn)橐呀?jīng)上傳到了 maven 倉(cāng)庫(kù)中,我們使用非常方便:
添加 maven 依賴(lài)
com.github.dadiyang equator 1.0.1
初始化并調(diào)用方法
Equator equator = new GetterBaseEquator(); User user1 = new User(...); User user2 = new User(...); // 判斷屬性是否完全相等 equator.isEquals(user1, user2); // 獲取不同的屬性 List擴(kuò)展diff = equator.getDiffFields(user1, user2);
我們可以通過(guò)繼承并重寫(xiě) isFieldEquals 方法自定義比對(duì)規(guī)則,例如我們?cè)谧鰡卧獪y(cè)試的時(shí)候,對(duì)于 Date 類(lèi)型的字段的比對(duì),通常數(shù)據(jù)庫(kù)不保存毫秒數(shù),而我們 new 出來(lái)的 Date 對(duì)象則包含了毫秒數(shù),因此我們?cè)趯?duì)包含 Date 類(lèi)型字段的對(duì)象做比對(duì)的時(shí)候需要忽略日期的毫秒數(shù)。這時(shí)就可以通過(guò)重寫(xiě)isFieldEquals 方法來(lái)自定義了:
/** * 日期在數(shù)據(jù)庫(kù)不保存毫秒數(shù),因此需要特殊處理,比對(duì)時(shí)間時(shí),忽略毫秒數(shù) * * @author dadiyang * @date 2019/3/23 */ public class MmInsensitiveEquator extends GetterBaseEquator { @Override protected boolean isFieldEquals(FieldInfo fieldInfo) { if (fieldInfo.getFirstVal() instanceof Date) { Date first = (Date) fieldInfo.getFirstVal(); Date second = (Date) fieldInfo.getSecondVal(); if (Objects.equals(first, second)) { return true; } // 忽略毫秒數(shù) return Objects.equals(Math.round(first.getTime() / 1000), Math.round(second.getTime() / 1000)); } return super.isFieldEquals(fieldInfo); } }后記
對(duì)象比對(duì)是一個(gè)非常小的需求,通常我們只會(huì)寫(xiě)一個(gè)工具類(lèi)來(lái)完成。但是寫(xiě)一個(gè)工具類(lèi)在各個(gè)項(xiàng)目間隨處拷貝,非常不優(yōu)雅,給整個(gè)團(tuán)隊(duì)帶來(lái)很多不必要的維護(hù)成本。而且擴(kuò)展性比較差,有任何差異就需要寫(xiě)很多代碼去實(shí)現(xiàn)。
這時(shí),如果我們從具體解決某一個(gè)需求的視角上升到解決一類(lèi)需求,那么就能想出更加通用和優(yōu)雅的解決方案了。一個(gè)個(gè)具體的需求是無(wú)窮無(wú)盡的,以有限的人生去解決無(wú)限的需求,殆矣;但是將它們歸類(lèi)之后,我們會(huì)發(fā)現(xiàn),需求的種類(lèi)是有限的。
因此解決一類(lèi)一類(lèi)問(wèn)題,能讓我們擺脫無(wú)窮無(wú)盡的重復(fù)勞動(dòng),少加點(diǎn)班,多點(diǎn)時(shí)間陪陪家人哦。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77732.html
摘要:中,任何未處理的受檢查異常強(qiáng)制在子句中聲明。運(yùn)行時(shí)多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)需要方法重寫(xiě)子類(lèi)繼承父類(lèi)并重寫(xiě)父類(lèi)中已 1、簡(jiǎn)述Java程序編譯和運(yùn)行的過(guò)程:答:① Java編譯程序?qū)ava源程序翻譯為JVM可執(zhí)行代碼--字節(jié)碼,創(chuàng)建完源文件之后,程序會(huì)先被編譯成 .class 文件。② 在編譯好的java程序得到.class文件后,使用命令java 運(yùn)行這個(gè) .c...
摘要:中,任何未處理的受檢查異常強(qiáng)制在子句中聲明。運(yùn)行時(shí)多態(tài)是面向?qū)ο笞罹璧臇|西,要實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)需要方法重寫(xiě)子類(lèi)繼承父類(lèi)并重寫(xiě)父類(lèi)中已 1、簡(jiǎn)述Java程序編譯和運(yùn)行的過(guò)程:答:① Java編譯程序?qū)ava源程序翻譯為JVM可執(zhí)行代碼--字節(jié)碼,創(chuàng)建完源文件之后,程序會(huì)先被編譯成 .class 文件。② 在編譯好的java程序得到.class文件后,使用命令java 運(yùn)行這個(gè) .c...
摘要:抽象函數(shù)引發(fā)的關(guān)系是等價(jià)關(guān)系。所以當(dāng)且僅當(dāng)通過(guò)調(diào)用抽象數(shù)據(jù)類(lèi)型的任何操作不能區(qū)分它們時(shí),兩個(gè)對(duì)象是相等的。必須為每個(gè)抽象數(shù)據(jù)類(lèi)型適當(dāng)?shù)囟x操作。一般來(lái)說(shuō),在面向?qū)ο缶幊讨惺褂檬且环N陋習(xí)。 大綱 什么是等價(jià)性?為什么要討論等價(jià)性?三種等價(jià)性的方式==與equals()不可變類(lèi)型的等價(jià)性對(duì)象契約可變類(lèi)型的等價(jià)性自動(dòng)包裝和等價(jià)性 什么是等價(jià)性?為什么要討論等價(jià)性? ADT上的相等操作 ADT...
摘要:減少垃圾收集壓力因?yàn)樗虚L(zhǎng)生命周期的數(shù)據(jù)都是在的管理內(nèi)存中以二進(jìn)制表示的,所以所有數(shù)據(jù)對(duì)象都是短暫的,甚至是可變的,并且可以重用。當(dāng)然,并不是唯一一個(gè)基于且對(duì)二進(jìn)制數(shù)據(jù)進(jìn)行操作的數(shù)據(jù)處理系統(tǒng)。 showImg(https://segmentfault.com/img/remote/1460000020044119?w=1280&h=853); 前言 如今,許多用于分析大型數(shù)據(jù)集的開(kāi)源系...
摘要:中有三種不同的對(duì)象,三種對(duì)象的屬性和行為和下方的類(lèi)似構(gòu)造函數(shù)對(duì)象構(gòu)造函數(shù)為的類(lèi)定義名稱(chēng),任何添加到這個(gè)構(gòu)造函數(shù)對(duì)象中的屬性都是類(lèi)字段和類(lèi)方法。 JavaScript中的Java式繼承 區(qū)別 Java類(lèi)似的強(qiáng)類(lèi)型面向?qū)ο笳Z(yǔ)言,類(lèi)為 實(shí)例字段 他們是基于實(shí)例的屬性或變量,用以保存獨(dú)立對(duì)象的狀態(tài) 實(shí)例方法 他們是類(lèi)的所有實(shí)例所共享的方法,由每個(gè)獨(dú)立的實(shí)例調(diào)用 類(lèi)字段 這些屬性或者變量是屬于類(lèi)...
閱讀 3480·2023-04-26 02:48
閱讀 1473·2021-10-11 10:57
閱讀 2499·2021-09-23 11:35
閱讀 1206·2021-09-06 15:02
閱讀 3305·2019-08-30 15:54
閱讀 1623·2019-08-30 15:44
閱讀 891·2019-08-30 15:44
閱讀 997·2019-08-30 12:52