記得第一次跳槽的時候凝危,到招聘網(wǎng)站上翻看各種初級工程師的招聘要求波俄,都會有意無意的加上一句:具有良好的面向對象思維。當時心里很不屑蛾默,面向對象無非就是"繼承懦铺,多態(tài),封裝"嘛支鸡。直到工作了很多年之后冬念,看了很多書之后,越來越覺得當時的想法有點low了牧挣,剛好前一段時間和朋友聊到日常開發(fā)中有些設計的優(yōu)劣急前,有些心得,想把它記錄下來瀑构,遂有此文裆针。
面試別人的時候,我偶爾會問一個問題:請用一句話來描述何為restful寺晌。對于這個問題据块,面試者答得各式各樣,其實在我心里的答案就是:restful就是用路徑定位資源折剃,用get/post/put/delete操作資源。說白了像屋,restful最核心的概念并不是url樣式或者get/post方法而是資源怕犁。何為資源?這個就是你的應用上的領域對象了己莺。在互聯(lián)網(wǎng)企業(yè)中奏甫,現(xiàn)在很少有人再用hibernate/jpa了,其實熟悉jpa的人對restful有一種天生的親近感凌受,它們天然的描述了對象之間的關系阵子,可以這樣說,restful是面向對象思想在api設計上的一種體現(xiàn)胜蛉,所以風格自由挠进,兼容性更好,觀之就能理解業(yè)務對象之間的關系誊册。很多人推崇的代碼即文檔领突,不過如是。
即便我對hibernate如此推崇案怯,也只是相對日常開發(fā)中最常用的mybatis來講的君旦,在更極致的面向對象設計理念中,hibernate所代表的設計風格,只是一種貧血設計模型金砍。因為萬事萬物局蚀,不可能只有狀態(tài)而沒有行為,通俗來講恕稠,就是不可能只有屬性琅绅,而沒有方法(get/set不算)。舉一個簡單的例子
public class Person{
int age;// 年齡
String name; // 姓名
String idCard; // 身份證號
GENDERS gender; // 性別
Person partner; // 伴侶
enum GENDERS{
MALE,FEMALE;
}
// 和某人結婚
void marriadWith(Person somebody){
if(this.gender.equals(somebody.gender)){
throw new IllegalStateException("不能和同性結婚")
}
if(this.age<18 || somebody.age<18){
throw new IllegalStateException("未成年人不能結婚")
}
this.partner=somebody;
somebody.partner=this;
}
}
如上所示谱俭,這才是一個完整體現(xiàn)了面向對象思想的代碼設計奉件。可能從事企業(yè)開發(fā)的朋友們對這種寫法會嗤之以鼻昆著,因為——這個例子沒有數(shù)據(jù)庫操作县貌。
誠然,因為我們沒有無限的內存凑懂,導致我們業(yè)務對象的生命周期的大部分時間都是以另一種形態(tài)靜靜躺在數(shù)據(jù)庫中煤痕,而且由于數(shù)據(jù)庫的各種設計特性,會割裂我們最接近現(xiàn)實的設計接谨。比如上面的例子摆碉,在數(shù)據(jù)庫里面存的可能是
create table t_person(
age int,
name varchar(64),
id_card varchar(32),
gender smallint,
partner_id_card varchar(32),
primary key id_card
)
很多朋友喜歡先設計數(shù)據(jù)庫,然后通過mybatis官方提供的generator反向生成對應的業(yè)務實體脓豪,但是很不幸巷帝,大多數(shù)互聯(lián)網(wǎng)公司都是禁止使用外鍵的,這就導致了我們的業(yè)務實體成了下面的樣子
public class Person{
int age;// 年齡
String name; // 姓名
String idCard; // 身份證號
int gender; // 性別
String partnerIdCard; // 伴侶
}
好了扫夜,我們辛辛苦苦挖出來的領域知識被消磨殆盡了楞泼。
這就是我為什么如此厭惡mybatis和generator了。我厭惡的并不是這兩項技術笤闯,而是厭惡的這種設計方式湮滅了我們的領域知識堕阔,讓我們進一步學習業(yè)務領域,改進設計方案的可能無限趨近于零了颗味。
在這里超陆,我再次鄭重推薦一種設計方法,就是架構師們常常掛在嘴邊的DDD浦马,全稱是領域驅動設計时呀,我稱之為面向對象思想在企業(yè)開發(fā)中的落地方案。這篇文章不是專門介紹ddd的晶默,就不詳細介紹了退唠。
面向對象的"繼承,多態(tài)荤胁,封裝"三大特征里面瞧预,只要熟練使用設計模式基本上對繼承和多態(tài)就能有足夠的認識了屎债,但是"封裝"這兩個字,卻沒那么容易垢油,很多設計上的缺陷就是由"封裝"認識不足引發(fā)的盆驹。
在Java企業(yè)開發(fā)工作中,很多項目都會按照controller/entity/service/dao這樣的職責進行代碼的劃分滩愁,好像這樣就做到了"分層"躯喇。剛工作的時候硝枉,我也是這種劃分方式的擁躉,到后來越來越覺得這種劃分方式不科學妻味。首先,并不是所有的代碼調用都會從controller到dao责球,也不是所有的controller都會以來entity焦履,按照這種劃分方式寫,猶如八股文一樣繁瑣并且又臭又長雏逾。再者,被分在同一個包中的controller很少有互相調用栖博,dao更不會互相調用,相反仇让,被分在不同的模塊中的XXXController常常會依賴XXXEntity侨把,再通過XXXService調用XXXDao簡直就像呼吸一樣頻繁,這就形成了不同模塊之間的高耦合相同模塊之間的低內聚妹孙,也不能遵循相同模塊共同發(fā)布的原則,簡直就是一個大泥團获枝。這是對面向對象思想的封裝思想嚴重的認識不足,這種情況高級程序員乃至很多架構師亦不能免俗省店,大概是習慣使然吧。
最近在讀一本小說雹舀,小說中把"道"和"術"分別比喻成路和腳粗俱。誠然说榆,如果沒有技術我們就沒法去開發(fā),但是如果沒有設計思想签财,就會我們迷失方向,最終導致我們的代碼一團亂麻邦鲫,甚至會導致項目失敗神汹。在我們日常開發(fā)中 ,我們心里應該有一條準繩屁魏,什么樣的技術可以用,以及技術如何使用都應該在心里過一遍蚁堤。做程序員的固然要不斷學習,但世上技術千千萬撬即,我們只需要學有用的就夠了呈队,什么樣的技術有用剥槐,一旦心里有一條準繩宪摧,自然會知道。