延迟加载是一种代码气味
您見過那些具有許多屬性的巨大物體嗎? 這些域?qū)ο笥捎诓幌M麖臄?shù)據(jù)庫檢索太多信息而在其中使用延遲加載? 我敢打賭你有這種令人懷疑的快樂。
今天,我想與大家分享我對它們的印象- 使用延遲加載應(yīng)該被視為一種代碼味道!
讓我解釋一下自己:
- 延遲加載意味著有時您不需要某個對象的某些屬性。 這些屬性將在不同的上下文中是必需的。 這是否意味著您要根據(jù)上下文構(gòu)建不同的對象?
- 使用此對象的功能肯定知道太多。 它知道對象的API,并且此API還包含需要未加載屬性的方法。 很好,不是嗎?
- 您必須記住每個地方需要什么,不需要什么…
- …而且,更糟糕的是,您必須記住您可能使用的功能以及特定位置不支持的方法。
如果您還不夠,請讓我詳細(xì)說明。
延遲加載如何工作
簡而言之, 延遲加載允許您在加載父級時不加載子級。 僅當(dāng)您明確要求時才加載它們。
它是如何工作的? 讓我們看一個簡單的例子:
class User {private final Name name;@OneToMany(fetch = FetchType.LAZY)private List<Role> roles;@OneToMany(fetch = FetchType.LAZY)private List<Subscription> subscriptions;// Some more attributes and methods }此類的定義告訴您什么? FetchType.LAZY對我們意味著什么? 這為我們提供了包含用戶角色和訂閱的列表的信息,除非我們明確要求此類數(shù)據(jù),否則它們不會填充數(shù)據(jù)。
什么是有界上下文?
受限上下文是域驅(qū)動開發(fā)中的主要模式之一。 通過將它們分為不同的上下文,它可以幫助您使用大型域模型。 由于這個原因,您的域?qū)ο笞兊酶?#xff0c;應(yīng)用程序的業(yè)務(wù)邏輯變得更容易理解。
但是……為什么呢?
在前面的段落中,我寫了User類的定義告訴我們的內(nèi)容。 到現(xiàn)在為止,一切都與機制有關(guān)。 現(xiàn)在我們可以走得更遠(yuǎn)。
讓我們再來看一下我們的課:
class User {private final Name name;@OneToMany(fetch = FetchType.LAZY)private List<Role> roles;@OneToMany(fetch = FetchType.LAZY)private List<Subscription> subscriptions;// Some more attributes and methods }除了已經(jīng)提到的內(nèi)容之外,您能告訴我更多有關(guān)此對象的信息嗎?
我們知道我們正在使用其對象在可能需要但不一定需要角色的地方使用的類。 可能需要訂閱但不一定要訂閱的地方。 名稱始終是必需的。
我們知道在我們的應(yīng)用程序/環(huán)境中有一些功能/位置需要這些屬性,而在某些地方這些屬性是無用的。
但是……我們必須遍歷代碼才能找到那些地方。 這需要時間和精力。 不幸的是,我們還有機會錯過一些地方。
我們所知道的...我們所不知道的...
知道在哪里和需要什么會更好嗎? 當(dāng)然可以! 問題是:如何實現(xiàn)?
讓我們對示例進(jìn)行簡短分析:
class User {private final Name name;@OneToMany(fetch = FetchType.LAZY)private List<Role> roles;@OneToMany(fetch = FetchType.LAZY)private List<Subscription> subscriptions;// Some more attributes and methods }我們已經(jīng)知道一些事情:
- 名稱始終是必需的。
- 有時我們需要角色。
- 有時我們需要訂閱。
根據(jù)這些信息,我們可以添加另一件事– 我們知道我們并不總是需要所有這些信息 。 也許聽起來有些瑣碎,但這也很重要。
這就是信息。 現(xiàn)在是未知的時候了:
- 在哪里我們既需要角色又需要訂閱?
- 在不同的地方需要角色和訂閱嗎?
- 有沒有我們不需要的地方?
- 是否取決于上下文需要什么屬性?
未知數(shù)的問題在于,我們必須遍歷代碼才能找到答案。 但這還不是問題的終點。 當(dāng)您最終找到這些位置時,沒有方法或變量或任何可重命名的信息,不會在一段時間內(nèi)丟失此信息。 下次您將不得不重復(fù)該工作。
讓我們改進(jìn)代碼
由于上一段中列出了未知數(shù),因此更改現(xiàn)有代碼(真正的代碼)和我們正在使用的代碼并不容易。 這就是為什么我建議您在考慮延遲加載之后立即進(jìn)行此更改。 這是最便宜的改進(jìn)的正確時機。
好的,但是如何從示例中改進(jìn)代碼?
首先要做的是找到未知數(shù)的答案。 沒有這些答案,我們就無法前進(jìn)。 在我們的案例中,我將假設(shè)我們認(rèn)識到三種不同的情況:
- 身份驗證和授權(quán)是我們需要用戶名及其角色的地方。
- 我們在處理報告發(fā)送的地方需要用戶名及其訂閱。
- 在我們應(yīng)用程序的其他區(qū)域,我們既不需要角色也不需要訂閱。
現(xiàn)在,我們可以重構(gòu)User類并將其拆分為更容易理解的內(nèi)容:
class AuthUser {private final Name name;private List<Role> roles;// Some more attributes and methods }class ReportUser {private final Name name;private List<Subscription> subscriptions;// Some more attributes and methods }class ApplicationUser {private final Name name;// Some more attributes and methods }現(xiàn)在我們有了三個類,而不是一個,但是我們的代碼中也有更多信息。 我們無需遍歷代碼即可找出所需內(nèi)容和位置。 打開類的定義就足夠了
下一步是什么?
不幸的是,要在您的域中顯示狀態(tài),您必須付出很多努力。 為什么? 主要是因為未知。 應(yīng)用程序越大,獲取所有信息的難度就越大。 這就是為什么我鼓勵您在考慮將延遲加載作為解決方案之后立即拆分類。
如果您的域中已經(jīng)有延遲加載的引用,則應(yīng)僅重構(gòu)已經(jīng)使用的部分。 您將使更改的風(fēng)險和進(jìn)行更改所需的工作最小化。 無論如何,代碼將變得更具描述性。
祝好運!
翻譯自: https://www.javacodegeeks.com/2017/01/lazy-loading-code-smell.html
總結(jié)
以上是生活随笔為你收集整理的延迟加载是一种代码气味的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 侍魂安卓版下载(侍魂安卓)
- 下一篇: 房子备案后多久下房本有效(房子备案后多久