只一篇就夠了·設(shè)計(jì)模式(3) - 觀察者模式

觀察者模式(Observer Pattern)是對(duì)象之間一對(duì)多的依賴關(guān)系牙寞,當(dāng)一個(gè)對(duì)象改變時(shí),其他依賴它的對(duì)象都會(huì)收到通知并自動(dòng)更新蝙云。

怎么來(lái)理解這句話呢酸员?用微信朋友圈來(lái)舉個(gè)例子,假如你就是被依賴的對(duì)象河胎,你的好友都依賴你闯袒,這樣的關(guān)系就形成了一對(duì)多,當(dāng)你發(fā)朋友圈的時(shí)候你的好友都能收到通知游岳,并且自動(dòng)更新政敢。

觀察者模式是一個(gè)比較簡(jiǎn)單的模式,它的核心很簡(jiǎn)單胚迫,只有兩個(gè)角色喷户,一個(gè)是被依賴的對(duì)象,在朋友圈例子里面就是你自己访锻,這個(gè)叫主題或者被觀察者褪尝,另一個(gè)對(duì)象是你的朋友叫觀察者或者訂閱者,為了統(tǒng)一認(rèn)知期犬,后面都叫主題(被觀察者)和訂閱者(觀察者)河哑。

類圖

類圖不是目的,只是方便理解

[圖片上傳失敗...(image-538efc-1527174205892)]

從類圖上可以看到龟虎,主題不關(guān)心其他訂閱者的實(shí)現(xiàn)璃谨,只關(guān)心Observer接口,所有實(shí)現(xiàn)了Observer接口并訂閱了主題的對(duì)象都能在主題發(fā)生變化的時(shí)候得到通知遣总。

實(shí)例

現(xiàn)在來(lái)實(shí)現(xiàn)一個(gè)汽車儀表盤睬罗,汽車在行駛過(guò)程中轉(zhuǎn)速和速度都會(huì)一直處于變化中轨功,我們現(xiàn)在通過(guò)觀察者模式把轉(zhuǎn)速和速度顯示到儀表盤上。
首先容达,模擬一輛汽車從0-100加速的過(guò)程古涧,這個(gè)過(guò)程中拿到汽車把實(shí)時(shí)數(shù)據(jù):

/**
 * 汽車回調(diào)數(shù)據(jù),這里會(huì)根據(jù)汽車的速度變化花盐,持續(xù)的傳遞轉(zhuǎn)速和速度
 */
fun carInfo(power:Float, speed: Float)
{

}
/**
 * 汽車引擎羡滑,模擬汽車從0-100加速
 */
for (speed in 0..1000)
{
    Thread.sleep(10)
    carInfo(speed/200f + Random().nextInt(2), speed.toFloat()/10)
}
// 部分汽車數(shù)據(jù)打印
power: 0.0   speed: 0.0
power: 0.005   speed: 0.1
power: 0.01   speed: 0.2
power: 0.015   speed: 0.3
power: 0.02   speed: 0.4
power: 1.025   speed: 0.5
power: 1.03   speed: 0.6
power: 1.035   speed: 0.7
power: 0.04   speed: 0.8
power: 0.045   speed: 0.9
power: 0.05   speed: 1.0
power: 1.055   speed: 1.1

既然要顯示到儀表盤,現(xiàn)在還差一個(gè)儀表盤Display用于顯示速度和轉(zhuǎn)速:

/**
 * 儀表盤
 * Created by Carlton on 2016/11/9.
 */
class Display
{
    var power:Float = 0f
    var speed:Float = 0f

    fun display()
    {
        println("汽車當(dāng)前的 轉(zhuǎn)速:$power  速度:$speed")
    }
}

現(xiàn)在我們把速度變化數(shù)據(jù)通過(guò)儀表盤Display展示出來(lái):

val display = Display()
/**
 * 汽車回調(diào)數(shù)據(jù)算芯,這里會(huì)根據(jù)汽車的速度變化柒昏,持續(xù)的傳遞轉(zhuǎn)速和速度
 */
fun carInfo(power:Float, speed: Float)
{
    display.power = power
    display.speed = speed
    display.display()
}
// 儀表盤數(shù)據(jù)
……
汽車當(dāng)前的 轉(zhuǎn)速:3.985  速度:79.7
汽車當(dāng)前的 轉(zhuǎn)速:4.99  速度:79.8
汽車當(dāng)前的 轉(zhuǎn)速:3.995  速度:79.9
汽車當(dāng)前的 轉(zhuǎn)速:4.0  速度:80.0
汽車當(dāng)前的 轉(zhuǎn)速:5.005  速度:80.1
汽車當(dāng)前的 轉(zhuǎn)速:5.01  速度:80.2
汽車當(dāng)前的 轉(zhuǎn)速:4.015  速度:80.3
汽車當(dāng)前的 轉(zhuǎn)速:4.02  速度:80.4
汽車當(dāng)前的 轉(zhuǎn)速:5.025  速度:80.5
汽車當(dāng)前的 轉(zhuǎn)速:5.03  速度:80.6
……

現(xiàn)在我們就實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的汽車儀表盤展示數(shù)據(jù),這樣寫(xiě)有什么問(wèn)題呢熙揍?如果我們給汽車擴(kuò)展一個(gè)后視鏡顯示速度职祷,中控臺(tái)展示速度,我們又需要來(lái)修改carInfo()去設(shè)置和顯示后視鏡届囚、中控臺(tái)有梆,顯然不符合設(shè)計(jì)原則
現(xiàn)在我們知道整個(gè)系統(tǒng)中有兩個(gè)角色:汽車變化的數(shù)據(jù)意系、儀表盤泥耀。按照觀察者模式,把汽車變化的數(shù)據(jù)定義成主題(被觀察者)蛔添,儀表盤定義訂閱者(觀察者)痰催,然后用觀察者模式重構(gòu)整個(gè)系統(tǒng)。
首先迎瞧,實(shí)現(xiàn)觀察者接口:

/**
 * 主題夸溶,有的地方叫觀察者Observable
 * @param T 更新的數(shù)據(jù)回調(diào)
 * Created by Carlton on 2016/11/9.
 */
interface Subject<T>
{
    /**
     * 注冊(cè)成為觀察者
     */
    fun registeObserver(observer: Observer<T>)

    /**
     * 刪除觀察者
     */
    fun removeObserver(observer: Observer<T>)

    /**
     * 通知觀察者數(shù)據(jù)已經(jīng)發(fā)生了變化
     */
    fun notifyObservers(value: T)
}

/**
 * 觀察者
 * @param T 觀察者回調(diào)的數(shù)據(jù)類型
 * Created by Carlton on 2016/11/9.
 */
interface Observer<in T>
{
    /**
     * 數(shù)據(jù)更新
     */
    fun update(value: T)
}

接下來(lái)把數(shù)據(jù)封裝成一個(gè)主題(被觀察者CarSubject:

/**
 * 具體的主題,被觀察者
 * Created by Carlton on 2016/11/9.
 */
class CarSubject : Subject<Array<Float>>
{
    /**
     * 觀察者
     */
    val observers = ArrayList<Observer<Array<Float>>>()
    override fun registerObserver(observer: Observer<Array<Float>>)
    {
        observers.add(observer)
    }

    override fun removeObserver(observer: Observer<Array<Float>>)
    {
        if(observers.contains(observer))
        {
            observers.remove(observer)
        }
    }

    override fun notifyObservers(value: Array<Float>)
    {
        for (observer in observers)
        {
            observer.update(value)
        }
    }
}

現(xiàn)在改造一下我們的系統(tǒng)夹攒,把數(shù)據(jù)用主題綁定起來(lái):

val carSubject = CarSubject()

/**
 * 汽車回調(diào)數(shù)據(jù)蜘醋,這里會(huì)根據(jù)汽車的速度變化,持續(xù)的傳遞轉(zhuǎn)速和速度
 */
fun carInfo(power:Float, speed: Float)
{
    carSubject.notifyObservers(arrayOf(power, speed))
}

到這里我們實(shí)現(xiàn)了一個(gè)可擴(kuò)展的觀察者模式系統(tǒng)咏尝,觀察者模式中的接口部分一般都是固定的压语,包括java里面都有支持觀察者模式,后面會(huì)說(shuō)道编检,所以如果我們要實(shí)現(xiàn)一個(gè)觀察者模式胎食,接口部分我們只需要實(shí)現(xiàn)一次,或者直接使用java api提供的接口允懂,主要需要實(shí)現(xiàn)主題或者觀察者接口厕怜。

在上面的例子中,我們自己提供了觀察者接口SubjectObserver粥航,接著我們實(shí)現(xiàn)了一個(gè)主題CarSubject用于封裝汽車變化的數(shù)據(jù)琅捏,提供給其他對(duì)這個(gè)數(shù)據(jù)感興趣的觀察者們。那么递雀,現(xiàn)在把儀表盤做為觀察者柄延,去訂閱主題,修改一下之前的Display:

/**
 * 儀表盤缀程,傳遞的數(shù)據(jù)是一個(gè)數(shù)組搜吧,0下標(biāo)存的是轉(zhuǎn)速,1下標(biāo)存的是速度
 * Created by Carlton on 2016/11/9.
 */
class Display : Observer<Array<Float>>
{
    override fun update(value: Array<Float>)
    {
        power = value[0]
        speed = value[1]
        display()
    }

    var power:Float = 0f
    var speed:Float = 0f

    fun display()
    {
        println("汽車當(dāng)前的 轉(zhuǎn)速:$power  速度:$speed")
    }
}

運(yùn)行系統(tǒng):

val carSubject = CarSubject()
// 添加儀表盤觀察者
carSubject.registerObserver(Display())

// 儀表盤顯示
……
汽車當(dāng)前的 轉(zhuǎn)速:4.525  速度:90.5
汽車當(dāng)前的 轉(zhuǎn)速:4.53  速度:90.6
汽車當(dāng)前的 轉(zhuǎn)速:4.535  速度:90.7
汽車當(dāng)前的 轉(zhuǎn)速:5.54  速度:90.8
汽車當(dāng)前的 轉(zhuǎn)速:5.545  速度:90.9
汽車當(dāng)前的 轉(zhuǎn)速:4.55  速度:91.0
汽車當(dāng)前的 轉(zhuǎn)速:4.555  速度:91.1
汽車當(dāng)前的 轉(zhuǎn)速:4.56  速度:91.2
汽車當(dāng)前的 轉(zhuǎn)速:4.565  速度:91.3
……

如果現(xiàn)在儀表盤不需要監(jiān)聽(tīng)主題的數(shù)據(jù)了杨凑,可以調(diào)用carSubject.removeObserver()移除對(duì)象滤奈,這樣主題數(shù)據(jù)發(fā)生變化后,就不會(huì)通知到這個(gè)觀察者對(duì)象撩满。

接下來(lái)蜒程,添加中控臺(tái)和后視鏡的數(shù)據(jù)顯示,把中控臺(tái)和后視鏡當(dāng)成觀察者去訂閱CarSubject伺帘。

這里解答一個(gè)疑惑搞糕,為什么觀察者去訂閱主題,反而要把訂閱和移除訂閱的方法放到主題里面而不是觀察者里面曼追,這樣也很好理解啊汉规?主要原因是現(xiàn)實(shí)世界和程序世界還是有區(qū)別礼殊,如果我們把這兩個(gè)方法按照現(xiàn)實(shí)的理解放到觀察者里面,代碼會(huì)變得比較復(fù)雜针史,沒(méi)有現(xiàn)在這種實(shí)現(xiàn)方式簡(jiǎn)單明確晶伦,有興趣的可以自己去按照現(xiàn)實(shí)的理解方式實(shí)現(xiàn)一個(gè)。設(shè)計(jì)模式只是一種編程思想啄枕,不是編程的形式婚陪,理解到思想就行了。

新添加兩個(gè)觀察者频祝,中控臺(tái)(CenterConsoleDisplay)泌参、后視鏡(RearviewBack):

/**
 * 中控臺(tái)
 * Created by Carlton on 2016/11/9.
 */
class CenterConsoleDisplay : Observer<Array<Float>>
{
    override fun update(value: Array<Float>)
    {
        println("中控臺(tái)顯示的速度:${value[1]}")
    }
}

/**
 * 后視鏡
 * Created by Carlton on 2016/11/9.
 */
class RearviewBack : Observer<Array<Float>>
{
    override fun update(value: Array<Float>)
    {
        println("后視鏡顯示: 速度 - ${value[1]}  轉(zhuǎn)速 - ${value[0]}")
    }
}

訂閱這兩個(gè)新的,啟動(dòng):

val carSubject = CarSubject()
// 添加儀表盤觀察者
carSubject.registerObserver(Display())
// 添加中控臺(tái)
carSubject.registerObserver(CenterConsoleDisplay())
// 添加后視鏡
carSubject.registerObserver(RearviewBack())

// 各個(gè)地方的數(shù)據(jù)展示
……
中控臺(tái)顯示的速度:98.9
后視鏡顯示: 速度 - 98.9  轉(zhuǎn)速 - 4.945
汽車當(dāng)前的 轉(zhuǎn)速:4.95  速度:99.0
中控臺(tái)顯示的速度:99.0
后視鏡顯示: 速度 - 99.0  轉(zhuǎn)速 - 4.95
汽車當(dāng)前的 轉(zhuǎn)速:4.955  速度:99.1
中控臺(tái)顯示的速度:99.1
后視鏡顯示: 速度 - 99.1  轉(zhuǎn)速 - 4.955
汽車當(dāng)前的 轉(zhuǎn)速:5.96  速度:99.2
中控臺(tái)顯示的速度:99.2
后視鏡顯示: 速度 - 99.2  轉(zhuǎn)速 - 5.96
……

數(shù)據(jù)的推和拉

觀察者模式中獲取數(shù)據(jù)的方式有兩種常空,一種是推給觀察者沽一,一種是觀察者根據(jù)需要自己拉,有什么區(qū)別呢漓糙?如果是推的方式不管觀察者對(duì)這部分信息是否感興趣都會(huì)推給觀察者铣缠,有冗余數(shù)據(jù)比如我們的中控臺(tái)(CenterConsoleDisplay)只對(duì)速度感興趣。如果是用拉的方式呢?這樣就能根據(jù)觀察者自己的需要獲取想要的數(shù)據(jù)蝗蛙,Java里面兩種方式都支持蝇庭,下面改造一下通過(guò)拉的方式實(shí)現(xiàn)數(shù)據(jù)傳遞,這樣的話CarSubject也就是主題需要暴露一些獲取數(shù)據(jù)的方法:

/**
 * 觀察者
 * @param T 觀察者回調(diào)的數(shù)據(jù)類型
 * Created by Carlton on 2016/11/9.
 */
interface Observer<T>
{
    /**
     * 數(shù)據(jù)更新
     */
    fun update(value: T)
    // ------------------   變化的部分   --------------------------
    /**
     * 重載一個(gè)方法捡硅,讓觀察者可以用拉的方式獲取數(shù)據(jù)
     */
    fun update(subject: Subject<T>)
    // ------------------   變化的部分   --------------------------
}

/**
 * 主題哮内,有的地方叫觀察者Observable
 * @param T 更新的數(shù)據(jù)回調(diào)
 * Created by Carlton on 2016/11/9.
 */
interface Subject<T>
{
    /**
     * 注冊(cè)成為觀察者
     */
    fun registerObserver(observer: Observer<T>)

    /**
     * 刪除觀察者
     */
    fun removeObserver(observer: Observer<T>)

    /**
     * 通知觀察者數(shù)據(jù)已經(jīng)發(fā)生了變化
     */
    fun notifyObservers(value: T)
    // ------------------   變化的部分   --------------------------
    /**
     * 通知觀察者數(shù)據(jù)已經(jīng)發(fā)生了變化,可以拉數(shù)據(jù)了
     */
    fun notifyObservers()
    // ------------------   變化的部分   --------------------------
}

/**
 * 具體的主題病曾,被觀察者
 * Created by Carlton on 2016/11/9.
 */
class CarSubject : Subject<Array<Float>>
{
    // ------------------   變化的部分   --------------------------
    var speed:Float = 0f
    var power:Float = 0f
    override fun notifyObservers()
    {
        for (observer in observers)
        {
            observer.update(this)
        }
    }
    // ------------------   變化的部分   --------------------------

    /**
     * 觀察者
     */
    val observers = ArrayList<Observer<Array<Float>>>()
    override fun registerObserver(observer: Observer<Array<Float>>)
    {
        observers.add(observer)
    }

    override fun removeObserver(observer: Observer<Array<Float>>)
    {
        if(observers.contains(observer))
        {
            observers.remove(observer)
        }
    }

    override fun notifyObservers(value: Array<Float>)
    {
        for (observer in observers)
        {
            observer.update(value)
        }
    }
}

/**
 * 中控臺(tái)
 * Created by Carlton on 2016/11/9.
 */
class CenterConsoleDisplay : Observer<Array<Float>>
{
    // ------------------   變化的部分   --------------------------
    override fun update(subject: Subject<Array<Float>>)
    {
        val carSubject:CarSubject = subject as CarSubject
        println("中控臺(tái)顯示的速度:${carSubject.speed}")
    }
    // ------------------   變化的部分   --------------------------

    override fun update(value: Array<Float>)
    {
        println("中控臺(tái)顯示的速度:${value[1]}")
    }
}

/**
 * 汽車回調(diào)數(shù)據(jù)牍蜂,這里會(huì)根據(jù)汽車的速度變化,持續(xù)的傳遞轉(zhuǎn)速和速度
 */
fun carInfo(power:Float, speed: Float)
{
    // ------------------   變化的部分   --------------------------
    carSubject.power = power
    carSubject.speed = speed
    carSubject.notifyObservers()
    // ------------------   變化的部分   --------------------------
    carSubject.notifyObservers(arrayOf(power, speed))
}

更靈活的設(shè)計(jì)

不知道大家發(fā)現(xiàn)一個(gè)問(wèn)題沒(méi)有泰涂,打印出來(lái)的速度和轉(zhuǎn)速都是有小數(shù)鲫竞,正常情況下速度表變化都是整數(shù)每次變化為1,為了說(shuō)明簡(jiǎn)單的用速度和轉(zhuǎn)速大于2的時(shí)候才通知觀察者來(lái)代替這個(gè)需求逼蒙。如果我們要處理這個(gè)問(wèn)題可以在觀察者對(duì)象中拿到數(shù)據(jù)后處理从绘,不過(guò)觀察者模式有一個(gè)比較優(yōu)雅的處理方式setChanged(),有什么用呢是牢?用來(lái)標(biāo)記數(shù)據(jù)是否發(fā)生了不變化如果沒(méi)有發(fā)生變化則不通知觀察者僵井,這樣我們就能控制何時(shí)通知觀察者,現(xiàn)在改造一下CarSubject驳棱,并在Subject中新增接口setChanged()

/**
 * 具體的主題批什,被觀察者
 * Created by Carlton on 2016/11/9.
 */
class CarSubject : Subject<Array<Float>>
{
    var speed:Float = 0f
    var power:Float = 0f
    override fun notifyObservers()
    {
        if (!isChanged)
        {
            return
        }
        for (observer in observers)
        {
            observer.update(this)
        }
        isChanged = false
    }

    /**
     * 數(shù)據(jù)是否發(fā)生變化
     */
    var isChanged: Boolean = false
    override fun setChanged()
    {
        isChanged = true
    }
    /**
     * 觀察者
     */
    val observers = ArrayList<Observer<Array<Float>>>()
    override fun registerObserver(observer: Observer<Array<Float>>)
    {
        observers.add(observer)
    }

    override fun removeObserver(observer: Observer<Array<Float>>)
    {
        if(observers.contains(observer))
        {
            observers.remove(observer)
        }
    }

    override fun notifyObservers(value: Array<Float>)
    {
        if (!isChanged)
        {
            return
        }
        for (observer in observers)
        {
            observer.update(value)
        }
        isChanged = false
    }
}

現(xiàn)在在通知觀察者之前我們必須設(shè)置數(shù)據(jù)更新標(biāo)志調(diào)用setChanged(),這里我們讓轉(zhuǎn)速和速度都大于2的時(shí)候才通知觀察者:

/**
 * 汽車回調(diào)數(shù)據(jù)社搅,這里會(huì)根據(jù)汽車的速度變化驻债,持續(xù)的傳遞轉(zhuǎn)速和速度
 */
fun carInfo(power:Float, speed: Float)
{
    carSubject.power = power
    carSubject.speed = speed
    // 這里我們可以讓速度和轉(zhuǎn)速大于2的時(shí)候才通知觀察者
    if (carSubject.power > 2 && carSubject.speed > 2)
    {
        carSubject.setChanged()
    }
    carSubject.notifyObservers()
    carSubject.notifyObservers(arrayOf(power, speed))
}

Java里面的觀察者

Java里面提供了一個(gè)被觀察者類:java.util.Observable這不是一個(gè)接口,里面有具體的實(shí)現(xiàn)形葬,跟我們的CarSubject一樣合呐,已經(jīng)做好了添加觀察者、重置標(biāo)志符等功能笙以,需要的時(shí)候直接繼承淌实。還有一個(gè)java.util.Observer觀察者接口,跟我們上面的是一樣的猖腕。Java把java.util.Observable定義成一個(gè)類拆祈,主要是流程化了主題功能,不像用接口的時(shí)候需要自己實(shí)現(xiàn)添加觀察者等功能谈息,這樣也有一個(gè)問(wèn)題就是擴(kuò)展性變差了缘屹,因?yàn)榻涌诳偸潜阮愐`活。如果用Java自帶的觀察者API來(lái)實(shí)現(xiàn)我們的系統(tǒng)侠仇,只需要用CarSubject來(lái)繼承java.util.Observable就可以了轻姿,CarSubject中就不需要再去實(shí)現(xiàn)這些方法了犁珠,因?yàn)楦割愐呀?jīng)實(shí)現(xiàn)好了:

/**
 * 注冊(cè)成為觀察者
 */
fun registerObserver(observer: Observer<T>)

/**
 * 刪除觀察者
 */
fun removeObserver(observer: Observer<T>)

/**
 * 通知觀察者數(shù)據(jù)已經(jīng)發(fā)生了變化
 */
fun notifyObservers(value: T)

/**
 * 通知觀察者數(shù)據(jù)已經(jīng)發(fā)生了變化,可以拉數(shù)據(jù)了
 */
fun notifyObservers()

/**
 * 標(biāo)記數(shù)據(jù)變化
 */
fun setChanged()

MVC說(shuō)幾句

MVC有很多實(shí)現(xiàn)方式互亮,但是用觀察者模式實(shí)現(xiàn)是我覺(jué)得最好用的方式犁享,我們把V想成訂閱者,把M實(shí)現(xiàn)成主題豹休,這樣的話炊昆,當(dāng)我們的Model中有數(shù)據(jù)變化的時(shí)候就可以直接通知到View,讓View用數(shù)據(jù)來(lái)更新界面威根,這樣寫(xiě)出來(lái)的架構(gòu)更容易理解和解耦凤巨。

總結(jié)

觀察者模式主要有兩個(gè)角色,一個(gè)是觀察者洛搀,一個(gè)是被觀察者敢茁,所有觀察者都能夠收到被觀察者數(shù)據(jù)變化的通知,如果某個(gè)觀察者不在關(guān)心主題的數(shù)據(jù)了留美,也可以從被觀察者的列表中刪除這個(gè)觀察者彰檬,這樣它就不會(huì)收到通知了。如果使用Java谎砾,沒(méi)有特別的需求情況下逢倍,不建議自己實(shí)現(xiàn)觀察者接口,而是直接使用Java API景图。觀察者有很多可以應(yīng)用的地方较雕,非常有用的一種編程思路,比如RxJava里面等等很多框架都有觀察者模式挚币。觀察者模式在項(xiàng)目中是經(jīng)常使用的一種模式郎笆,當(dāng)明白它的核心思想后,在項(xiàng)目中能幫助我們實(shí)現(xiàn)更好維護(hù)的代碼忘晤。

??查看更多??

不登高山,不知天之高也激捏;不臨深溪设塔,不知地之厚也
感謝指點(diǎn)、交流远舅、喜歡

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末闰蛔,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子图柏,更是在濱河造成了極大的恐慌序六,老刑警劉巖废酷,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件眷篇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡梗脾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門繁涂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拱她,“玉大人,你說(shuō)我怎么就攤上這事扔罪”樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵矿酵,是天一觀的道長(zhǎng)唬复。 經(jīng)常有香客問(wèn)我,道長(zhǎng)全肮,這世上最難降的妖魔是什么敞咧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮倔矾,結(jié)果婚禮上妄均,老公的妹妹穿的比我還像新娘。我一直安慰自己哪自,他們只是感情好丰包,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著壤巷,像睡著了一般邑彪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上胧华,一...
    開(kāi)封第一講書(shū)人閱讀 52,196評(píng)論 1 308
  • 那天寄症,我揣著相機(jī)與錄音,去河邊找鬼矩动。 笑死有巧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的悲没。 我是一名探鬼主播篮迎,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼示姿!你這毒婦竟也來(lái)了甜橱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤栈戳,失蹤者是張志新(化名)和其女友劉穎岂傲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體子檀,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡镊掖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年乃戈,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堰乔。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡偏化,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镐侯,到底是詐尸還是另有隱情侦讨,我是刑警寧澤,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布苟翻,位于F島的核電站韵卤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏崇猫。R本人自食惡果不足惜沈条,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诅炉。 院中可真熱鬧蜡歹,春花似錦、人聲如沸涕烧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)议纯。三九已至父款,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間瞻凤,已是汗流浹背憨攒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留阀参,地道東北人肝集。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蛛壳,于是被迫代替她去往敵國(guó)和親包晰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

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