一灭忠、前言
如果你學(xué)習(xí)過(guò)其他語(yǔ)言或者接觸過(guò)其它語(yǔ)言的開(kāi)發(fā)人員,你會(huì)發(fā)現(xiàn)Java開(kāi)發(fā)人員好像更加傾向于過(guò)度設(shè)計(jì)肥败。
也許是因?yàn)镴ava開(kāi)發(fā)比較傳統(tǒng)趾浅,也許是因?yàn)檫@是你的老師(教學(xué)視頻、教學(xué)文檔)教過(guò)你的馒稍。我在檢查自己之前的代碼的時(shí)候發(fā)現(xiàn)皿哨,盡管我盡量會(huì)在編寫(xiě)代碼時(shí)不過(guò)度設(shè)計(jì),但是總歸會(huì)有許多不當(dāng)?shù)牡胤健?/p>
當(dāng)然纽谒,你可能認(rèn)為证膨,你只是一個(gè)“初級(jí)”的開(kāi)發(fā)人員,只有架構(gòu)師才資格設(shè)計(jì)鼓黔,所以只有他們才能承擔(dān)過(guò)度工程的責(zé)任央勒,對(duì)嗎?恐怕并非如此澳化,無(wú)數(shù)的開(kāi)發(fā)人員一直都在這樣做崔步。在本文中,我將重點(diǎn)一個(gè)過(guò)度設(shè)計(jì)的癥狀缎谷,并將其擴(kuò)展到其他方面井濒。
二、過(guò)度設(shè)計(jì)
我在學(xué)生時(shí)期列林,我曾試圖設(shè)計(jì)我的班級(jí)層次結(jié)構(gòu)瑞你,并使其盡可能地可擴(kuò)展,所以將它轉(zhuǎn)換為由具體類(lèi)實(shí)現(xiàn)的父接口希痴。它們之間可能只有一個(gè)抽象類(lèi)者甲。像下面的圖:
這看起來(lái)非常完美,構(gòu)成了可擴(kuò)展的層次結(jié)構(gòu)润梯,并且實(shí)現(xiàn)了面向接口編程过牙。
在 Spring 的生態(tài)環(huán)境中,大量使用了類(lèi)似這種形式的設(shè)計(jì)方案纺铭。例如 ViewResolver 接口寇钉,它具有豐富的子級(jí)層次結(jié)構(gòu)和非常多的實(shí)現(xiàn)類(lèi)。(例如:InternalResourceViewResolver舶赔、VelocityLayoutViewResolver)扫倡。在框架的其他部分也有非常多的示例(beanFactory、ApplicationContext)。
但是撵溃,要明白的一些重點(diǎn)是:
- Spring 在層次化的結(jié)構(gòu)設(shè)計(jì)中組織了許多不同的子類(lèi)疚鲤。
- Spring 是一個(gè)框架,框架的含義是可擴(kuò)展缘挑,不可修改集歇。
在我們寫(xiě)過(guò)的大多數(shù) Spring Web 程序中。找到我們定義的接口(Controller语淘、Service诲宇、Dao),會(huì)發(fā)現(xiàn)惶翻,大多數(shù)情況下姑蓝,他們的實(shí)現(xiàn)類(lèi)只有一個(gè),而且可能會(huì)用 Impl 為后綴吕粗。如果接口位于 xyz 包中纺荧,那么實(shí)現(xiàn)類(lèi)就會(huì)在 xyz.impl 包中,不知道大家會(huì)不會(huì)對(duì)與此種設(shè)計(jì)感到好奇颅筋?為什么要這樣做宙暇?我們很難為接口的實(shí)現(xiàn)類(lèi)提供一個(gè)相關(guān)的名稱(chēng),因?yàn)閷?shí)現(xiàn)類(lèi)和接口之間沒(méi)有語(yǔ)義上的區(qū)別议泵,即實(shí)現(xiàn)類(lèi)沒(méi)有專(zhuān)門(mén)化接口客给。基于此得出的結(jié)論是:這種接口不是必須的肢簿。
一些高級(jí)開(kāi)發(fā)人員可能會(huì)說(shuō):“即便現(xiàn)在沒(méi)有用靶剑,抽象設(shè)計(jì)在以后也有用!”池充。但是桩引,為了將來(lái)的可能會(huì)有用這一點(diǎn)而在現(xiàn)在加入了一堆不必要的東西,只會(huì)浪費(fèi)前期時(shí)間收夸,而且對(duì)于大多數(shù)的 Web 程序來(lái)說(shuō)坑匠,以后也不會(huì)有用。這種設(shè)計(jì)方法無(wú)疑與敏捷開(kāi)發(fā)相沖突卧惜。
當(dāng)然厘灼,即使在以后真的有這種需求了,借助現(xiàn)代 IDE 的重構(gòu)功能咽瓷,也可以很方便的修改程序设凹。
早期的 Spring 動(dòng)態(tài)代理只有 JDK 的動(dòng)態(tài)代理,新版本的 Spring 早已經(jīng)支持了 cglib 代理方式茅姜,所以創(chuàng)建一個(gè)接口只是為了可以實(shí)現(xiàn)動(dòng)態(tài)代理這方面也是不成立的闪朱。
三、后記
如果有人說(shuō)我設(shè)計(jì)接口就是為了未來(lái)做準(zhǔn)備,那我我就非要說(shuō)你這是過(guò)度設(shè)計(jì)奋姿。
無(wú)用的接口只是過(guò)度設(shè)計(jì)的一個(gè)方面锄开,另外的許許多多方面都有過(guò)度設(shè)計(jì)的影子,這是 Java 開(kāi)發(fā)的特性称诗,無(wú)法改變萍悴。