Python設(shè)計(jì)模式之責(zé)任鏈模式

責(zé)任鏈模式

開發(fā)一個(gè)應(yīng)用時(shí),多數(shù)時(shí)候我們都能預(yù)先知道哪個(gè)方法能處理某個(gè)特定請(qǐng)求居暖。然而乃秀,情況并非總是如此肛著。例如,想想任意一種廣播計(jì)算機(jī)網(wǎng)絡(luò)跺讯,例如最早的以太網(wǎng)實(shí)現(xiàn)(請(qǐng)參考網(wǎng)頁[t.cn/RqrTp0Y])枢贿。在廣播計(jì)算機(jī)網(wǎng)絡(luò)中,會(huì)將所有請(qǐng)求發(fā)送給所有節(jié)點(diǎn)(簡(jiǎn)單起見刀脏,不考慮廣播域)局荚,但僅對(duì)所發(fā)送請(qǐng)求感興趣的節(jié)點(diǎn)會(huì)處理請(qǐng)求。加入廣播網(wǎng)絡(luò)的所有計(jì)算機(jī)使用一種常見的媒介相互連接,比如耀态,下圖中的三個(gè)節(jié)點(diǎn)通過光纜連接起來轮傍。

如果一個(gè)節(jié)點(diǎn)對(duì)某個(gè)請(qǐng)求不感興趣或者不知道如何處理這個(gè)請(qǐng)求,可以執(zhí)行以下兩個(gè)操作首装。

  • 忽略這個(gè)請(qǐng)求创夜,什么都不做
  • 將請(qǐng)求轉(zhuǎn)發(fā)給下一個(gè)節(jié)點(diǎn)

節(jié)點(diǎn)對(duì)一個(gè)請(qǐng)求的反應(yīng)方式是實(shí)現(xiàn)的細(xì)節(jié)。然而仙逻,我們可以使用廣播計(jì)算機(jī)網(wǎng)絡(luò)的類比來理解責(zé)任鏈模式是什么驰吓。責(zé)任鏈(Chain of Responsibility)模式用于讓多個(gè)對(duì)象來處理單個(gè)請(qǐng)求時(shí),或者用于預(yù)先不知道應(yīng)該由哪個(gè)對(duì)象(來自某個(gè)對(duì)象鏈)來處理某個(gè)特定請(qǐng)求時(shí)系奉。其原則如下所示檬贰。

(1) 存在一個(gè)對(duì)象鏈(鏈表、樹或任何其他便捷的數(shù)據(jù)結(jié)構(gòu))缺亮。
(2) 我們一開始將請(qǐng)求發(fā)送給鏈中的第一個(gè)對(duì)象翁涤。
(3) 對(duì)象決定其是否要處理該請(qǐng)求。
(4) 對(duì)象將請(qǐng)求轉(zhuǎn)發(fā)給下一個(gè)對(duì)象萌踱。
(5) 重復(fù)該過程葵礼,直到到達(dá)鏈尾。

在應(yīng)用級(jí)別虫蝶,不用討論光纜和網(wǎng)絡(luò)節(jié)點(diǎn)章咧,而是可以專注于對(duì)象以及請(qǐng)求的流程。下圖展示了客戶端代碼如何將請(qǐng)求發(fā)送給應(yīng)用的所有處理元素(又稱為節(jié)點(diǎn)或處理程序)能真,經(jīng)www.sourcema-king.com允許使用(請(qǐng)參考網(wǎng)頁[t.cn/RqrTYuB])赁严。

注意,客戶端代碼僅知道第一個(gè)處理元素粉铐,而非擁有對(duì)所有處理元素的引用疼约;并且每個(gè)處理元素僅知道其直接的下一個(gè)鄰居(稱為后繼),而不知道所有其他處理元素蝙泼。這通常是一種單向關(guān)系程剥,用編程術(shù)語來說是一個(gè)單向鏈表,與之相反的是雙向鏈表汤踏。單向鏈表不允許雙向地遍歷元素织鲸,雙向鏈表則是允許的。這種鏈?zhǔn)浇M織方式大有用處:可以解耦發(fā)送方(客戶端)和接收方(處理元素)(請(qǐng)參考[GOF95溪胶,第254頁])搂擦。

以下例子來自于GitHub:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""http://www.dabeaz.com/coroutines/"""

from contextlib import contextmanager
import os
import sys
import time


class Handler(object):

    def __init__(self, successor=None):
        self._successor = successor

    def handle(self, request):
        res = self._handle(request)
        if not res:
            self._successor.handle(request)

    def _handle(self, request):
        raise NotImplementedError('Must provide implementation in subclass.')


class ConcreteHandler1(Handler):

    def _handle(self, request):
        if 0 < request <= 10:
            print('request {} handled in handler 1'.format(request))
            return True


class ConcreteHandler2(Handler):

    def _handle(self, request):
        if 10 < request <= 20:
            print('request {} handled in handler 2'.format(request))
            return True


class ConcreteHandler3(Handler):

    def _handle(self, request):
        if 20 < request <= 30:
            print('request {} handled in handler 3'.format(request))
            return True


class DefaultHandler(Handler):

    def _handle(self, request):
        print('end of chain, no handler for {}'.format(request))
        return True


class Client(object):

    def __init__(self):
        self.handler = ConcreteHandler1(
            ConcreteHandler3(ConcreteHandler2(DefaultHandler())))

    def delegate(self, requests):
        for request in requests:
            self.handler.handle(request)


def coroutine(func):
    def start(*args, **kwargs):
        cr = func(*args, **kwargs)
        next(cr)
        return cr
    return start


@coroutine
def coroutine1(target):
    while True:
        request = yield
        if 0 < request <= 10:
            print('request {} handled in coroutine 1'.format(request))
        else:
            target.send(request)


@coroutine
def coroutine2(target):
    while True:
        request = yield
        if 10 < request <= 20:
            print('request {} handled in coroutine 2'.format(request))
        else:
            target.send(request)


@coroutine
def coroutine3(target):
    while True:
        request = yield
        if 20 < request <= 30:
            print('request {} handled in coroutine 3'.format(request))
        else:
            target.send(request)


@coroutine
def default_coroutine():
    while True:
        request = yield
        print('end of chain, no coroutine for {}'.format(request))


class ClientCoroutine:

    def __init__(self):
        self.target = coroutine1(coroutine3(coroutine2(default_coroutine())))

    def delegate(self, requests):
        for request in requests:
            self.target.send(request)


def timeit(func):

    def count(*args, **kwargs):
        start = time.time()
        res = func(*args, **kwargs)
        count._time = time.time() - start
        return res
    return count


@contextmanager
def suppress_stdout():
    try:
        stdout, sys.stdout = sys.stdout, open(os.devnull, 'w')
        yield
    finally:
        sys.stdout = stdout


if __name__ == "__main__":
    client1 = Client()
    client2 = ClientCoroutine()
    requests = [2, 5, 14, 22, 18, 3, 35, 27, 20]

    client1.delegate(requests)
    print('-' * 30)
    client2.delegate(requests)

    requests *= 10000
    client1_delegate = timeit(client1.delegate)
    client2_delegate = timeit(client2.delegate)
    with suppress_stdout():
        client1_delegate(requests)
        client2_delegate(requests)
    # lets check what is faster
    print(client1_delegate._time, client2_delegate._time)

### OUTPUT ###
# request 2 handled in handler 1
# request 5 handled in handler 1
# request 14 handled in handler 2
# request 22 handled in handler 3
# request 18 handled in handler 2
# request 3 handled in handler 1
# end of chain, no handler for 35
# request 27 handled in handler 3
# request 20 handled in handler 2
# ------------------------------
# request 2 handled in coroutine 1
# request 5 handled in coroutine 1
# request 14 handled in coroutine 2
# request 22 handled in coroutine 3
# request 18 handled in coroutine 2
# request 3 handled in coroutine 1
# end of chain, no coroutine for 35
# request 27 handled in coroutine 3
# request 20 handled in coroutine 2
# (0.2369999885559082, 0.16199994087219238)

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

ATM機(jī)以及及一般而言用于接收/返回鈔票或硬幣的任意類型機(jī)器(比如,零食自動(dòng)販賣機(jī))都使用了責(zé)任鏈模式哗脖。機(jī)器上總會(huì)有一個(gè)放置各種鈔票的槽口瀑踢,如下圖所示(經(jīng)www.sourcemaking.com允許使用)扳还。

鈔票放入之后,會(huì)被傳遞到恰當(dāng)?shù)娜萜鞒髫病bn票返回時(shí)氨距,則是從恰當(dāng)?shù)娜萜髦蝎@取(請(qǐng)參考網(wǎng)頁[t.cn/RqrTYuB]和網(wǎng)頁[t.cn/RqrTnts])棘劣。我們可以把這個(gè)槽口視為共享通信媒介俏让,不同的容器則是處理元素。結(jié)果包含來自一個(gè)或多個(gè)容器的現(xiàn)金呈础。例如舆驶,在上圖中橱健,我們看到在從ATM機(jī)取175美元時(shí)會(huì)發(fā)生什么而钞。

軟件的例子

我試過尋找一些使用責(zé)任鏈模式的Python應(yīng)用的好例子,但是沒找到拘荡,很可能是因?yàn)镻ython程序員不使用這個(gè)名稱臼节。因此,很抱歉珊皿,我將使用其他編程語言的例子作為參考网缝。

Java的servlet過濾器是在一個(gè)HTTP請(qǐng)求到達(dá)H標(biāo)處理程序之前執(zhí)行的一些代碼片段。在使用servlet過濾器時(shí)蟋定,有一個(gè)過濾器鏈粉臊,其中每個(gè)過濾器執(zhí)行一個(gè)不同動(dòng)作(用戶身份驗(yàn)證、記H志驶兜、數(shù)據(jù)壓縮等)扼仲,并且將請(qǐng)求轉(zhuǎn)發(fā)給下一個(gè)過濾器直到鏈結(jié)束;如果發(fā)生錯(cuò)誤(例如抄淑,連續(xù)三次身份驗(yàn)證失斖佬住)則跳出處理流程(請(qǐng)參考網(wǎng)頁[t.cn/RqrTukH])。

Apple的Cocoa和Cocoa Touch框架使用責(zé)任鏈來處理事件肆资。在某個(gè)視圖接收到一個(gè)其并不知道如何處理的事件時(shí)矗愧,會(huì)將事件轉(zhuǎn)發(fā)給其超視圖,直到有個(gè)視圖能夠處理這個(gè)事件或者視圖鏈結(jié)束(請(qǐng)參考網(wǎng)頁[t.cn/RqrTrzK])郑原。

應(yīng)用案例

通過使用責(zé)任鏈模式唉韭,我們能讓許多不同對(duì)象來處理一個(gè)特定請(qǐng)求。在我們預(yù)先不知道應(yīng)該由哪個(gè)對(duì)象來處理某個(gè)請(qǐng)求時(shí)犯犁,這是有用的属愤。其中一個(gè)例子是采購系統(tǒng)。在采購系統(tǒng)中栖秕,有許多核準(zhǔn)權(quán)限春塌。某個(gè)核準(zhǔn)權(quán)限可能可以核準(zhǔn)在一定額度之內(nèi)的訂單,假設(shè)為100美元。如果訂單超過了100美元只壳,則會(huì)將訂單發(fā)送給鏈中的下一個(gè)核準(zhǔn)權(quán)限俏拱,比如能夠核準(zhǔn)在200美元以下的訂單,等等吼句。

另一個(gè)責(zé)任鏈可以派上用場(chǎng)的場(chǎng)景是锅必,在我們知道可能會(huì)有多個(gè)對(duì)象都需要對(duì)同一個(gè)請(qǐng)求進(jìn)行處理之時(shí)。這在基于事件的編程中是常有的事情惕艳。單個(gè)事件搞隐,比如一次鼠標(biāo)左擊,可被多個(gè)事件監(jiān)聽者捕獲远搪。

不過應(yīng)該注意劣纲,如果所有請(qǐng)求都能被單個(gè)處理程序處理,責(zé)任鏈就沒那么有用了谁鳍,除非確實(shí)不知道會(huì)是哪個(gè)程序處理請(qǐng)求癞季。這一模式的價(jià)值在于解耦√惹保客戶端與所有處理程序(一個(gè)處理程序與所有其他處理程序之間也是如此)之間不再是多對(duì)多關(guān)系绷柒,客戶端僅需要知道如何與鏈的起始節(jié)點(diǎn)(標(biāo)頭)進(jìn)行通信。

下圖演示了緊耦合與松耦合之間的區(qū)別心涮因。松耦合系統(tǒng)背后的考慮是簡(jiǎn)化維護(hù)废睦,并讓我們易于理解系統(tǒng)的工作原理(請(qǐng)參考網(wǎng)頁https://infomgmt.wordpress.com/2010/02/18/a-visual-respresen-tation-of-coupling/)。

數(shù)據(jù)耦合(data coupling)养泡、特征耦合(stamp coupling)嗜湃、控制耦合(control coupling)、共用耦合(common coupling)和內(nèi)容耦合(content coupling)這幾個(gè)概念的含義可參考Wikipedia詞條 https://en.wikipedia.org/wiki/Coupling_(computer_programming)瓤荔。 ——譯者注

實(shí)現(xiàn)

使用Python實(shí)現(xiàn)責(zé)任鏈模式有許多種方式净蚤,但是我最喜歡的實(shí)現(xiàn)是Vespe Savikko所提出的(請(qǐng)參考網(wǎng)頁[t.cn/RqruSj1])。Vespe的實(shí)現(xiàn)以地道的Python風(fēng)格使用動(dòng)態(tài)分發(fā)來處理請(qǐng)求(請(qǐng)參考網(wǎng)頁[t.cn/RqruWFp])输硝。

我們以Vespe的實(shí)現(xiàn)為參考實(shí)現(xiàn)一個(gè)簡(jiǎn)單的事件系統(tǒng)今瀑。下面是該系統(tǒng)的UML類圖。

Event類描述一個(gè)事件点把。為了讓它簡(jiǎn)單一點(diǎn)橘荠,在我們的案例中一個(gè)事件只有一個(gè)name屬性。

class Event:

    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

Widget類是應(yīng)用的核心類郎逃。UML圖中展示的parent聚合關(guān)系表明每個(gè)控件都有一個(gè)到父對(duì)象的引用哥童。按照約定,我們假定父對(duì)象是一個(gè)Widget實(shí)例褒翰。然而贮懈,注意匀泊,根據(jù)繼承的規(guī)則,任何Widget子類的實(shí)例(例如朵你,MsgText的實(shí)例)也是Widget實(shí)例各聘。parent的默認(rèn)值為None。

class Widget:
    def __init__(self, parent=None):
        self.parent = parent

handle()方法使用動(dòng)態(tài)分發(fā)抡医,通過hasattr()和getattr()決定一個(gè)特定請(qǐng)求(event)應(yīng)該由誰來處理躲因。如果被請(qǐng)求處理事件的控件并不支持該事件,則有兩種回退機(jī)制忌傻。如果控件有parent大脉,則執(zhí)行parent的handle()方法。如果控件沒有parent水孩,但有handle_default()方法镰矿,則執(zhí)行handle_default()。

def handle(self, event):
    handler = 'handle_{}'.format(event)
    if hasattr(self, handler):
        method = getattr(self, handler)
        method(event)
    elif self.parent:
        self.parent.handle(event)
    elif hasattr(self, 'handle_default'):
        self.handle_default(event)

此時(shí)荷愕,你可能已明臼為什么UML類圖中Widget與Event類僅是關(guān)聯(lián)關(guān)系而已(不是聚合或組合關(guān)系)衡怀。關(guān)聯(lián)關(guān)系用于表明Widget類知道Event類,但對(duì)其沒有任何嚴(yán)格的引用安疗,因?yàn)槭录H需要作為參數(shù)傳遞給handle()。

MainWindow够委、MsgText和SendDialog是具有不同行為的控件荐类。我們并不期望這三個(gè)控件都能處理相同的事件,即使它們能處理相同事件茁帽,表現(xiàn)出來也可能是不同的玉罐。MainWindow僅能處理close和default事件。

class MainWindow(Widget):
    def handle_close(self, event):
        print('MainWindow: {}'.format(event))
    def handle_default(self, event):
        print('MainWindow Default: {}'.format(event))

SendDialog僅能處理paint事件潘拨。

class SendDialog(Widget):
        def handle_paint(self, event):
            print('SendDialog: {}'.format(event))

最后吊输,MsgText僅能處理down事件。

class MsgText(Widget):
    def handle_down(self, event):
        print('MsgText: {}'.format(event))

main()函數(shù)展示如何創(chuàng)建一些控件和事件铁追,以及控件如何對(duì)那些事件作出反應(yīng)季蚂。所有事件都會(huì)被發(fā)送給所有控件。注意其中每個(gè)控件的父子關(guān)系琅束。sd對(duì)象(SendDialog的一個(gè)實(shí)例)的父對(duì)象是mw(MainWindow的一個(gè)實(shí)例)扭屁。然而,并不是所有對(duì)象都需要一個(gè)MainWindow實(shí)例的父對(duì)象涩禀。例如料滥,msg對(duì)象(MsgText的一個(gè)實(shí)例)是以sd作為父對(duì)象。

def main(): 5 mw = MainWindow()
    sd = SendDialog(mw)
    msg = MsgText(sd)
    for e in ('down', 'paint', 'unhandled', 'close'):
        evt = Event(e)
        print('\nSending event -{}- to MainWindow'.format(evt))
        mw.handle(evt)
        print('Sending event -{}- to SendDialog'.format(evt))
        sd.handle(evt)
        print('Sending event -{}- to MsgText'.format(evt))
        msg.handle(evt)

以下是示例的完整代碼(chain.py)艾船。

class Event:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name

class Widget:
    def __init__(self, parent=None):
        self.parent = parent

    def handle(self, event):
        handler = 'handle_{}'.format(event)
        if hasattr(self, handler):
            method = getattr(self, handler)
            method(event)
        elif self.parent:
            self.parent.handle(event)
        elif hasattr(self, 'handle_default'):
            self.handle_default(event)

class MainWindow(Widget):
    def handle_close(self, event):
        print('MainWindow: {}'.format(event))

    def handle_default(self, event):
        print('MainWindow Default: {}'.format(event))

class SendDialog(Widget):
    def handle_paint(self, event):
        print('SendDialog: {}'.format(event))

class MsgText(Widget):
    def handle_down(self, event):
        print('MsgText: {}'.format(event))

def main():
    mw = MainWindow()
    sd = SendDialog(mw)
    msg = MsgText(sd)

    for e in ('down', 'paint', 'unhandled', 'close'):
        evt = Event(e)
        print('\nSending event -{}- to MainWindow'.format(evt))
        mw.handle(evt)
        print('Sending event -{}- to SendDialog'.format(evt))
        sd.handle(evt)
        print('Sending event -{}- to MsgText'.format(evt))
        msg.handle(evt)

if __name__ == '__main__':
    main()
Sending event -down- to MainWindow
MainWindow Default: down
Sending event -down- to SendDialog
MainWindow Default: down
Sending event -down- to MsgText
MsgText: down

Sending event -paint- to MainWindow
MainWindow Default: paint
Sending event -paint- to SendDialog
SendDialog: paint
Sending event -paint- to MsgText
SendDialog: paint

Sending event -unhandled- to MainWindow
MainWindow Default: unhandled
Sending event -unhandled- to SendDialog
MainWindow Default: unhandled
Sending event -unhandled- to MsgText
MainWindow Default: unhandled

Sending event -close- to MainWindow
MainWindow: close
Sending event -close- to SendDialog
MainWindow: close
Sending event -close- to MsgText
MainWindow: close

從輸出中我們能看到一些有趣的東西葵腹。例如高每,發(fā)送一個(gè)down事件給MainWindow,最終被MainWindow默認(rèn)處理函數(shù)處理践宴。另一個(gè)不錯(cuò)的用例是觉义,雖然close事件不能被SendDialog和MsgText直接處理,但所有close事件最終都能被MainWindow正確處理浴井。這正是使用父子關(guān)系作為一種回退機(jī)制的優(yōu)美之處晒骇。

如果你想在這個(gè)事件例子上花費(fèi)更多時(shí)間發(fā)揮自己的創(chuàng)意,可以替換這些愚蠢的print語旬磺浙,針對(duì)羅列出來的事件添加一些實(shí)際的行為洪囤。當(dāng)然,并不限于羅列出來的事件撕氧。隨意添加一些你喜歡的事件匪蝙,做一些有用的事情!

另一個(gè)練習(xí)是在運(yùn)行時(shí)添加一個(gè)MsgText實(shí)例蒙谓,以MainWindow為其父芝雪。這個(gè)有難度嗎?也挑個(gè)事件類型來試試(為一個(gè)已有控件添加一個(gè)新的事件)不脯,哪個(gè)更難府怯?

小結(jié)

本章中,我們學(xué)習(xí)了責(zé)任鏈設(shè)計(jì)模式防楷。在尤法預(yù)先知道處理程序的數(shù)量和類型時(shí)牺丙,該模式有助于對(duì)請(qǐng)求/處理事件進(jìn)行建模。適合使用責(zé)任鏈模式的系統(tǒng)例子包括基于事件的系統(tǒng)复局、采購系統(tǒng)和運(yùn)輸系統(tǒng)冲簿。

在責(zé)任鏈模式中,發(fā)送方可直接訪問鏈中的首個(gè)節(jié)點(diǎn)亿昏。若首個(gè)節(jié)點(diǎn)不能處理請(qǐng)求峦剔,則轉(zhuǎn)發(fā)給下一個(gè)節(jié)點(diǎn),如此直到請(qǐng)求被某個(gè)節(jié)點(diǎn)處理或者整個(gè)鏈遍歷結(jié)束角钩。這種設(shè)計(jì)用于實(shí)現(xiàn)發(fā)送方與接收方(多個(gè))之間的解耦吝沫。

ATM機(jī)是責(zé)任鏈的一個(gè)例子。用于取放鈔票的槽口可看作是鏈的頭部彤断。從這里開始野舶,根據(jù)具體交易,一個(gè)或多個(gè)容器會(huì)被用于處理交易宰衙。這些容器可看作是鏈中的處理程序平道。

Java的servlet過濾器使用責(zé)任鏈模式對(duì)一個(gè)HTTP請(qǐng)求執(zhí)行不同的動(dòng)作(例如,壓縮和身份驗(yàn)證)供炼。Apple的Cocoa框架使用相同的模式來處理事件一屋,比如窘疮,按鈕和手勢(shì)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末冀墨,一起剝皮案震驚了整個(gè)濱河市闸衫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诽嘉,老刑警劉巖蔚出,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異虫腋,居然都是意外死亡骄酗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門悦冀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來趋翻,“玉大人,你說我怎么就攤上這事盒蟆√だ樱” “怎么了?”我有些...
    開封第一講書人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵历等,是天一觀的道長(zhǎng)讨惩。 經(jīng)常有香客問我,道長(zhǎng)募闲,這世上最難降的妖魔是什么步脓? 我笑而不...
    開封第一講書人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮浩螺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘仍侥。我一直安慰自己要出,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開白布农渊。 她就那樣靜靜地躺著患蹂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砸紊。 梳的紋絲不亂的頭發(fā)上传于,一...
    開封第一講書人閱讀 52,807評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音醉顽,去河邊找鬼沼溜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛游添,可吹牛的內(nèi)容都是我干的系草。 我是一名探鬼主播通熄,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼找都!你這毒婦竟也來了唇辨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤能耻,失蹤者是張志新(化名)和其女友劉穎赏枚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晓猛,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饿幅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鞍帝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诫睬。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖帕涌,靈堂內(nèi)的尸體忽然破棺而出摄凡,到底是詐尸還是另有隱情,我是刑警寧澤蚓曼,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布亲澡,位于F島的核電站,受9級(jí)特大地震影響纫版,放射性物質(zhì)發(fā)生泄漏床绪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一其弊、第九天 我趴在偏房一處隱蔽的房頂上張望癞己。 院中可真熱鬧,春花似錦梭伐、人聲如沸痹雅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绩社。三九已至,卻和暖如春赂苗,著一層夾襖步出監(jiān)牢的瞬間愉耙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工拌滋, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朴沿,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓鸠真,卻偏偏與公主長(zhǎng)得像悯仙,于是被迫代替她去往敵國(guó)和親龄毡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,336評(píng)論 25 707
  • 職責(zé)鏈 1.概述 你去政府部門求人辦事過嗎锡垄?有時(shí)候你會(huì)遇到過官員踢球推責(zé)沦零,你的問題在我這里能解決就解決,不能...
    derivator_2閱讀 443評(píng)論 0 0
  • 第一章 Nginx簡(jiǎn)介 Nginx是什么 沒有聽過Nginx货岭?那么一定聽過它的“同行”Apache吧路操!Ngi...
    JokerW閱讀 32,704評(píng)論 24 1,002
  • 寫在前面的碎碎念 雖然對(duì)韓國(guó)并沒有如果追星族一樣的狂熱。因?yàn)殡x京較近千贯,再加上目前便宜的出境費(fèi)用屯仗,和放心大膽的買買買...
    桃小圈閱讀 695評(píng)論 0 2
  • 引言 就在我作為人母自我感覺良好,覺得自己是一個(gè)對(duì)孩子很有耐心搔谴、愛心的媽媽的時(shí)候魁袜,我今天打了孩子。 打孩子時(shí)敦第,我自...
    松樹愛姜姜閱讀 232評(píng)論 1 0