Python設(shè)計(jì)模式之觀察者模式

觀察者模式

有時(shí),我們希望在一個(gè)對(duì)象的狀態(tài)改變時(shí)更新另外一組對(duì)象。在MVC模式中有這樣一個(gè)非常常見(jiàn)的例子丈牢,假設(shè)在兩個(gè)視圖(例如,一個(gè)餅圖和一個(gè)電子表格)中使用同一個(gè)模型的數(shù)據(jù)骤菠,無(wú)論何時(shí)更改了模型它改,都需要更新兩個(gè)視圖。這就是觀察者設(shè)計(jì)模式要處理的問(wèn)題(請(qǐng)參考[Eckel08商乎,第213頁(yè)])央拖。

觀察者模式描述單個(gè)對(duì)象(發(fā)布者,又稱(chēng)為主持者或可觀察者)與一個(gè)或多個(gè)對(duì)象(訂閱者鹉戚,又稱(chēng)為觀察者)之間的發(fā)布—訂閱關(guān)系鲜戒。在MVC例子中,發(fā)布者是模型抹凳,訂閱者是視圖遏餐。然而,MVC并非是僅有的發(fā)布—訂閱例子赢底。信息聚合訂閱(比如失都,RSS或Atom)是另一種例子。許多讀者通常會(huì)使用一個(gè)信息聚合閱讀器訂閱信息流颖系,每當(dāng)增加一條新信息時(shí)嗅剖,他們就能自動(dòng)地獲取到更新。

觀察者模式背后的思想等同于MVC和關(guān)注點(diǎn)分離原則背后的思想嘁扼,即降低發(fā)布者與訂閱者之間的耦合度信粮,從而易于在運(yùn)行時(shí)添加/刪除訂閱者。此外趁啸,發(fā)布者不關(guān)心它的訂閱者是誰(shuí)强缘。它只是將通知發(fā)送給所有訂閱者(請(qǐng)參考[GOF95,第327頁(yè)])不傅。

以下為來(lái)自于github的示例:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
"""http://code.activestate.com/recipes/131499-observer-pattern/"""


class Subject(object):

    def __init__(self):
        self._observers = []

    def attach(self, observer):
        if observer not in self._observers:
            self._observers.append(observer)

    def detach(self, observer):
        try:
            self._observers.remove(observer)
        except ValueError:
            pass

    def notify(self, modifier=None):
        for observer in self._observers:
            if modifier != observer:
                observer.update(self)


# Example usage
class Data(Subject):

    def __init__(self, name=''):
        Subject.__init__(self)
        self.name = name
        self._data = 0

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, value):
        self._data = value
        self.notify()


class HexViewer:

    def update(self, subject):
        print(u'HexViewer: Subject %s has data 0x%x' %
              (subject.name, subject.data))


class DecimalViewer:

    def update(self, subject):
        print(u'DecimalViewer: Subject %s has data %d' %
              (subject.name, subject.data))


# Example usage...
def main():
    data1 = Data('Data 1')
    data2 = Data('Data 2')
    view1 = DecimalViewer()
    view2 = HexViewer()
    data1.attach(view1)
    data1.attach(view2)
    data2.attach(view2)
    data2.attach(view1)

    print(u"Setting Data 1 = 10")
    data1.data = 10
    print(u"Setting Data 2 = 15")
    data2.data = 15
    print(u"Setting Data 1 = 3")
    data1.data = 3
    print(u"Setting Data 2 = 5")
    data2.data = 5
    print(u"Detach HexViewer from data1 and data2.")
    data1.detach(view2)
    data2.detach(view2)
    print(u"Setting Data 1 = 10")
    data1.data = 10
    print(u"Setting Data 2 = 15")
    data2.data = 15


if __name__ == '__main__':
    main()

### OUTPUT ###
# Setting Data 1 = 10
# DecimalViewer: Subject Data 1 has data 10
# HexViewer: Subject Data 1 has data 0xa
# Setting Data 2 = 15
# HexViewer: Subject Data 2 has data 0xf
# DecimalViewer: Subject Data 2 has data 15
# Setting Data 1 = 3
# DecimalViewer: Subject Data 1 has data 3
# HexViewer: Subject Data 1 has data 0x3
# Setting Data 2 = 5
# HexViewer: Subject Data 2 has data 0x5
# DecimalViewer: Subject Data 2 has data 5
# Detach HexViewer from data1 and data2.
# Setting Data 1 = 10
# DecimalViewer: Subject Data 1 has data 10
# Setting Data 2 = 15
# DecimalViewer: Subject Data 2 has data 15

現(xiàn)實(shí)生活的例子

現(xiàn)實(shí)中旅掂,拍賣(mài)會(huì)類(lèi)似于觀察者模式。每個(gè)拍賣(mài)出價(jià)人都有一些拍牌访娶,在他們想出價(jià)時(shí)就可以舉起來(lái)商虐。不論出價(jià)人在何時(shí)舉起一塊拍牌,拍賣(mài)師都會(huì)像主持者那樣更新報(bào)價(jià)崖疤,并將新的價(jià)格廣播給所有出價(jià)人(訂閱者)秘车。

下圖展示了觀察者模式與拍賣(mài)會(huì)的關(guān)聯(lián),經(jīng)www.sourcemaking.com 允許使用(請(qǐng)參考網(wǎng)頁(yè)[t.cn/rqr1yxo])劫哼。

軟件的例子

django-observer源代碼包(請(qǐng)參考網(wǎng)頁(yè)[t.cn/rqr14oz])是一個(gè)第三方django包叮趴,可用于注冊(cè)回調(diào)函數(shù),之后在某些django模型字段發(fā)生變化時(shí)執(zhí)行权烧。它支持許多不同類(lèi)型的模型字段(charfield眯亦、integerfield等)伤溉。

rabbitmq可用于為應(yīng)用添加異步消息支持,支持多種消息協(xié)議(比如妻率,http和amqp)乱顾,可在python應(yīng)用中用于實(shí)現(xiàn)發(fā)布—訂閱模式,也就是觀察者設(shè)計(jì)模式(請(qǐng)參考網(wǎng)頁(yè)[t.cn/rqr1iix])舌涨。

應(yīng)用案例

當(dāng)我們希望在一個(gè)對(duì)象(主持者/發(fā)布者/可觀察者)發(fā)生變化時(shí)通知/更新另一個(gè)或多個(gè)對(duì)象的時(shí)候糯耍,通常會(huì)使用觀察者模式。觀察者的數(shù)量以及誰(shuí)是觀察者可能會(huì)有所不同囊嘉,也可以(在運(yùn)行時(shí))動(dòng)態(tài)地改變温技。

可以想到許多觀察者模式在其中有用武之地的案例。本章開(kāi)頭已提過(guò)這樣的一個(gè)案例扭粱,就是信息聚合舵鳞。尤論格式為RSS、Atom還是其他琢蛤,思想都一樣:你追隨某個(gè)信息源蜓堕,當(dāng)它每次更新時(shí),你都會(huì)收到關(guān)于更新的一個(gè)通知(請(qǐng)參考[Zlobin13博其,第60頁(yè)])套才。

同樣的概念也存在于社交網(wǎng)絡(luò)。如果你使用社交網(wǎng)絡(luò)服務(wù)關(guān)聯(lián)了另一個(gè)人慕淡,在關(guān)聯(lián)的人更新某些內(nèi)容時(shí)背伴,你能收到相關(guān)通知,不論這個(gè)關(guān)聯(lián)的人是你關(guān)注的一個(gè)Twitter用戶峰髓,F(xiàn)acebook上的一個(gè)真實(shí)朋友傻寂,還是LinkdIn上的一位同事。

事件驅(qū)動(dòng)系統(tǒng)是另一個(gè)可以使用(通常也會(huì)使用)觀察者模式的例子携兵。在這種系統(tǒng)中疾掰,監(jiān)聽(tīng)者被用于監(jiān)聽(tīng)特定事件。監(jiān)聽(tīng)者正在監(jiān)聽(tīng)的事件被創(chuàng)建出來(lái)時(shí)徐紧,就會(huì)觸發(fā)它們静檬。這個(gè)事件可以是鍵入(鍵盤(pán)的)某個(gè)特定鍵、移動(dòng)鼠標(biāo)或者其他并级。事件扮演發(fā)布者的角色拂檩,監(jiān)聽(tīng)者則扮演觀察者的角色。在這里死遭,關(guān)鍵點(diǎn)是單個(gè)事件(發(fā)布者)可以關(guān)聯(lián)多個(gè)監(jiān)聽(tīng)者(觀察者),請(qǐng)參考網(wǎng)頁(yè)[t.cn/Rqr1Xgj]凯旋。

實(shí)現(xiàn)

本節(jié)中呀潭,我們將實(shí)現(xiàn)一個(gè)數(shù)據(jù)格式化程序钉迷。這里描述的想法來(lái)源于ActiveState網(wǎng)站上觀察者模式用法的Python代碼實(shí)現(xiàn)(請(qǐng)參考網(wǎng)頁(yè)[t.cn/Rqr1SDO])。默認(rèn)格式化程序是以十進(jìn)制格式展示一個(gè)數(shù)值钠署。然而糠聪,我們可以添加/注冊(cè)更多的格式化程序。這個(gè)例子中將添加一個(gè)十六進(jìn)制格式化程序和一個(gè)二進(jìn)制格式化程序谐鼎。每次更新默認(rèn)格式化程序的值時(shí)舰蟆,已注冊(cè)的格式化程序就會(huì)收到通知,并采取行動(dòng)狸棍。在這里身害,行動(dòng)就是以相關(guān)的格式展示新的值。

在一些模式中草戈,繼承能體現(xiàn)自身價(jià)值塌鸯,觀察者模式是這些模式中的一個(gè)。我們可以實(shí)現(xiàn)一個(gè)基類(lèi)Publisher唐片,包括添加丙猬、刪除及通知觀察者這些公用功能。DefaultFormatter類(lèi)繼承自Publisher费韭,并添加格式化程序特定的功能茧球。我們可以按需動(dòng)態(tài)地添加刪除觀察者。下面的類(lèi)圖展示了一個(gè)使用兩個(gè)觀察者(HexFormatter和BinaryFormatter)的示例星持。注意抢埋,因?yàn)轭?lèi)圖是靜態(tài)的,所以尤法展示系統(tǒng)的整個(gè)生命周期钉汗,只能展示某個(gè)特定時(shí)間點(diǎn)的系統(tǒng)狀態(tài)羹令。

從Publisher類(lèi)開(kāi)始說(shuō)起。觀察者們保存在列表observers中损痰。add()方法注冊(cè)一個(gè)新的觀察者福侈,或者在該觀察者已存在時(shí)引發(fā)一個(gè)錯(cuò)誤。remove()方法注銷(xiāo)一個(gè)已有觀察者卢未,或者在該觀察者尚未存在時(shí)引發(fā)一個(gè)錯(cuò)誤肪凛。最后,notify()方法則在變化發(fā)生時(shí)通知所有觀察者辽社。

class Publisher:
    def __init__(self):
        self.observers = []

    def add(self, observer):
        if observer not in self.observers:
            self.observers.append(observer)
        else:
            print('Failed to add: {}'.format(observer))

    def remove(self, observer):
        try:
            self.observers.remove(observer)
        except ValueError:
            print('Failed to remove: {}'.format(observer))

    def notify(self):
        [o.notify(self) for o in self.observers]

接著是DefaultFormatter類(lèi)伟墙。init()做的第一件事情就是調(diào)用基類(lèi)的init()方法,因?yàn)檫@在Python中沒(méi)法自動(dòng)完成滴铅。DefaultFormatter實(shí)例有自己的名字戳葵,這樣便于我們跟蹤其狀態(tài)。對(duì)于_data變量汉匙,我們使用了名稱(chēng)改編來(lái)聲明不能直接訪問(wèn)該變量拱烁。注意生蚁,Python中直接訪問(wèn)一個(gè)變量始終是可能的(請(qǐng)參考[Lott14,第54頁(yè)])戏自,不過(guò)資深開(kāi)發(fā)人員沒(méi)有借口這樣做邦投,因?yàn)榇a已經(jīng)聲明不應(yīng)該這樣做。這里使用名稱(chēng)改編是有一個(gè)嚴(yán)肅理由的擅笔。請(qǐng)繼續(xù)往下看志衣。DefaultFormatter把_data變量用作一個(gè)整數(shù),默認(rèn)值為零猛们。

class DefaultFormatter(Publisher):
    def __init__(self, name):
        Publisher.__init__(self)
        self.name = name
        self._data = 0

_str_()方法返回關(guān)于發(fā)布者名稱(chēng)和_data值的信息念脯。type(self). __name是一種獲取類(lèi)名的方便技巧,避免硬編碼類(lèi)名阅懦。這降低了代碼的可讀性和二,卻提高了可維護(hù)性。是否喜歡耳胎,要看你的選擇惯吕。

def str (self):
    return "{}: '{}' has data = {}".format(type(self).__name__, self.name, self._data)

類(lèi)中有兩個(gè)data()方法。第一個(gè)使用@property修飾器來(lái)提供_data變量的讀訪問(wèn)方式怕午。這樣废登,我們就能使用object.data來(lái)替代object.data()。

@property
def data(self):
    return self._data

第二個(gè)data()更有意思郁惜。它使用了@setter修飾器堡距,該修飾器會(huì)在每次使用賦值操作符(=)為_(kāi)data變量賦新值時(shí)被調(diào)用。該方法也會(huì)嘗試把新值強(qiáng)制類(lèi)型轉(zhuǎn)換為一個(gè)整數(shù)兆蕉,并在類(lèi)型轉(zhuǎn)換失敗時(shí)處理異常羽戒。

@data.setter
def data(self, new_value):
    try:
        self._data = int(new_value)
    except ValueError as e:
        print('Error: {}'.format(e))
    else:
        self.notify()

下一步是添加觀察者。HexFormatter和BinaryFormatter的功能非常相似虎韵。唯一的不同在于如何格式化從發(fā)布者那獲取到的數(shù)據(jù)值易稠,即分別以十六進(jìn)制和二進(jìn)制進(jìn)行格式化。

class HexFormatter:
    def notify(self, publisher):
        print("{}: '{}' has now hex data = {}".format(type(self).__name__, publisher.name, hex(publisher.data)))

class BinaryFormatter:
    def notify(self, publisher):
        print("{}: '{}' has now bin data = {}".format(type(self).__name__, publisher.name, bin(publisher.data)))

如果沒(méi)有測(cè)試數(shù)據(jù)包蓝,示例就不好玩了驶社。main()函數(shù)一開(kāi)始創(chuàng)建一個(gè)名為test1的Default-Formatter實(shí)例,并在之后關(guān)聯(lián)了兩個(gè)可用的觀察者测萎。也使用了異常處理來(lái)確保在用戶輸入問(wèn)題數(shù)據(jù)時(shí)應(yīng)用不會(huì)崩潰亡电。此外,諸如兩次添加相同的觀察者或刪除尚不存在的觀察者之類(lèi)的事情也不應(yīng)該導(dǎo)致崩潰硅瞧。

def main():
    df = DefaultFormatter('test1')
    print(df)
    print()
    hf = HexFormatter()
    df.add(hf)
    df.data = 3
    print(df)
    print()
    bf = BinaryFormatter()
    df.add(bf)
    df.data = 21
    print(df)
    print()
    df.remove(hf)
    df.data = 40
    print(df)
    print()
    df.remove(hf)
    df.add(bf)
    df.data = 'hello'
    print(df)
    print()
    df.data = 15.8
    print(df)

示例的完整代碼(observer.py)如下所示份乒。

class Publisher:
    def __init__(self):
        self.observers = []

    def add(self, observer):
        if observer not in self.observers:
            self.observers.append(observer)
        else:
            print('Failed to add: {}'.format(observer))

    def remove(self, observer):
        try:
            self.observers.remove(observer)
        except ValueError:
            print('Failed to remove: {}'.format(observer))

    def notify(self):
        [o.notify(self) for o in self.observers]

class DefaultFormatter(Publisher):
    def __init__(self, name):
        Publisher.__init__(self)
        self.name = name
        self._data = 0

    def __str__(self):
        return "{}: '{}' has data = {}".format(type(self).__name__, self.name, self._data)

    @property
    def data(self):
        return self._data

    @data.setter
    def data(self, new_value):
        try:
            self._data = int(new_value)
        except ValueError as e:
            print('Error: {}'.format(e))
        else:
            self.notify()

class HexFormatter:
    def notify(self, publisher):
        print("{}: '{}' has now hex data = {}".format(type(self).__name__, publisher.name, hex(publisher.data)))

class BinaryFormatter:
    def notify(self, publisher):
        print("{}: '{}' has now bin data = {}".format(type(self).__name__, publisher.name, bin(publisher.data)))

def main():
    df = DefaultFormatter('test1')
    print(df)

    print()
    hf = HexFormatter()
    df.add(hf)
    df.data = 3
    print(df)

    print()
    bf = BinaryFormatter()
    df.add(bf)
    df.data = 21
    print(df)

    print()
    df.remove(hf)
    df.data = 40
    print(df)

    print()
    df.remove(hf)
    df.add(bf)

    df.data = 'hello'
    print(df)

    print()
    df.data = 15.8
    print(df)

if __name__ == '__main__':
    main()
DefaultFormatter: 'test1' has data = 0

HexFormatter: 'test1' has now hex data = 0x3
DefaultFormatter: 'test1' has data = 3

HexFormatter: 'test1' has now hex data = 0x15
BinaryFormatter: 'test1' has now bin data = 0b10101
DefaultFormatter: 'test1' has data = 21

BinaryFormatter: 'test1' has now bin data = 0b101000
DefaultFormatter: 'test1' has data = 40

Failed to remove: <__main__.HexFormatter object at 0x1068730f0>
Failed to add: <__main__.BinaryFormatter object at 0x106873160>
Error: invalid literal for int() with base 10: 'hello'
DefaultFormatter: 'test1' has data = 40

BinaryFormatter: 'test1' has now bin data = 0b1111
DefaultFormatter: 'test1' has data = 15

執(zhí)行observer.py會(huì)輸出以下內(nèi)容。

python3 observer.py

DefaultFormatter: 'test1' has data = 0
HexFormatter: 'test1' has now hex data = 0x3
DefaultFormatter: 'test1' has data = 3
HexFormatter: 'test1' has now hex data = 0x15
BinaryFormatter: 'test1' has now bin data = 0b10101
DefaultFormatter: 'test1' has data = 21
BinaryFormatter: 'test1' has now bin data = 0b101000
DefaultFormatter: 'test1' has data = 40

Failed to remove: < main .HexFormatter object at 0x7f30a2fb82e8>
Failed to add: < main .BinaryFormatter object at 0x7f30a2fb8320>
Error: invalid literal for int() with base 10: 'hello'
BinaryFormatter: 'test1' has now bin data = 0b101000
DefaultFormatter: 'test1' has data = 40

BinaryFormatter: 'test1' has now bin data = 0b1111
DefaultFormatter: 'test1' has data = 15

在輸出中我們看到,添加額外的觀察者或辖,就會(huì)出現(xiàn)更多(相關(guān)的)輸出拇勃;一個(gè)觀察者被刪除后,就再也不會(huì)被通知到孝凌。這正是我們想要的,能夠按需啟用/禁用運(yùn)行時(shí)通知月腋。

應(yīng)用的防護(hù)性編程方面看起來(lái)也工作得不錯(cuò)蟀架。嘗試玩一些花樣都是不會(huì)被允許的,比如榆骚,刪除一個(gè)不存在的觀察者或者兩次添加相同的觀察者片拍。不過(guò),顯示的信息還不太友好妓肢,就留給你作為練習(xí)吧捌省。在API要求一個(gè)數(shù)字參數(shù)時(shí)輸出一個(gè)字符串所導(dǎo)致的運(yùn)行時(shí)失敗,也能得到正確處理碉钠,不會(huì)造成應(yīng)用崩潰/終止纲缓。

如果是交互式的,這個(gè)例子會(huì)有趣得多喊废。即使只是以一個(gè)簡(jiǎn)單的菜單形式允許用戶在運(yùn)行時(shí)綁定/解綁觀察者或修改DefaultFormatter的值祝高,也是不錯(cuò)的,因?yàn)檫@樣能看到更多的運(yùn)行時(shí)方面的信息污筷。請(qǐng)隨意來(lái)做吧工闺。

另一個(gè)不錯(cuò)的練習(xí)是添加更多的觀察者。例如瓣蛀,可以添加一個(gè)八進(jìn)制格式化程序陆蟆、羅馬數(shù)字格式化程序或使用你最?lèi)?ài)展現(xiàn)形式的任何其他觀察者。發(fā)揮你的創(chuàng)意惋增,享受樂(lè)趣吧叠殷!

小結(jié)

本章中,我們學(xué)習(xí)了觀察者設(shè)計(jì)模式器腋。若希望在一個(gè)對(duì)象的狀態(tài)變化時(shí)能夠通知/提醒所有相關(guān)者(一個(gè)對(duì)象或一組對(duì)象)溪猿,則可以使用觀察者模式。觀察者模式的一個(gè)重要特性是纫塌,在運(yùn)行時(shí)诊县,訂閱者/觀察者的數(shù)量以及觀察者是誰(shuí)可能會(huì)變化,也可以改變措左。

為理解觀察者模式依痊,你可以想一想拍賣(mài)會(huì)的場(chǎng)景,出價(jià)人是訂閱者,拍賣(mài)師是發(fā)布者胸嘁。這一模式在軟件領(lǐng)域的應(yīng)用非常多瓶摆。大體上,所有利用MVC模式的系統(tǒng)都是基于事件的性宏。作為具體的例子群井,我們提到了以下兩項(xiàng)。

  • django-observer毫胜,一個(gè)第三方Django庫(kù)书斜,用于注冊(cè)在模型字段變更時(shí)執(zhí)行的觀察者。
  • RabbitMQ的Python綁定酵使。我們介紹了一個(gè)RabbitMQ的具體例子荐吉,用于實(shí)現(xiàn)發(fā)布—訂閱(即觀察者)模式。

在實(shí)現(xiàn)例子中口渔,我們看到了如何使用觀察者模式創(chuàng)建可在運(yùn)行時(shí)綁定/解綁的數(shù)據(jù)格式化程序样屠,以此增強(qiáng)對(duì)象的行為。希望你會(huì)覺(jué)得推薦的練習(xí)比較有趣缺脉。

第14章介紹狀態(tài)設(shè)計(jì)模式痪欲,該模式可用于實(shí)現(xiàn)一個(gè)核心的計(jì)算機(jī)科學(xué)概念:狀態(tài)機(jī)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末攻礼,一起剝皮案震驚了整個(gè)濱河市勤揩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秘蛔,老刑警劉巖陨亡,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異深员,居然都是意外死亡负蠕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)倦畅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)遮糖,“玉大人,你說(shuō)我怎么就攤上這事叠赐∮耍” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵芭概,是天一觀的道長(zhǎng)赛不。 經(jīng)常有香客問(wèn)我,道長(zhǎng)罢洲,這世上最難降的妖魔是什么踢故? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上殿较,老公的妹妹穿的比我還像新娘耸峭。我一直安慰自己,他們只是感情好淋纲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布劳闹。 她就那樣靜靜地躺著,像睡著了一般洽瞬。 火紅的嫁衣襯著肌膚如雪玷或。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天片任,我揣著相機(jī)與錄音,去河邊找鬼蔬胯。 笑死对供,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的氛濒。 我是一名探鬼主播产场,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舞竿!你這毒婦竟也來(lái)了京景?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤骗奖,失蹤者是張志新(化名)和其女友劉穎确徙,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體执桌,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鄙皇,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仰挣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伴逸。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖膘壶,靈堂內(nèi)的尸體忽然破棺而出错蝴,到底是詐尸還是另有隱情,我是刑警寧澤颓芭,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布顷锰,位于F島的核電站,受9級(jí)特大地震影響亡问,放射性物質(zhì)發(fā)生泄漏馍惹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望万矾。 院中可真熱鬧悼吱,春花似錦、人聲如沸良狈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)薪丁。三九已至遇西,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間严嗜,已是汗流浹背粱檀。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漫玄,地道東北人茄蚯。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像睦优,于是被迫代替她去往敵國(guó)和親渗常。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理汗盘,服務(wù)發(fā)現(xiàn)皱碘,斷路器,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 工廠模式類(lèi)似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品隐孽,去做同樣的事情癌椿,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式。簡(jiǎn)單...
    舟漁行舟閱讀 7,758評(píng)論 2 17
  • 1 場(chǎng)景問(wèn)題# 1.1 訂閱報(bào)紙的過(guò)程## 來(lái)考慮實(shí)際生活中訂閱報(bào)紙的過(guò)程菱阵,這里簡(jiǎn)單總結(jié)了一下如失,訂閱報(bào)紙的基本流程...
    七寸知架構(gòu)閱讀 4,621評(píng)論 5 57
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,110評(píng)論 25 707
  • 1.籃球 那時(shí)我在念高三,學(xué)長(zhǎng)已經(jīng)大一送粱。 這節(jié)高考倒計(jì)時(shí)第七天的自習(xí)課褪贵,我已經(jīng)開(kāi)始焦躁,在教室里如坐針氈抗俄,書(shū)翻來(lái)翻...
    壹本正經(jīng)閱讀 815評(píng)論 0 1