聊聊程序設(shè)計(jì)思想之面向接口編程IOP

前言

我們?cè)谝话銓?shí)現(xiàn)一個(gè)系統(tǒng)的時(shí)候闸溃,通常是將定義與實(shí)現(xiàn)合為一體胯努,不加分離的东臀,但是有時(shí)候最為理想的系統(tǒng)設(shè)計(jì)規(guī)范應(yīng)是所有的定義與實(shí)現(xiàn)分離,盡管這可能對(duì)系統(tǒng)中的某些情況有點(diǎn)麻煩。

在一個(gè)面向?qū)ο蟮南到y(tǒng)中龄广,系統(tǒng)的各種功能是由許許多多的不同對(duì)象協(xié)作完成的硫眯。在這種情況下,各個(gè)對(duì)象內(nèi)部是如何實(shí)現(xiàn)自己的,對(duì)系統(tǒng)設(shè)計(jì)人員來(lái)講就不那么重要了择同;而各個(gè)對(duì)象之間的協(xié)作關(guān)系則成為系統(tǒng)設(shè)計(jì)的關(guān)鍵两入。小到不同類之間的通信,大到各模塊之間的交互敲才,在系統(tǒng)設(shè)計(jì)之初都是要著重考慮的裹纳,這也是系統(tǒng)設(shè)計(jì)的主要工作內(nèi)容。面向接口編程就是指按照這種思想來(lái)編程归斤。

關(guān)于接口的理解

接口從更深層次的理解痊夭,應(yīng)是定義(規(guī)范,約束)與實(shí)現(xiàn)(名實(shí)分離的原則)的分離脏里。
接口的本身反映了系統(tǒng)設(shè)計(jì)人員對(duì)系統(tǒng)的抽象理解。
接口應(yīng)有兩類:
    第一類是對(duì)一個(gè)體的抽象虹曙,它可對(duì)應(yīng)為一個(gè)抽象體(abstract class)迫横;
    第二類是對(duì)一個(gè)體某一方面的抽象,即形成一個(gè)抽象面(interface)酝碳;

依賴注入(Dependency Injection)

說(shuō)到面向接口編程矾踱,我覺(jué)得還是有必要說(shuō)下依賴注入這個(gè)概念硫痰,下面舉下網(wǎng)上很多文章都在舉的例子來(lái)說(shuō)明下:

 我們有一個(gè)公交車(chē)類(Bus)访忿,每天早上6點(diǎn)鐘需要發(fā)車(chē)(work)煤蹭,為其分配對(duì)應(yīng)的司機(jī)(Driver)毕莱,看代碼

@implementation Bus
- (void)work {
    Driver *driver = [[Driver alloc] initWithName:@"張三"];
    //dosomething
}
@end

在上面這段代碼中储耐,Bus對(duì)象的運(yùn)作需要用到Driver對(duì)象动分,因而創(chuàng)建了一個(gè)Driver對(duì)象郑气,我們稱Bus對(duì)Driver有一個(gè)依賴怠堪。這樣的強(qiáng)耦合關(guān)系會(huì)因?yàn)槿蘸蟮淖兓o我們帶來(lái)很多麻煩芽偏,不久將來(lái)張三師傅辭職了雷逆,我們需要修改Bus-work()的代碼,也就是說(shuō)在開(kāi)發(fā)過(guò)程中非常不便于單元測(cè)試(一是不能方便地更換各種Driver對(duì)象污尉,二是如果Driver這個(gè)職位創(chuàng)建是耗時(shí)操作或者高成本操作膀哲,我們并不能使用準(zhǔn)備好的Driver實(shí)現(xiàn)快速重復(fù)測(cè)試)。 我們繼續(xù):

@implementation Bus

@property (strong, nonatomic) Driver *driver;
- (instancetype)initWithDriver:(Driver *)driver {
    self = [super init];
    if (self) {
        self.dirver = driver;
    }
    return self;
}
- (void)work {
    //dosomething
}
@end

以上這段代碼我們通過(guò)init方法被碗,為Bus對(duì)象傳入了一個(gè)Driver對(duì)象某宪,像這種非自己主動(dòng)初始化依賴,而從外部通過(guò)注入點(diǎn)注入依賴的方式锐朴,我們就稱為依賴注入兴喂,而例子中的這種注入的方法稱之為構(gòu)造器注入。明顯的,這個(gè)場(chǎng)景中Bus和Driver的耦合因此輕了一層瞻想。說(shuō)到解耦压真,并不是說(shuō)Bus和Driver之間的依賴關(guān)系就不存在了,在Bus的范圍內(nèi)看來(lái)蘑险,只是將依賴建立從編譯期間推遲到了運(yùn)行期間滴肿,畢竟Bus無(wú)論如何也是需要Driver提供服務(wù)的。對(duì)此佃迄,這篇文章有一個(gè)非常形象的比喻泼差,“依賴就像是系統(tǒng)中的 plugin (插件),主系統(tǒng)并不強(qiáng)依賴于任何一個(gè)插件呵俏,但一旦插件被加載堆缘,主系統(tǒng)就應(yīng)該可以準(zhǔn)確調(diào)用適當(dāng)插件的功能”。

類似這樣的注入方式還有

*   屬性注入
*   方法注入
*   環(huán)境上下文注入
*   子類重寫(xiě)方法注入等

不同的只是注入的手段普碎,思想還是一樣的吼肥。

實(shí)際開(kāi)發(fā)中的實(shí)例展示

下面文中用到這個(gè)例子和代碼來(lái)著這篇文章,我覺(jué)得文章中的這個(gè)例子很有啟發(fā)性麻车,所以加上了一些自己的理解進(jìn)去缀皱,想看原文的可以點(diǎn)進(jìn)進(jìn)入閱讀原著。

MVP模式雖然能解決許多MVC模式下存在的問(wèn)題动猬,但對(duì)于比較復(fù)雜的需求啤斗,
還是會(huì)存在邏輯過(guò)于復(fù)雜,Presenter層也出現(xiàn)難以維護(hù)的問(wèn)題赁咙。下面我們就通過(guò)一個(gè)實(shí)際的例子钮莲,
來(lái)看看面對(duì)復(fù)雜的業(yè)務(wù)邏輯,我們應(yīng)該如何去設(shè)計(jì)和實(shí)現(xiàn)彼水。

很多復(fù)雜的需求崔拥,在最初都是從一個(gè)簡(jiǎn)單的場(chǎng)景,一步步往上增加功能猿涨。
在這個(gè)過(guò)程中握童,如果不持續(xù)的進(jìn)行優(yōu)化和重構(gòu),到最后就成了所謂的"只有上帝能看懂的代碼"叛赚。說(shuō)了這么多澡绩,進(jìn)入正題,來(lái)看這個(gè)需求俺附。
V1.0 單文件上傳

實(shí)現(xiàn)一個(gè)簡(jiǎn)單的單文件上傳肥卡,文件的索引存儲(chǔ)在數(shù)據(jù)庫(kù)中,文件存儲(chǔ)在App的沙箱里面事镣。這個(gè)應(yīng)該對(duì)于有經(jīng)驗(yàn)的客戶端開(kāi)發(fā)者來(lái)說(shuō)是小菜一碟步鉴,比較簡(jiǎn)單也容易實(shí)現(xiàn)。我們可以把這個(gè)需求大致拆分成以下幾個(gè)子需求

  1. 初始化上傳View
  2. 更新上傳View
  3. 點(diǎn)擊上傳按鈕事件
  4. 數(shù)據(jù)庫(kù)中獲取上傳模型
  5. 發(fā)起HTTP請(qǐng)求上傳文件
  6. 檢查網(wǎng)絡(luò)狀態(tài)

以上幾項(xiàng)如果使用傳統(tǒng)的MVC模式,實(shí)現(xiàn)起來(lái)如下圖所示

MVC

我們可以看到上述需求基本都直接在UploadViewController中實(shí)現(xiàn)氛琢,目前需求還是比較簡(jiǎn)單的情形下面喊递,還是勉強(qiáng)能夠接受,也不需要更多的思考阳似。如果使用MVP的模式進(jìn)行優(yōu)化骚勘,如下圖所示

MVP.png

現(xiàn)在UploadPresenter負(fù)責(zé)處理上傳邏輯了,而UploadViewController專注于UI更新和事件傳遞撮奏,整體的結(jié)構(gòu)更加清晰俏讹,以后維護(hù)代碼也會(huì)比較方便。

V2.0 多文件上傳

需求來(lái)了畜吊!需要在原來(lái)的基礎(chǔ)上支持多文件上傳泽疆,意味著我們多了一個(gè)子需求

  1. 維護(hù)上傳模型隊(duì)列

很顯然,我們需要在UploadPresenter中增加一個(gè)維護(hù)上傳隊(duì)列的功能玲献,最初我也確實(shí)是這樣實(shí)現(xiàn)的殉疼,但是由于文件上傳需要監(jiān)聽(tīng)的事件比較多,回調(diào)也比較頻繁青自,直接在Presenter中繼續(xù)寫(xiě)這樣的邏輯代碼株依,已經(jīng)成倍增加了代碼的復(fù)雜性。

所以經(jīng)過(guò)一番思考延窜,我考慮把文件上傳這部分的邏輯單獨(dú)提取出一層FileUploader,而UploadPresenter只負(fù)責(zé)維護(hù)FileUploader的隊(duì)列以及檢查網(wǎng)絡(luò)狀態(tài)抹锄。具體的實(shí)現(xiàn)如下所示逆瑞。

MVP2.png

我們可以看到,分層之后的結(jié)構(gòu)又更加清晰了伙单,每一層的職責(zé)都比較單一获高,目前看起來(lái)一切OK!

V3.0 多來(lái)源上傳

原來(lái)我們的上傳文件的來(lái)源是存在于App沙箱里的吻育,我們通過(guò)數(shù)據(jù)庫(kù)查詢可以找到這個(gè)文件的索引和路徑念秧,進(jìn)而獲取到這個(gè)文件進(jìn)行上傳。現(xiàn)在萬(wàn)惡的需求又來(lái)了布疼,需要支持上傳系統(tǒng)相冊(cè)中獲取的圖片/視頻摊趾。

  1. 支持系統(tǒng)相冊(cè)和App沙箱中獲取文件

到這里可能有些讀者已經(jīng)有點(diǎn)頭大了,如果沒(méi)有仔細(xì)思考游两,很可能從這里就走向了代碼質(zhì)量崩潰的道路砾层。

這個(gè)時(shí)候,我們就要思考贱案,他們是多來(lái)源肛炮,但是對(duì)于FileUploader來(lái)說(shuō),它其實(shí)不關(guān)心模型的來(lái)源,它只需要獲取到模型的二進(jìn)制流侨糟。于是碍扔,我們可以抽象出一個(gè)BaseModel,提供一個(gè)stream只讀屬性秕重,兩種來(lái)源分別繼承BaseModel不同,各自重載stream只讀屬性,實(shí)現(xiàn)自己的構(gòu)造文件stream的方法悲幅。對(duì)于FileUploader來(lái)說(shuō)套鹅,它只持有BaseModel即可,這就是繼承和多態(tài)的一個(gè)典型的使用場(chǎng)景汰具。

如果后續(xù)還有更多來(lái)源的文件卓鹿,比如網(wǎng)絡(luò)文件(先下載再上傳?),也只需要繼續(xù)繼承BaseModel留荔,重載stream即可吟孙,對(duì)于FileUploader和它的所有上層來(lái)說(shuō),一切都是透明的聚蝶,無(wú)需進(jìn)行修改杰妓。經(jīng)過(guò)這樣的設(shè)計(jì),我們的代碼的可維護(hù)性和可擴(kuò)展性又好了碘勉。下面是架構(gòu)圖巷挥。

MVP3.png
V4.0 多方式上傳

在HTTP文件上傳中,我們可以直接上傳文件的二進(jìn)制流验靡,這種就需要服務(wù)端做特定的支持倍宾。但更為常用和支持廣泛的做法是使用HTTP表單文件傳輸,即組裝HTTP請(qǐng)求的body時(shí)采用multipart/form-data的標(biāo)準(zhǔn)組裝胜嗓,傳輸數(shù)據(jù)高职。于是,我們又多了一個(gè)需求:

  1. 支持表單傳輸和流傳輸

思路和剛才的多來(lái)源上傳差不多辞州,我們把上面的兩種來(lái)源的模型怔锌,即FSBaseMABaseM抽象為父類,父類含有各自的文件二進(jìn)制數(shù)據(jù)的抽象变过,子類分別實(shí)現(xiàn)二進(jìn)制直接組裝流埃元,和按multipart/form-data格式組裝流,實(shí)現(xiàn)如下圖牵啦。

MVP4.png
V5.0 支持FTP/Socket上傳

剛才我們的文件上傳亚情,底層的協(xié)議是基于Http,此時(shí)我們需要支持FTP/Socket協(xié)議的傳輸哈雏,應(yīng)該怎么辦楞件?

  1. 支持HTTP/FTP/Socket

經(jīng)過(guò)上面的思考衫生,相信你一定知道該怎么做了。這里留個(gè)思考土浸,答案:


對(duì)比

最后罪针,我們把目前的需求全都整理一下

  1. 初始化上傳View
  2. 更新上傳View
  3. 點(diǎn)擊上傳按鈕事件
  4. 數(shù)據(jù)庫(kù)中獲取上傳模型
  5. 發(fā)起HTTP請(qǐng)求上傳文件
  6. 檢查網(wǎng)絡(luò)狀態(tài)
  7. 維護(hù)上傳模型隊(duì)列
  8. 支持系統(tǒng)相冊(cè)和App沙箱中獲取文件
  9. 支持表單傳輸和流傳輸
  10. 支持HTTP/FTP/Socket

我們看看,如果分別采用MVC黄伊、MVP_V1泪酱、MVP_V2、MVP_V3还最、MVP_V4墓阀、MVP_V5,來(lái)實(shí)現(xiàn)目前的十個(gè)需求拓轻,我們的代碼大致會(huì)分布在哪幾層斯撮。

優(yōu)化后的架構(gòu)模式之間的比較

孰優(yōu)孰劣一目了然。如果采用最原始的MVC模式的話扶叉,保守估計(jì)ViewController代碼量至少3K行以上勿锅。

總結(jié)
  • 運(yùn)用MVP的設(shè)計(jì)模式,邏輯和UI操作解耦
  • 分層模式枣氧,上層擁有下層溢十,下層通過(guò)接口與上層通信,達(dá)到解耦达吞。
  • 利用繼承和多態(tài)张弛,屏蔽底層實(shí)現(xiàn)的細(xì)節(jié),達(dá)到職責(zé)分離和高擴(kuò)展性

代碼優(yōu)化和重構(gòu)的技巧

在這次的項(xiàng)目重構(gòu)中酪劫,我也總結(jié)了一些重構(gòu)方面的技巧和貼士乌庶,希望能幫助到想開(kāi)始進(jìn)行代碼重構(gòu)的同學(xué)

事不過(guò)三
  • 大段重復(fù)的代碼出現(xiàn)了三次或以上——提取成一個(gè)公共的方法,這一點(diǎn)是最常見(jiàn)也最容易做到的契耿,只要在平時(shí)的編碼過(guò)程中養(yǎng)成這種習(xí)慣,對(duì)于出現(xiàn)過(guò)三次以上重復(fù)代碼段螃征,提取成一個(gè)公共方法搪桂。

  • 一個(gè)類的職責(zé)有三種或以上——通過(guò)合理分層的方式,減少職責(zé)盯滚,這一點(diǎn)在上面的例子中已經(jīng)闡述地比較清楚了踢械,通過(guò)職責(zé)的分層,上層持有下層魄藕,下層通過(guò)接口與上層通訊内列。其實(shí)這也是MVP模式的本質(zhì)。

  • 同類的if/else出現(xiàn)了三次或以上——考慮使用抽象類和多態(tài)代替if/else背率,如果相同的if/else判斷在你的代碼中出現(xiàn)了很多次的話话瞧,則應(yīng)該考慮設(shè)計(jì)一個(gè)抽象類去替代這些判斷嫩与。這里可能有點(diǎn)難以理解,舉個(gè)例子就好懂很多交排,比如划滋,現(xiàn)在我們有一個(gè)水果類,有三種水果埃篓,水果有顏色处坪、價(jià)錢(qián)和品種

class Fruit {
    
    var name:String = ""
    
    func getColor() -> UIColor? {
        if name == "apple" {
            return UIColor.red
        } else if name == "banana" {
            return UIColor.yellow
        } else if name == "orange" {
            return UIColor.orange
        }
        return nil
    }

    func getPrice() -> Float? {
        if name == "apple" {
            return 10
        } else if name == "banana" {
            return 20
        } else if name == "orange" {
            return 30
        }
        return nil
    }
    
    func getType() -> String? {
        if name == "apple" {
            return "紅富士"
        } else if name == "banana" {
            return "芭蕉"
        } else if name == "orange" {
            return "皇帝"
        }
        return nil
    }
}

這里的對(duì)名稱name的相同的if/else判斷出現(xiàn)了三次,如果此時(shí)我們多了一種水果梨架专,我們得修改上述所有的if/else判斷同窘,這樣就會(huì)非常難維護(hù)。

這種場(chǎng)景我們可以考慮抽象出一個(gè)Fruit的抽象類/接口/協(xié)議部脚,通過(guò)實(shí)現(xiàn)水果類/接口/協(xié)議的方式想邦,此時(shí)如果多了一種水果,讓這種水果繼續(xù)實(shí)現(xiàn)Fruit協(xié)議就行睛低,這樣我們就通過(guò)新增的方式替代修改案狠,提高了代碼的可維護(hù)性。

protocol Fruit {
    func getPrice() -> Float?
    func getType() -> String?
    func getColor() -> UIColor?
    var name:String { get }
}

class Apple:Fruit {
    var name:String = "apple"
    func getColor() -> UIColor? {
        return UIColor.red
    }
    
    func getPrice() -> Float? {
        return 10
    }
    
    func getType() -> String? {
        return "紅富士"
    }
}

class Banana:Fruit {
    var name:String = "banana"
    func getColor() -> UIColor? {
        return UIColor.yellow
    }
    
    func getPrice() -> Float? {
        return 20
    }
    
    func getType() -> String? {
        return "芭蕉"
    }
}

class Orange:Fruit {
    var name:String = "orange"
    func getColor() -> UIColor? {
        return UIColor.orange
    }
    
    func getPrice() -> Float? {
        return 30
    }
    
    func getType() -> String? {
        return "皇帝柑"
    }
}

這個(gè)例子跟我之前提的一篇文章的例子是極其相似的:使用state pattern替代if else钱雷,都是面向接口編程的典型實(shí)例骂铁。而且這個(gè)例子還不如我之前提到的那篇文章中的實(shí)例更能說(shuō)明面向接口編程的必要性,因?yàn)槟芹邕壿嫷阶詈髸?huì)發(fā)展為不得不解決的痛了罩抗。

合理分層
  • 縱向分層——層級(jí)之間有關(guān)聯(lián)
    上層持有下層拉庵,下層通過(guò)接口與上層通信。這里為什么不讓下層也持有上層呢套蒂?主要還是為了能夠解耦钞支,下層設(shè)計(jì)的目的是為上層服務(wù)的,它不應(yīng)該依賴上層操刀。這種設(shè)計(jì)模式在計(jì)算機(jī)科學(xué)中是很常見(jiàn)的烁挟,比如計(jì)算機(jī)網(wǎng)絡(luò)中的網(wǎng)絡(luò)分層設(shè)計(jì)。

  • 橫向分層——層級(jí)之間無(wú)關(guān)聯(lián)
    適用于功能相對(duì)獨(dú)立的模塊骨坑,簡(jiǎn)單劃分即可撼嗓。我們的iOS項(xiàng)目的首頁(yè)就是由好幾個(gè)部分組成,這個(gè)部分之間無(wú)太多的關(guān)聯(lián)欢唾,我們簡(jiǎn)單劃分成幾個(gè)模塊就行且警。如果出現(xiàn)了少數(shù)需要通訊的場(chǎng)景,使用Notification即可礁遣。

避免過(guò)度設(shè)計(jì)
  • 越簡(jiǎn)單的越是有效的斑芜,復(fù)雜的架構(gòu)設(shè)計(jì)往往在客戶端高速迭代開(kāi)發(fā)中意義不大(相比服務(wù)端)

  • 沒(méi)有銀彈!軟件開(kāi)發(fā)是工程化的祟霍,沒(méi)有完美的架構(gòu)模式杏头,很多時(shí)候需要具體問(wèn)題具體分析盈包,靈活運(yùn)用設(shè)計(jì)模式,得到局部的最優(yōu)解大州。比如前面提到的MVP模式续语,如果生搬硬套,同樣無(wú)法解決Presenter層復(fù)雜的問(wèn)題厦画。

  • 如何判斷過(guò)度設(shè)計(jì)疮茄?膠水代碼過(guò)多,大量文件的行數(shù)小于100根暑,想了一天力试,沒(méi)寫(xiě)出代碼,也沒(méi)寫(xiě)出架構(gòu)方案

重構(gòu)的時(shí)機(jī)和對(duì)象
  • 時(shí)機(jī)排嫌,單文件代碼行數(shù)開(kāi)始超過(guò)500行的時(shí)候
    Code Review是重構(gòu)的好幫手
  • 對(duì)象畸裳,需求經(jīng)常變化或增加的功能,一定要注意設(shè)計(jì)淳地,避免走向質(zhì)量不可控
    穩(wěn)定且不變的功能怖糊,不重構(gòu)

總結(jié)

上文中我引用的是一篇?jiǎng)e人文章中的內(nèi)容,我從中看到的是面向接口的思想颇象,并沒(méi)有多突出 MVP的思想伍伤。面向接口的編程思想對(duì)程序的擴(kuò)展性和維護(hù)性是極友好的,是大型系統(tǒng)中復(fù)雜邏輯的一個(gè)極其好的解決方案遣钳,本文只是一個(gè)例子扰魂,一個(gè)引子,引導(dǎo)我們從這個(gè)思想層面來(lái)思考程序的設(shè)計(jì)蕴茴,希望大家有所獲劝评。


參考文章:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市倦淀,隨后出現(xiàn)的幾起案子蒋畜,更是在濱河造成了極大的恐慌,老刑警劉巖撞叽,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件百侧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡能扒,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)辫狼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)初斑,“玉大人,你說(shuō)我怎么就攤上這事膨处〖樱” “怎么了砂竖?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)鹃答。 經(jīng)常有香客問(wèn)我乎澄,道長(zhǎng),這世上最難降的妖魔是什么测摔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任置济,我火速辦了婚禮,結(jié)果婚禮上锋八,老公的妹妹穿的比我還像新娘浙于。我一直安慰自己,他們只是感情好挟纱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布羞酗。 她就那樣靜靜地躺著,像睡著了一般紊服。 火紅的嫁衣襯著肌膚如雪檀轨。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天欺嗤,我揣著相機(jī)與錄音参萄,去河邊找鬼。 笑死剂府,一個(gè)胖子當(dāng)著我的面吹牛拧揽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播腺占,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼淤袜,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了衰伯?” 一聲冷哼從身側(cè)響起铡羡,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎意鲸,沒(méi)想到半個(gè)月后烦周,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡怎顾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年读慎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片槐雾。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夭委,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出募强,到底是詐尸還是另有隱情株灸,我是刑警寧澤崇摄,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站慌烧,受9級(jí)特大地震影響逐抑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屹蚊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一厕氨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淑翼,春花似錦腐巢、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至遭京,卻和暖如春胃惜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背哪雕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工船殉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斯嚎。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓利虫,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親堡僻。 傳聞我的和親對(duì)象是個(gè)殘疾皇子糠惫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,182評(píng)論 25 707
  • 我向神的禱告 主啊,你在圣經(jīng)上說(shuō)钉疫,你召我硼讽,本不是要我沾染污穢,乃是要我成為圣潔(參帖撒羅尼迦前書(shū)4:7)牲阁。你揀選我...
    _Dorcas_張閱讀 1,928評(píng)論 0 0
  • 前幾天閑來(lái)無(wú)事固阁,看了幾期《愛(ài)情保衛(wèi)戰(zhàn)》,有一期讓我印象深刻城菊。男嘉賓和女嘉賓已經(jīng)結(jié)婚备燃,可是男嘉賓在平時(shí)表現(xiàn)出來(lái)的吝嗇...
    鹿珄閱讀 431評(píng)論 1 2
  • 五年級(jí)今天考試 兒子們從昨天開(kāi)始就為考試做的準(zhǔn)備 昨天下午:買(mǎi)"逢考必過(guò)"扇子(未果),清涼帖凌唬,所以考試文具(除鉛...
    夜語(yǔ)婉婷閱讀 232評(píng)論 0 0