《JAVA與模式》— 迭代子模式

在閻宏博士的《JAVA與模式》一書(shū)中開(kāi)頭是這樣描述迭代子(Iterator)模式的:

迭代子模式又叫游標(biāo)(Cursor)模式,是對(duì)象的行為模式。迭代子模式可以順序地訪問(wèn)一個(gè)聚集中的元素而不必暴露聚集的內(nèi)部表象(internal representation)蛹屿。

聚集和JAVA聚集

多個(gè)對(duì)象聚在一起形成的總體稱之為聚集(Aggregate)竞漾,聚集對(duì)象是能夠包容一組對(duì)象的容器對(duì)象仿耽。聚集依賴于聚集結(jié)構(gòu)的抽象化合冀,具有復(fù)雜化和多樣性。數(shù)組就是最基本的聚集项贺,也是其他的JAVA聚集對(duì)象的設(shè)計(jì)基礎(chǔ)君躺。

JAVA聚集對(duì)象是實(shí)現(xiàn)了共同的java.util.Collection接口的對(duì)象,是JAVA語(yǔ)言對(duì)聚集概念的直接支持开缎。從1.2版開(kāi)始棕叫,JAVA語(yǔ)言提供了很多種聚集,包括Vector啥箭、ArrayList谍珊、HashSet治宣、HashMap急侥、Hashtable等,這些都是JAVA聚集的例子侮邀。

迭代子模式的結(jié)構(gòu)

迭代子模式有兩種實(shí)現(xiàn)方式坏怪,分別是白箱聚集與外稟迭代子和黑箱聚集于內(nèi)稟迭代子。

白箱聚集與外稟迭代子

如果一個(gè)聚集的接口提供了可以用來(lái)修改聚集元素的方法绊茧,這個(gè)接口就是所謂的寬接口铝宵。

如果聚集對(duì)象為所有對(duì)象提供同一個(gè)接口,也就是寬接口的話,當(dāng)然會(huì)滿足迭代子模式對(duì)迭代子對(duì)象的要求鹏秋。但是尊蚁,這樣會(huì)破壞對(duì)聚集對(duì)象的封裝。這種提供寬接口的聚集叫做白箱聚集侣夷。聚集對(duì)象向外界提供同樣的寬接口横朋,如下圖所示:


在這里插入圖片描述

由于聚集自己實(shí)現(xiàn)迭代邏輯,并向外部提供適當(dāng)?shù)慕涌诎偻兀沟玫涌梢詮耐獠靠刂凭奂氐牡^(guò)程琴锭。這樣一來(lái)迭代子所控制的僅僅是一個(gè)游標(biāo)而已,這種迭代子叫做游標(biāo)迭代子(Cursor Iterator)衙传。由于迭代子是在聚集結(jié)構(gòu)之外的决帖,因此這樣的迭代子又叫做外稟迭代子(Extrinsic Iterator)。

現(xiàn)在看一看白箱聚集與外稟迭代子的實(shí)現(xiàn)蓖捶。一個(gè)白箱聚集向外界提供訪問(wèn)自己內(nèi)部元素的接口(稱作遍歷方法或者Traversing Method)地回,從而使外稟迭代子可以通過(guò)聚集的遍歷方法實(shí)現(xiàn)迭代功能。

因?yàn)榈倪壿嬍怯删奂瘜?duì)象本身提供的腺阳,所以這樣的外稟迭代子角色往往僅僅保持迭代的游標(biāo)位置落君。

一個(gè)典型的由白箱聚集與外稟迭代子組成的系統(tǒng)如下圖所示,在這個(gè)實(shí)現(xiàn)中具體迭代子角色是一個(gè)外部類亭引,而具體聚集角色向外界提供遍歷聚集元素的接口绎速。


在這里插入圖片描述

迭代子模式涉及到以下幾個(gè)角色:

●  抽象迭代子(Iterator)角色:此抽象角色定義出遍歷元素所需的接口。
●  具體迭代子(ConcreteIterator)角色:此角色實(shí)現(xiàn)了Iterator接口焙蚓,并保持迭代過(guò)程中的游標(biāo)位置纹冤。
●  聚集(Aggregate)角色:此抽象角色給出創(chuàng)建迭代子(Iterator)對(duì)象的接口。
●  具體聚集(ConcreteAggregate)角色:實(shí)現(xiàn)了創(chuàng)建迭代子(Iterator)對(duì)象的接口购公,返回一個(gè)合適的具體迭代子實(shí)例萌京。
●  客戶端(Client)角色:持有對(duì)聚集及其迭代子對(duì)象的引用,調(diào)用迭代子對(duì)象的迭代接口宏浩,也有可能通過(guò)迭代子操作聚集元素的增加和刪除知残。

源代碼

抽象聚集角色類,這個(gè)角色規(guī)定出所有的具體聚集必須實(shí)現(xiàn)的接口比庄。迭代子模式要求聚集對(duì)象必須有一個(gè)工廠方法求妹,也就是createIterator()方法,以向外界提供迭代子對(duì)象的實(shí)例佳窑。

public abstract class Aggregate {
    /**
     * 工廠方法制恍,創(chuàng)建相應(yīng)迭代子對(duì)象的接口
     */
    public abstract Iterator createIterator();
}

具體聚集角色類,實(shí)現(xiàn)了抽象聚集角色類所要求的接口神凑,也就是createIterator()方法净神。此外何吝,還有方法getElement()向外界提供聚集元素,而方法size()向外界提供聚集的大小等鹃唯。

public class ConcreteAggregate extends Aggregate {
    
    private Object[] objArray = null;
    /**
     * 構(gòu)造方法爱榕,傳入聚合對(duì)象的具體內(nèi)容
     */
    public ConcreteAggregate(Object[] objArray){
        this.objArray = objArray;
    }
    
    @Override
    public Iterator createIterator() {
        
        return new ConcreteIterator(this);
    }
    /**
     * 取值方法:向外界提供聚集元素
     */
    public Object getElement(int index){
        
        if(index < objArray.length){
            return objArray[index];
        }else{
            return null;
        }
    }
    /**
     * 取值方法:向外界提供聚集的大小
     */
    public int size(){
        return objArray.length;
    }
}

抽象迭代子角色類

public interface Iterator {
    /**
     * 迭代方法:移動(dòng)到第一個(gè)元素
     */
    public void first();
    /**
     * 迭代方法:移動(dòng)到下一個(gè)元素
     */
    public void next();
    /**
     * 迭代方法:是否為最后一個(gè)元素
     */
    public boolean isDone();
    /**
     * 迭代方法:返還當(dāng)前元素
     */
    public Object currentItem();
}

具體迭代子角色類

public class ConcreteIterator implements Iterator {
    //持有被迭代的具體的聚合對(duì)象
    private ConcreteAggregate agg;
    //內(nèi)部索引,記錄當(dāng)前迭代到的索引位置
    private int index = 0;
    //記錄當(dāng)前聚集對(duì)象的大小
    private int size = 0;
    
    public ConcreteIterator(ConcreteAggregate agg){
        this.agg = agg;
        this.size = agg.size();
        index = 0;
    }
    /**
     * 迭代方法:返還當(dāng)前元素
     */
    @Override
    public Object currentItem() {
        return agg.getElement(index);
    }
    /**
     * 迭代方法:移動(dòng)到第一個(gè)元素
     */
    @Override
    public void first() {
        
        index = 0;
    }
    /**
     * 迭代方法:是否為最后一個(gè)元素
     */
    @Override
    public boolean isDone() {
        return (index >= size);
    }
    /**
     * 迭代方法:移動(dòng)到下一個(gè)元素
     */
    @Override
    public void next() {

        if(index < size)
        {
            index ++;
        }
    }

}

客戶端類

public class Client {

    public void operation(){
        Object[] objArray = {"One","Two","Three","Four","Five","Six"};
        //創(chuàng)建聚合對(duì)象
        Aggregate agg = new ConcreteAggregate(objArray);
        //循環(huán)輸出聚合對(duì)象中的值
        Iterator it = agg.createIterator();
        while(!it.isDone()){
            System.out.println(it.currentItem());
            it.next();
        }
    }
    public static void main(String[] args) {
        
        Client client = new Client();
        client.operation();
    }

}

上面的例子首先創(chuàng)建了一個(gè)聚集類實(shí)例坡慌,然后調(diào)用聚集對(duì)象的工廠方法createIterator()以得到一個(gè)迭代子對(duì)象呆细。在得到迭代子的實(shí)例后,客戶端開(kāi)始迭代過(guò)程八匠,打印出所有的聚集元素絮爷。

外稟迭代子的意義

一個(gè)常常會(huì)問(wèn)的問(wèn)題是:既然白箱聚集已經(jīng)向外界提供了遍歷方法,客戶端已經(jīng)可以自行進(jìn)行迭代了梨树,為什么還要應(yīng)用迭代子模式坑夯,并創(chuàng)建一個(gè)迭代子對(duì)象進(jìn)行迭代呢?

客戶端當(dāng)然可以自行進(jìn)行迭代抡四,不一定非得需要一個(gè)迭代子對(duì)象柜蜈。但是,迭代子對(duì)象和迭代模式會(huì)將迭代過(guò)程抽象化指巡,將作為迭代消費(fèi)者的客戶端與迭代負(fù)責(zé)人的迭代子責(zé)任分隔開(kāi)淑履,使得兩者可以獨(dú)立的演化。在聚集對(duì)象的種類發(fā)生變化藻雪,或者迭代的方法發(fā)生改變時(shí)秘噪,迭代子作為一個(gè)中介層可以吸收變化的因素,而避免修改客戶端或者聚集本身勉耀。

此外指煎,如果系統(tǒng)需要同時(shí)針對(duì)幾個(gè)不同的聚集對(duì)象進(jìn)行迭代,而這些聚集對(duì)象所提供的遍歷方法有所不同時(shí)便斥,使用迭代子模式和一個(gè)外界的迭代子對(duì)象是有意義的至壤。具有同一迭代接口的不同迭代子對(duì)象處理具有不同遍歷接口的聚集對(duì)象,使得系統(tǒng)可以使用一個(gè)統(tǒng)一的迭代接口進(jìn)行所有的迭代枢纠。

黑箱聚集與內(nèi)稟迭代子

如果一個(gè)聚集的接口沒(méi)有提供修改聚集元素的方法像街,這樣的接口就是所謂的窄接口。

聚集對(duì)象為迭代子對(duì)象提供一個(gè)寬接口晋渺,而為其他對(duì)象提供一個(gè)窄接口镰绎。換言之,聚集對(duì)象的內(nèi)部結(jié)構(gòu)應(yīng)當(dāng)對(duì)迭代子對(duì)象適當(dāng)公開(kāi)些举,以便迭代子對(duì)象能夠?qū)奂瘜?duì)象有足夠的了解跟狱,從而可以進(jìn)行迭代操作俭厚。但是户魏,聚集對(duì)象應(yīng)當(dāng)避免向其他的對(duì)象提供這些方法,因?yàn)槠渌麑?duì)象應(yīng)當(dāng)經(jīng)過(guò)迭代子對(duì)象進(jìn)行這些工作,而不是直接操控聚集對(duì)象叼丑。


在這里插入圖片描述

在JAVA語(yǔ)言中关翎,實(shí)現(xiàn)雙重接口的辦法就是將迭代子類設(shè)計(jì)成聚集類的內(nèi)部成員類。這樣迭代子對(duì)象將可以像聚集對(duì)象的內(nèi)部成員一樣訪問(wèn)聚集對(duì)象的內(nèi)部結(jié)構(gòu)鸠信。下面給出一個(gè)示意性的實(shí)現(xiàn)纵寝,說(shuō)明這種雙重接口的結(jié)構(gòu)時(shí)怎么樣產(chǎn)生的,以及使用了雙重接口結(jié)構(gòu)之后迭代子模式的實(shí)現(xiàn)方案星立。這種同時(shí)保證聚集對(duì)象的封裝和迭代子功能的實(shí)現(xiàn)的方案叫做黑箱實(shí)現(xiàn)方案爽茴。

由于迭代子是聚集的內(nèi)部類,迭代子可以自由訪問(wèn)聚集的元素绰垂,所以迭代子可以自行實(shí)現(xiàn)迭代功能并控制對(duì)聚集元素的迭代邏輯室奏。由于迭代子是在聚集的結(jié)構(gòu)之內(nèi)定義的,因此這樣的迭代子又叫做內(nèi)稟迭代子(Intrinsic Iterator)劲装。

為了說(shuō)明黑箱方案的細(xì)節(jié)胧沫,這里給出一個(gè)示意性的黑箱實(shí)現(xiàn)。在這個(gè)實(shí)現(xiàn)里占业,聚集類ConcreteAggregate含有一個(gè)內(nèi)部成員類ConcreteIterator绒怨,也就是實(shí)現(xiàn)了抽象迭代子接口的具體迭代子類,同時(shí)聚集并不向外界提供訪問(wèn)自己內(nèi)部元素的方法谦疾。

在這里插入圖片描述

源代碼

抽象聚集角色類南蹂,這個(gè)角色規(guī)定出所有的具體聚集必須實(shí)現(xiàn)的接口。迭代子模式要求聚集對(duì)象必須有一個(gè)工廠方法念恍,也就是createIterator()方法碎紊,以向外界提供迭代子對(duì)象的實(shí)例。

public abstract class Aggregate {
    /**
     * 工廠方法樊诺,創(chuàng)建相應(yīng)迭代子對(duì)象的接口
     */
    public abstract Iterator createIterator();
}

抽象迭代子角色類

public interface Iterator {
    /**
     * 迭代方法:移動(dòng)到第一個(gè)元素
     */
    public void first();
    /**
     * 迭代方法:移動(dòng)到下一個(gè)元素
     */
    public void next();
    /**
     * 迭代方法:是否為最后一個(gè)元素
     */
    public boolean isDone();
    /**
     * 迭代方法:返還當(dāng)前元素
     */
    public Object currentItem();
}

具體聚集角色類仗考,實(shí)現(xiàn)了抽象聚集角色所要求的接口,也就是createIterator()方法词爬。此外秃嗜,聚集類有一個(gè)內(nèi)部成員類ConcreteIterator,這個(gè)內(nèi)部類實(shí)現(xiàn)了抽象迭代子角色所規(guī)定的接口顿膨;而工廠方法createIterator()所返還的就是這個(gè)內(nèi)部成員類的實(shí)例锅锨。

public class ConcreteAggregate extends Aggregate {
    
    private Object[] objArray = null;
    /**
     * 構(gòu)造方法,傳入聚合對(duì)象的具體內(nèi)容
     */
    public ConcreteAggregate(Object[] objArray){
        this.objArray = objArray;
    }
    
    @Override
    public Iterator createIterator() {

        return new ConcreteIterator();
    }
    /**
     * 內(nèi)部成員類恋沃,具體迭代子類
     */
    private class ConcreteIterator implements Iterator
    {
        //內(nèi)部索引必搞,記錄當(dāng)前迭代到的索引位置
        private int index = 0;
        //記錄當(dāng)前聚集對(duì)象的大小
        private int size = 0;
        /**
         * 構(gòu)造函數(shù)
         */
        public ConcreteIterator(){
            
            this.size = objArray.length;
            index = 0;
        }
        /**
         * 迭代方法:返還當(dāng)前元素
         */
        @Override
        public Object currentItem() {
            return objArray[index];
        }
        /**
         * 迭代方法:移動(dòng)到第一個(gè)元素
         */
        @Override
        public void first() {
            
            index = 0;
        }
        /**
         * 迭代方法:是否為最后一個(gè)元素
         */
        @Override
        public boolean isDone() {
            return (index >= size);
        }
        /**
         * 迭代方法:移動(dòng)到下一個(gè)元素
         */
        @Override
        public void next() {

            if(index < size)
            {
                index ++;
            }
        }
    }
}

客戶端類

public class Client {

    public void operation(){
        Object[] objArray = {"One","Two","Three","Four","Five","Six"};
        //創(chuàng)建聚合對(duì)象
        Aggregate agg = new ConcreteAggregate(objArray);
        //循環(huán)輸出聚合對(duì)象中的值
        Iterator it = agg.createIterator();
        while(!it.isDone()){
            System.out.println(it.currentItem());
            it.next();
        }
    }
    public static void main(String[] args) {
        
        Client client = new Client();
        client.operation();
    }

}

上面的例子首先創(chuàng)建了一個(gè)聚集類實(shí)例,然后調(diào)用聚集對(duì)象的工廠方法createIterator()以得到一個(gè)迭代子對(duì)象囊咏。在得到迭代子的實(shí)例后恕洲,客戶端開(kāi)始迭代過(guò)程塔橡,打印出所有的聚集元素。

主動(dòng)迭代子和被動(dòng)迭代子

主動(dòng)迭代子和被動(dòng)迭代子又稱作外部迭代子和內(nèi)部迭代子霜第。

所謂主動(dòng)(外部)迭代子葛家,指的是由客戶端來(lái)控制迭代下一個(gè)元素的步驟,客戶端會(huì)明顯調(diào)用迭代子的next()等迭代方法泌类,在遍歷過(guò)程中向前進(jìn)行癞谒。

所謂被動(dòng)(內(nèi)部)迭代子,指的是由迭代子自己來(lái)控制迭代下一個(gè)元素的步驟刃榨。因此弹砚,如果想要在迭代的過(guò)程中完成工作的話,客戶端就需要把操作傳遞給迭代子枢希,迭代子在迭代的時(shí)候會(huì)在每個(gè)元素上執(zhí)行這個(gè)操作迅栅,類似于JAVA的回調(diào)機(jī)制。

總體來(lái)說(shuō)外部迭代器比內(nèi)部迭代器要靈活一些晴玖,因此我們常見(jiàn)的實(shí)現(xiàn)多屬于主動(dòng)迭代子读存。

靜態(tài)迭代子和動(dòng)態(tài)迭代子

●  靜態(tài)迭代子由聚集對(duì)象創(chuàng)建,并持有聚集對(duì)象的一份快照(snapshot)呕屎,在產(chǎn)生后這個(gè)快照的內(nèi)容就不再變化让簿。客戶端可以繼續(xù)修改原聚集的內(nèi)容秀睛,但是迭代子對(duì)象不會(huì)反映出聚集的新變化尔当。

靜態(tài)迭代子的好處是它的安全性和簡(jiǎn)易性,換言之蹂安,靜態(tài)迭代子易于實(shí)現(xiàn)椭迎,不容易出現(xiàn)錯(cuò)誤。但是由于靜態(tài)迭代子將原聚集復(fù)制了一份田盈,因此它的短處是對(duì)時(shí)間和內(nèi)存資源的消耗畜号。

●  動(dòng)態(tài)迭代子則與靜態(tài)迭代子完全相反,在迭代子被產(chǎn)生之后允瞧,迭代子保持著對(duì)聚集元素的引用简软,因此,任何對(duì)原聚集內(nèi)容的修改都會(huì)在迭代子對(duì)象上反映出來(lái)述暂。

完整的動(dòng)態(tài)迭代子不容易實(shí)現(xiàn)痹升,但是簡(jiǎn)化的動(dòng)態(tài)迭代子并不難實(shí)現(xiàn)。大多數(shù)JAVA設(shè)計(jì)師遇到的迭代子都是這種簡(jiǎn)化的動(dòng)態(tài)迭代子畦韭。為了說(shuō)明什么是簡(jiǎn)化的動(dòng)態(tài)迭代子疼蛾,首先需要介紹一個(gè)新的概念:Fail Fast。

Fail Fast

如果一個(gè)算法開(kāi)始之后艺配,它的運(yùn)算環(huán)境發(fā)生變化察郁,使得算法無(wú)法進(jìn)行必需的調(diào)整時(shí)衍慎,這個(gè)算法就應(yīng)當(dāng)立即發(fā)出故障信號(hào)。這就是Fail Fast的含義绳锅。

如果聚集對(duì)象的元素在一個(gè)動(dòng)態(tài)迭代子的迭代過(guò)程中發(fā)生變化時(shí),迭代過(guò)程會(huì)受到影響而變得不能自恰酝掩。這時(shí)候鳞芙,迭代子就應(yīng)當(dāng)立即拋出一個(gè)異常。這種迭代子就是實(shí)現(xiàn)了Fail Fast功能的迭代子期虾。

Fail Fast在JAVA聚集中的使用

JAVA語(yǔ)言以接口java.util.Iterator的方式支持迭代子模式原朝,Collection接口要求提供iterator()方法,此方法在調(diào)用時(shí)返還一個(gè)Iterator類型的對(duì)象镶苞。而作為Collection接口的子類型喳坠,AbstractList類的內(nèi)部成員類Itr便是實(shí)現(xiàn)Iterator接口的類。

Itr類的源代碼如下所示

    private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         */
        int cursor = 0;

        /**
         * Index of element returned by most recent call to next or
         * previous.  Reset to -1 if this element is deleted by a call
         * to remove.
         */
        int lastRet = -1;

        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         */
        int expectedModCount = modCount;

        public boolean hasNext() {
                return cursor != size();
        }

        public E next() {
                checkForComodification();
            try {
            E next = get(cursor);
            lastRet = cursor++;
            return next;
            } catch (IndexOutOfBoundsException e) {
            checkForComodification();
            throw new NoSuchElementException();
            }
        }

        public void remove() {
            if (lastRet == -1)
            throw new IllegalStateException();
                checkForComodification();

            try {
            AbstractList.this.remove(lastRet);
            if (lastRet < cursor)
                cursor--;
            lastRet = -1;
            expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
            throw new ConcurrentModificationException();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
            throw new ConcurrentModificationException();
        }
    }

從Itr類的源代碼中可以看到茂蚓,方法checkForComodification()會(huì)檢查聚集的內(nèi)容是否剛剛被外界直接修改過(guò)(不是通過(guò)迭代子提供的方法修改的)壕鹉。如果在迭代開(kāi)始后,聚集的內(nèi)容被外界繞過(guò)迭代子對(duì)象而直接修改的話聋涨,這個(gè)方法會(huì)立即拋出ConcurrentModificationException()異常晾浴。

這就是說(shuō),AbstractList.Itr迭代子是一個(gè)Fail Fast的迭代子牍白。

迭代子模式的優(yōu)點(diǎn)

(1)迭代子模式簡(jiǎn)化了聚集的接口脊凰。迭代子具備了一個(gè)遍歷接口,這樣聚集的接口就不必具備遍歷接口茂腥。
(2)每一個(gè)聚集對(duì)象都可以有一個(gè)或多個(gè)迭代子對(duì)象狸涌,每一個(gè)迭代子的迭代狀態(tài)可以是彼此獨(dú)立的。因此最岗,一個(gè)聚集對(duì)象可以同時(shí)有幾個(gè)迭代在進(jìn)行之中帕胆。
(3)由于遍歷算法被封裝在迭代子角色里面,因此迭代的算法可以獨(dú)立于聚集角色變化般渡。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惶楼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子诊杆,更是在濱河造成了極大的恐慌歼捐,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晨汹,死亡現(xiàn)場(chǎng)離奇詭異豹储,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)淘这,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門剥扣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)巩剖,“玉大人,你說(shuō)我怎么就攤上這事钠怯〖涯В” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵晦炊,是天一觀的道長(zhǎng)鞠鲜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)断国,這世上最難降的妖魔是什么贤姆? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮稳衬,結(jié)果婚禮上霞捡,老公的妹妹穿的比我還像新娘。我一直安慰自己薄疚,他們只是感情好碧信,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著街夭,像睡著了一般音婶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上莱坎,一...
    開(kāi)封第一講書(shū)人閱讀 51,301評(píng)論 1 301
  • 那天衣式,我揣著相機(jī)與錄音,去河邊找鬼檐什。 笑死碴卧,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的乃正。 我是一名探鬼主播住册,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瓮具!你這毒婦竟也來(lái)了荧飞?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤名党,失蹤者是張志新(化名)和其女友劉穎叹阔,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體传睹,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耳幢,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片睛藻。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡启上,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出店印,到底是詐尸還是另有隱情冈在,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布按摘,位于F島的核電站包券,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏院峡。R本人自食惡果不足惜兴使,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一系宜、第九天 我趴在偏房一處隱蔽的房頂上張望照激。 院中可真熱鬧,春花似錦盹牧、人聲如沸俩垃。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)口柳。三九已至,卻和暖如春有滑,著一層夾襖步出監(jiān)牢的瞬間跃闹,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工毛好, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留望艺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓肌访,卻偏偏與公主長(zhǎng)得像找默,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吼驶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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