02 | 架構(gòu)分層:我們?yōu)槭裁匆欢ㄒ@么做逛钻?

在系統(tǒng)從 0 到 1 的階段,為了讓系統(tǒng)快速上線锰提,我們通常是不考慮分層的曙痘。 但是隨著業(yè)務(wù)的越來越復(fù)雜,大量的代碼糾纏在一起立肘,會(huì)出現(xiàn)邏輯不清晰边坤、各模塊相互依賴、代碼擴(kuò)展性差谅年、改動(dòng)一處就牽一發(fā)而動(dòng)全身等問題茧痒。

這時(shí),對(duì)系統(tǒng)進(jìn)行分層就會(huì)被提上日程融蹂,那么我們要如何對(duì)架構(gòu)進(jìn)行分層旺订?架構(gòu)分層和高并發(fā)架構(gòu)設(shè)計(jì)又有什么關(guān)系呢?本節(jié)課超燃,我將帶你尋找答案区拳。

什么是分層架構(gòu)

軟件架構(gòu)分層在軟件工程中是一種常見的設(shè)計(jì)方式,它是將整體系統(tǒng)拆分成 N 個(gè)層次意乓,每個(gè)層次有獨(dú)立的職責(zé)樱调,多個(gè)層次協(xié)同提供完整的功能。

我們?cè)趧倓偝蔀槌绦騿T的時(shí)候届良,會(huì)被“教育”說系統(tǒng)的設(shè)計(jì)要是“MVC”(Model-View-Controller)架構(gòu)本涕。它將整體的系統(tǒng)分成了 Model(模型),View(視圖)和 Controller(控制器)三個(gè)層次伙窃,也就是將用戶視圖和業(yè)務(wù)處理隔離開菩颖,并且通過控制器連接起來,很好地實(shí)現(xiàn)了表現(xiàn)和邏輯的解耦为障,是一種標(biāo)準(zhǔn)的軟件分層架構(gòu)晦闰。

img

另外一種常見的分層方式是將整體架構(gòu)分為表現(xiàn)層、邏輯層和數(shù)據(jù)訪問層:

  • 表現(xiàn)層鳍怨,顧名思義嘛呻右,就是展示數(shù)據(jù)結(jié)果和接受用戶指令的,是最靠近用戶的一層鞋喇;
  • 邏輯層里面有復(fù)雜業(yè)務(wù)的具體實(shí)現(xiàn)声滥;
  • 數(shù)據(jù)訪問層則是主要處理和存儲(chǔ)之間的交互。

這是在架構(gòu)上最簡單的一種分層方式。其實(shí)落塑,我們?cè)诓唤?jīng)意間已經(jīng)按照三層架構(gòu)來做系統(tǒng)分層設(shè)計(jì)了纽疟,比如在構(gòu)建項(xiàng)目的時(shí)候,我們通常會(huì)建立三個(gè)目錄:Web憾赁、Service 和 Dao污朽,它們分別對(duì)應(yīng)了表現(xiàn)層、邏輯層還有數(shù)據(jù)訪問層龙考。

img

除此之外蟆肆,如果我們稍加留意,就可以發(fā)現(xiàn)很多的分層的例子晦款。比如我們?cè)诖髮W(xué)中學(xué)到的 OSI 網(wǎng)絡(luò)模型炎功,它把整個(gè)網(wǎng)絡(luò)分了七層,自下而上分別是物理層缓溅、數(shù)據(jù)鏈路層亡问、網(wǎng)絡(luò)層、傳輸層肛宋、會(huì)話層州藕、表示層和應(yīng)用層。

工作中經(jīng)常能用到 TCP/IP 協(xié)議酝陈,它把網(wǎng)絡(luò)簡化成了四層床玻,即鏈路層、網(wǎng)絡(luò)層沉帮、傳輸層和應(yīng)用層锈死。每一層各司其職又互相幫助,網(wǎng)絡(luò)層負(fù)責(zé)端到端的尋址和建立連接穆壕,傳輸層負(fù)責(zé)端到端的數(shù)據(jù)傳輸?shù)却#瑫r(shí)相鄰兩層還會(huì)有數(shù)據(jù)的交互。這樣可以隔離關(guān)注點(diǎn)喇勋,讓不同的層專注做不同的事情缨该。

img

Linux 文件系統(tǒng)也是分層設(shè)計(jì)的,從下圖你可以清晰地看出文件系統(tǒng)的層次川背。在文件系統(tǒng)的最上層是虛擬文件系統(tǒng)(VFS)贰拿,用來屏蔽不同的文件系統(tǒng)之間的差異,提供統(tǒng)一的系統(tǒng)調(diào)用接口熄云。虛擬文件系統(tǒng)的下層是 Ext3膨更、Ext4 等各種文件系統(tǒng),再向下是為了屏蔽不同硬件設(shè)備的實(shí)現(xiàn)細(xì)節(jié)缴允,我們抽象出來的單獨(dú)的一層——通用塊設(shè)備層荚守,然后就是不同類型的磁盤了。

我們可以看到,某些層次負(fù)責(zé)的是對(duì)下層不同實(shí)現(xiàn)的抽象矗漾,從而對(duì)上層屏蔽實(shí)現(xiàn)細(xì)節(jié)锈候。比方說 VFS 對(duì)上層(系統(tǒng)調(diào)用層)來說提供了統(tǒng)一的調(diào)用接口,同時(shí)對(duì)下層中不同的文件系統(tǒng)規(guī)約了實(shí)現(xiàn)模型缩功,當(dāng)新增一種文件系統(tǒng)實(shí)現(xiàn)的時(shí)候晴及,只需要按照這種模型來設(shè)計(jì)都办,就可以無縫插入到 Linux 文件系統(tǒng)中嫡锌。

img

那么,為什么這么多系統(tǒng)一定要做分層的設(shè)計(jì)呢琳钉?答案是分層設(shè)計(jì)存在一定的優(yōu)勢(shì)势木。

分層有什么好處

分層的設(shè)計(jì)可以簡化系統(tǒng)設(shè)計(jì),讓不同的人專注做某一層次的事情歌懒。想象一下啦桌,如果你要設(shè)計(jì)一款網(wǎng)絡(luò)程序卻沒有分層,該是一件多么痛苦的事情及皂。

因?yàn)槟惚仨毷且粋€(gè)通曉網(wǎng)絡(luò)的全才甫男,要知道各種網(wǎng)絡(luò)設(shè)備的接口是什么樣的,以便可以將數(shù)據(jù)包發(fā)送給它验烧。你還要關(guān)注數(shù)據(jù)傳輸?shù)募?xì)節(jié)板驳,并且需要處理類似網(wǎng)絡(luò)擁塞,數(shù)據(jù)超時(shí)重傳這樣的復(fù)雜問題碍拆。當(dāng)然了若治,你更需要關(guān)注數(shù)據(jù)如何在網(wǎng)絡(luò)上安全傳輸,不會(huì)被別人窺探和篡改感混。

而有了分層的設(shè)計(jì)端幼,你只需要專注設(shè)計(jì)應(yīng)用層的程序就可以了,其他都可以交給下面幾層來完成弧满。

再有婆跑,分層之后可以做到很高的復(fù)用。比如庭呜,我們?cè)谠O(shè)計(jì)系統(tǒng) A 的時(shí)候洽蛀,發(fā)現(xiàn)某一層具有一定的通用性,那么我們可以把它抽取獨(dú)立出來疟赊,在設(shè)計(jì)系統(tǒng) B 的時(shí)候使用起來郊供,這樣可以減少研發(fā)周期,提升研發(fā)的效率近哟。

最后一點(diǎn)驮审,分層架構(gòu)可以讓我們更容易做橫向擴(kuò)展。如果系統(tǒng)沒有分層,當(dāng)流量增加時(shí)我們需要針對(duì)整體系統(tǒng)來做擴(kuò)展疯淫。但是地来,如果我們按照上面提到的三層架構(gòu)將系統(tǒng)分層后,就可以針對(duì)具體的問題來做細(xì)致的擴(kuò)展熙掺。

比如說未斑,業(yè)務(wù)邏輯里面包含有比較復(fù)雜的計(jì)算,導(dǎo)致 CPU 成為性能的瓶頸币绩,那這樣就可以把邏輯層單獨(dú)抽取出來獨(dú)立部署蜡秽,然后只對(duì)邏輯層來做擴(kuò)展,這相比于針對(duì)整體系統(tǒng)擴(kuò)展所付出的代價(jià)就要小的多了缆镣。

這一點(diǎn)也可以解釋我們課程開始時(shí)提出的問題:架構(gòu)分層究竟和高并發(fā)設(shè)計(jì)的關(guān)系是怎樣的芽突?在“01 | 高并發(fā)系統(tǒng):它的通用設(shè)計(jì)方法是什么?”中我們了解到董瞻,橫向擴(kuò)展是高并發(fā)系統(tǒng)設(shè)計(jì)的常用方法之一寞蚌,既然分層的架構(gòu)可以為橫向擴(kuò)展提供便捷, 那么支撐高并發(fā)的系統(tǒng)一定是分層的系統(tǒng)钠糊。

如何來做系統(tǒng)分層

說了這么多分層的優(yōu)點(diǎn)挟秤,那么當(dāng)我們要做分層設(shè)計(jì)的時(shí)候,需要考慮哪些關(guān)鍵因素呢抄伍?

在我看來艘刚,最主要的一點(diǎn)就是你需要理清楚每個(gè)層次的邊界是什么。你也許會(huì)問:“如果按照三層架構(gòu)來分層的話逝慧,每一層的邊界不是很容易就界定嗎昔脯?”

沒錯(cuò),當(dāng)業(yè)務(wù)邏輯簡單時(shí)笛臣,層次之間的邊界的確清晰云稚,開發(fā)新的功能時(shí)也知道哪些代碼要往哪兒寫。但是當(dāng)業(yè)務(wù)邏輯變得越來越復(fù)雜時(shí)沈堡,邊界就會(huì)變得越來越模糊静陈,給你舉個(gè)例子。

任何一個(gè)系統(tǒng)中都有用戶系統(tǒng)诞丽,最基本的接口是返回用戶信息的接口鲸拥,它調(diào)用邏輯層的 GetUser 方法,GetUser 方法又和 User DB 交互獲取數(shù)據(jù)僧免,就像下圖左邊展示的樣子刑赶。

這時(shí),產(chǎn)品提出一個(gè)需求懂衩,在 APP 中展示用戶信息的時(shí)候撞叨,如果用戶不存在金踪,那么要自動(dòng)給用戶創(chuàng)建一個(gè)用戶。同時(shí)牵敷,要做一個(gè) HTML5 的頁面胡岔,HTML5 頁面要保留之前的邏輯,也就是不需要?jiǎng)?chuàng)建用戶枷餐。這時(shí)邏輯層的邊界就變得不清晰靶瘸,表現(xiàn)層也承擔(dān)了一部分的業(yè)務(wù)邏輯(將獲取用戶和創(chuàng)建用戶接口編排起來)。

img

那我們要如何做呢毛肋?參照阿里發(fā)布的《阿里巴巴 Java 開發(fā)手冊(cè) v1.4.0(詳盡版)》怨咪,我們可以將原先的三層架構(gòu)細(xì)化成下面的樣子:

img

我來解釋一下這個(gè)分層架構(gòu)中的每一層的作用。

  • 終端顯示層:各端模板渲染并執(zhí)行顯示的層村生。當(dāng)前主要是 Velocity 渲染惊暴,JS 渲染饼丘, JSP 渲染趁桃,移動(dòng)端展示等。

  • 開放接口層:將 Service 層方法封裝成開放接口肄鸽,同時(shí)進(jìn)行網(wǎng)關(guān)安全控制和流量控制等卫病。

  • Web 層:主要是對(duì)訪問控制進(jìn)行轉(zhuǎn)發(fā),各類基本參數(shù)校驗(yàn)典徘,或者不復(fù)用的業(yè)務(wù)簡單處理等蟀苛。

  • Service 層:業(yè)務(wù)邏輯層。

  • Manager 層:通用業(yè)務(wù)處理層逮诲。這一層主要有兩個(gè)作用帜平,其一,你可以將原先 Service 層的一些通用能力下沉到這一層梅鹦,比如與緩存和存儲(chǔ)交互策略裆甩,中間件的接入;其二齐唆,你也可以在這一層封裝對(duì)第三方接口的調(diào)用嗤栓,比如調(diào)用支付服務(wù),調(diào)用審核服務(wù)等箍邮。

  • DAO 層:數(shù)據(jù)訪問層茉帅,與底層 MySQL、Oracle锭弊、HBase 等進(jìn)行數(shù)據(jù)交互堪澎。

  • 外部接口或第三方平臺(tái):包括其它部門 RPC 開放接口,基礎(chǔ)平臺(tái)味滞,其它公司的 HTTP 接口樱蛤。

在這個(gè)分層架構(gòu)中主要增加了 Manager 層马昙,它與 Service 層的關(guān)系是:Manager 層提供原子的服務(wù)接口,Service 層負(fù)責(zé)依據(jù)業(yè)務(wù)邏輯來編排原子接口刹悴。

以上面的例子來說行楞,Manager 層提供創(chuàng)建用戶和獲取用戶信息的接口,而 Service 層負(fù)責(zé)將這兩個(gè)接口組裝起來土匀。這樣就把原先散布在表現(xiàn)層的業(yè)務(wù)邏輯都統(tǒng)一到了 Service 層子房,每一層的邊界就非常清晰了。

除此之外就轧,分層架構(gòu)需要考慮層次之間一定是相鄰層互相依賴证杭,數(shù)據(jù)的流轉(zhuǎn)也只能在相鄰的兩層之間流轉(zhuǎn)。

我們還是以三層架構(gòu)為例妒御,數(shù)據(jù)從表示層進(jìn)入之后一定要流轉(zhuǎn)到邏輯層解愤,做業(yè)務(wù)邏輯處理,然后流轉(zhuǎn)到數(shù)據(jù)訪問層來和數(shù)據(jù)庫交互乎莉。那么你可能會(huì)問:“如果業(yè)務(wù)邏輯很簡單的話可不可以從表示層直接到數(shù)據(jù)訪問層送讲,甚至直接讀數(shù)據(jù)庫呢?”

其實(shí)從功能上是可以的惋啃,但是從長遠(yuǎn)的架構(gòu)設(shè)計(jì)考慮哼鬓,這樣會(huì)造成層級(jí)調(diào)用的混亂,比方說如果表示層或者業(yè)務(wù)層可以直接操作數(shù)據(jù)庫边灭,那么一旦數(shù)據(jù)庫地址發(fā)生變更异希,你就需要在多個(gè)層次做更改,這樣就失去了分層的意義绒瘦,并且對(duì)于后面的維護(hù)或者重構(gòu)都會(huì)是災(zāi)難性的称簿。

分層架構(gòu)的不足

任何事物都不可能是盡善盡美的,分層架構(gòu)雖有優(yōu)勢(shì)也會(huì)有缺陷惰帽,它最主要的一個(gè)缺陷就是增加了代碼的復(fù)雜度憨降。

這是顯而易見的嘛,明明可以在接收到請(qǐng)求后就可以直接查詢數(shù)據(jù)庫獲得結(jié)果善茎,卻偏偏要在中間插入多個(gè)層次券册,并且有可能每個(gè)層次只是簡單地做數(shù)據(jù)的傳遞。有時(shí)增加一個(gè)小小的需求也需要更改所有層次上的代碼垂涯,看起來增加了開發(fā)的成本烁焙,并且從調(diào)試上來看也增加了復(fù)雜度,原本如果直接訪問數(shù)據(jù)庫我只需要調(diào)試一個(gè)方法耕赘,現(xiàn)在我卻要調(diào)試多個(gè)層次的多個(gè)方法骄蝇。

另外一個(gè)可能的缺陷是,如果我們把每個(gè)層次獨(dú)立部署操骡,層次間通過網(wǎng)絡(luò)來交互九火,那么多層的架構(gòu)在性能上會(huì)有損耗赚窃。這也是為什么服務(wù)化架構(gòu)性能要比單體架構(gòu)略差的原因,也就是所謂的“多一跳”問題岔激。

那我們是否要選擇分層的架構(gòu)呢勒极?答案當(dāng)然是肯定的。

你要知道虑鼎,任何的方案架構(gòu)都是有優(yōu)勢(shì)有缺陷的辱匿,天地尚且不全何況我們的架構(gòu)呢?分層架構(gòu)固然會(huì)增加系統(tǒng)復(fù)雜度炫彩,也可能會(huì)有性能的損耗匾七,但是相比于它能帶給我們的好處來說,這些都是可以接受的江兢,或者可以通過其它的方案解決的昨忆。我們?cè)谧鰶Q策的時(shí)候切不可以偏概全,因噎廢食杉允。

課程小結(jié)

今天我?guī)е懔私饬朔謱蛹軜?gòu)的優(yōu)勢(shì)和不足邑贴,以及我們?cè)趯?shí)際工作中如何來對(duì)架構(gòu)做分層。我想讓你了解的是夺颤,分層架構(gòu)是軟件設(shè)計(jì)思想的外在體現(xiàn)痢缎,是一種實(shí)現(xiàn)方式胁勺。我們熟知的一些軟件設(shè)計(jì)原則都在分層架構(gòu)中有所體現(xiàn)世澜。

比方說,單一職責(zé)原則規(guī)定每個(gè)類只有單一的功能署穗,在這里可以引申為每一層擁有單一職責(zé)寥裂,且層與層之間邊界清晰;迪米特法則原意是一個(gè)對(duì)象應(yīng)當(dāng)對(duì)其它對(duì)象有盡可能少的了解案疲,在分層架構(gòu)的體現(xiàn)是數(shù)據(jù)的交互不能跨層封恰,只能在相鄰層之間進(jìn)行;而開閉原則要求軟件對(duì)擴(kuò)展開放褐啡,對(duì)修改關(guān)閉诺舔。它的含義其實(shí)就是將抽象層和實(shí)現(xiàn)層分離,抽象層是對(duì)實(shí)現(xiàn)層共有特征的歸納總結(jié)备畦,不可以修改低飒,但是具體的實(shí)現(xiàn)是可以無限擴(kuò)展,隨意替換的懂盐。

掌握這些設(shè)計(jì)思想會(huì)自然而然地明白分層架構(gòu)設(shè)計(jì)的妙處褥赊,同時(shí)也能幫助我們做出更好的設(shè)計(jì)方案。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末莉恼,一起剝皮案震驚了整個(gè)濱河市拌喉,隨后出現(xiàn)的幾起案子速那,更是在濱河造成了極大的恐慌,老刑警劉巖尿背,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件端仰,死亡現(xiàn)場離奇詭異,居然都是意外死亡田藐,警方通過查閱死者的電腦和手機(jī)榆俺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坞淮,“玉大人茴晋,你說我怎么就攤上這事』鼐剑” “怎么了诺擅?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長啡直。 經(jīng)常有香客問我烁涌,道長,這世上最難降的妖魔是什么酒觅? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任撮执,我火速辦了婚禮,結(jié)果婚禮上舷丹,老公的妹妹穿的比我還像新娘抒钱。我一直安慰自己,他們只是感情好颜凯,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布谋币。 她就那樣靜靜地躺著,像睡著了一般症概。 火紅的嫁衣襯著肌膚如雪蕾额。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天彼城,我揣著相機(jī)與錄音诅蝶,去河邊找鬼。 笑死募壕,一個(gè)胖子當(dāng)著我的面吹牛调炬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播司抱,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼筐眷,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了习柠?” 一聲冷哼從身側(cè)響起匀谣,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤照棋,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后武翎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體烈炭,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年宝恶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了符隙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡垫毙,死狀恐怖霹疫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情综芥,我是刑警寧澤丽蝎,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站膀藐,受9級(jí)特大地震影響屠阻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜额各,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一国觉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虾啦,春花似錦麻诀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至需频,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間筷凤,已是汗流浹背昭殉。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留藐守,地道東北人挪丢。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像卢厂,于是被迫代替她去往敵國和親乾蓬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • 最近再看阮一峰的一篇博客提到了一本書《Software Architecture Patterns》(PDF),寫...
    卓_然閱讀 7,722評(píng)論 0 22
  • 1.從傳統(tǒng)三層架構(gòu)與DDD分層架構(gòu)的編程演變其實(shí)是思想的演變慎恒。 傳統(tǒng)三層架構(gòu)任内,即用戶界面層UI撵渡、業(yè)務(wù)邏輯層BAL、...
    咖啡電視閱讀 8,179評(píng)論 0 6
  • 一死嗦、生命周期 一個(gè)事物一旦出生趋距,就必然會(huì)長大,變異越除,一旦長大节腐,就面臨著衰老,接下來就是消亡了摘盆,這個(gè)過程就稱為一個(gè)事...
    ZyBlog閱讀 2,657評(píng)論 1 11
  • 第三章 數(shù)據(jù)庫系統(tǒng) 3.1 數(shù)據(jù)庫管理系統(tǒng)的類型 通常有多個(gè)分類標(biāo)準(zhǔn)翼雀。如按數(shù)據(jù)模型分類、按用戶數(shù)分類孩擂、按數(shù)據(jù)庫分布...
    步積閱讀 2,689評(píng)論 0 7
  • 昨天回來家里锅纺,晚上一直在喂蚊子。瞌睡的忍不可忍肋殴,咬的忍無可忍囤锉,抱著無需再忍的心態(tài),我躍身而起护锤,徒手屠殺這兩只嗜血鬼...
    奔跑的屎殼郎君閱讀 168評(píng)論 1 2