設(shè)計(jì)模式 | 原型模式及典型應(yīng)用

前言

本文的主要內(nèi)容如下:

  • 介紹原型模式
  • 示例
    • Java語言的clone
    • 淺克隆與深克隆
    • 實(shí)現(xiàn)深克隆
  • 原型模式的典型應(yīng)用

原型模式

原型模式(Prototype Pattern):使用原型實(shí)例指定創(chuàng)建對(duì)象的種類得滤,并且通過拷貝這些原型創(chuàng)建新的對(duì)象陨献。原型模式是一種對(duì)象創(chuàng)建型模式。

原型模式的工作原理很簡單:將一個(gè)原型對(duì)象傳給那個(gè)要發(fā)動(dòng)創(chuàng)建的對(duì)象懂更,這個(gè)要發(fā)動(dòng)創(chuàng)建的對(duì)象通過請(qǐng)求原型對(duì)象拷貝自己來實(shí)現(xiàn)創(chuàng)建過程眨业。

原型模式是一種“另類”的創(chuàng)建型模式急膀,創(chuàng)建克隆對(duì)象的工廠就是原型類自身,工廠方法由克隆方法來實(shí)現(xiàn)龄捡。

需要注意的是通過克隆方法所創(chuàng)建的對(duì)象是全新的對(duì)象卓嫂,它們在內(nèi)存中擁有新的地址,通常對(duì)克隆所產(chǎn)生的對(duì)象進(jìn)行修改對(duì)原型對(duì)象不會(huì)造成任何影響聘殖,每一個(gè)克隆對(duì)象都是相互獨(dú)立的晨雳。通過不同的方式修改可以得到一系列相似但不完全相同的對(duì)象。

角色

  • Prototype(抽象原型類):它是聲明克隆方法的接口奸腺,是所有具體原型類的公共父類悍募,可以是抽象類也可以是接口,甚至還可以是具體實(shí)現(xiàn)類洋机。
  • ConcretePrototype(具體原型類):它實(shí)現(xiàn)在抽象原型類中聲明的克隆方法坠宴,在克隆方法中返回自己的一個(gè)克隆對(duì)象。
  • Client(客戶類):讓一個(gè)原型對(duì)象克隆自身從而創(chuàng)建一個(gè)新的對(duì)象绷旗,在客戶類中只需要直接實(shí)例化或通過工廠方法等方式創(chuàng)建一個(gè)原型對(duì)象喜鼓,再通過調(diào)用該對(duì)象的克隆方法即可得到多個(gè)相同的對(duì)象。由于客戶類針對(duì)抽象原型類Prototype編程衔肢,因此用戶可以根據(jù)需要選擇具體原型類庄岖,系統(tǒng)具有較好的可擴(kuò)展性,增加或更換具體原型類都很方便角骤。

原型模式的核心在于如何實(shí)現(xiàn)克隆方法隅忿。

示例

Java語言提供的clone()方法

學(xué)過Java語言的人都知道,所有的Java類都繼承自 java.lang.Object邦尊。事實(shí)上背桐,Object 類提供一個(gè) clone() 方法,可以將一個(gè)Java對(duì)象復(fù)制一份蝉揍。因此在Java中可以直接使用 Object 提供的 clone() 方法來實(shí)現(xiàn)對(duì)象的克隆链峭,Java語言中的原型模式實(shí)現(xiàn)很簡單。

需要注意的是能夠?qū)崿F(xiàn)克隆的Java類必須實(shí)現(xiàn)一個(gè) 標(biāo)識(shí)接口 Cloneable又沾,表示這個(gè)Java類支持被復(fù)制弊仪。如果一個(gè)類沒有實(shí)現(xiàn)這個(gè)接口但是調(diào)用了clone()方法,Java編譯器將拋出一個(gè) CloneNotSupportedException 異常杖刷。

public class Mail implements Cloneable{
    private String name;
    private String emailAddress;
    private String content;
    public Mail(){
        System.out.println("Mail Class Constructor");
    }
    // ...省略 getter励饵、setter
    @Override
    protected Object clone() throws CloneNotSupportedException {
        System.out.println("clone mail object");
        return super.clone();
    }
}

在客戶端創(chuàng)建原型對(duì)象和克隆對(duì)象也很簡單,如下代碼所示:

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Mail mail = new Mail();
        mail.setContent("初始化模板");
        System.out.println("初始化mail:"+mail);
        for(int i = 0;i < 3;i++){
            System.out.println();
            Mail mailTemp = (Mail) mail.clone();
            mailTemp.setName("姓名"+i);
            mailTemp.setEmailAddress("姓名"+i+"@test.com");
            mailTemp.setContent("恭喜您滑燃,此次抽獎(jiǎng)活動(dòng)中獎(jiǎng)了");
            MailUtil.sendMail(mailTemp);
            System.out.println("克隆的mailTemp:"+mailTemp);
        }
        MailUtil.saveOriginMailRecord(mail);
    }
}

其中的 MailUtil 工具類為

public class MailUtil {
    public static void sendMail(Mail mail) {
        String outputContent = "向{0}同學(xué),郵件地址:{1},郵件內(nèi)容:{2}發(fā)送郵件成功";
        System.out.println(MessageFormat.format(outputContent, mail.getName(), mail.getEmailAddress(), mail.getContent()));
    }

    public static void saveOriginMailRecord(Mail mail) {
        System.out.println("存儲(chǔ)originMail記錄,originMail:" + mail.getContent());
    }
}

輸出如下:

Mail Class Constructor
初始化mail:Mail{name='null', emailAddress='null', content='初始化模板'}com.designpattern.prototype.Mail@12edcd21

clone mail object
向姓名0同學(xué),郵件地址:姓名0@test.com,郵件內(nèi)容:恭喜您役听,此次抽獎(jiǎng)活動(dòng)中獎(jiǎng)了發(fā)送郵件成功
克隆的mailTemp:Mail{name='姓名0', emailAddress='姓名0@test.com', content='恭喜您,此次抽獎(jiǎng)活動(dòng)中獎(jiǎng)了'}com.designpattern.prototype.Mail@34c45dca

clone mail object
向姓名1同學(xué),郵件地址:姓名1@test.com,郵件內(nèi)容:恭喜您,此次抽獎(jiǎng)活動(dòng)中獎(jiǎng)了發(fā)送郵件成功
克隆的mailTemp:Mail{name='姓名1', emailAddress='姓名1@test.com', content='恭喜您禾嫉,此次抽獎(jiǎng)活動(dòng)中獎(jiǎng)了'}com.designpattern.prototype.Mail@52cc8049

clone mail object
向姓名2同學(xué),郵件地址:姓名2@test.com,郵件內(nèi)容:恭喜您,此次抽獎(jiǎng)活動(dòng)中獎(jiǎng)了發(fā)送郵件成功
克隆的mailTemp:Mail{name='姓名2', emailAddress='姓名2@test.com', content='恭喜您蚊丐,此次抽獎(jiǎng)活動(dòng)中獎(jiǎng)了'}com.designpattern.prototype.Mail@5b6f7412
存儲(chǔ)originMail記錄,originMail:初始化模板

從輸出結(jié)果中我們可以觀察到:

  • for循環(huán)中的 mailTemp 從 mail 對(duì)象中克隆得到熙参,它們的內(nèi)存地址均不同,說明不是同一個(gè)對(duì)象麦备,克隆成功孽椰,克隆僅僅通過調(diào)用 super.clone() 即可。
  • 最后調(diào)用的 MailUtil.saveOriginMailRecord(mail); 中的 mail 對(duì)象的內(nèi)容仍為 for 循環(huán)之前設(shè)置的內(nèi)容凛篙,并沒有因?yàn)榭寺《淖儭?/li>
  • 克隆的時(shí)候調(diào)用了 clone 方法黍匾,并沒有調(diào)用 Mail 類的構(gòu)造器,只在最前面 new 的時(shí)候才調(diào)用了一次

關(guān)于輸出的內(nèi)存地址是怎么輸出的呛梆,我們還需要看一下 Object#toString 方法

public class Object {
    public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    //...省略...
}

所以所謂的內(nèi)存地址即為 hashCode() 的十六進(jìn)制表示锐涯,這里簡單的認(rèn)為 內(nèi)存地址相同則為同一個(gè)對(duì)象,不同則為不同對(duì)象

再來看一眼 Object#clone 方法

protected native Object clone() throws CloneNotSupportedException;

這是一個(gè) native 關(guān)鍵字修飾的方法

一般而言填物,Java語言中的clone()方法滿足:

  • 對(duì)任何對(duì)象x纹腌,都有 x.clone() != x,即克隆對(duì)象與原型對(duì)象不是同一個(gè)對(duì)象滞磺;
  • 對(duì)任何對(duì)象x升薯,都有 x.clone().getClass() == x.getClass(),即克隆對(duì)象與原型對(duì)象的類型一樣击困;
  • 如果對(duì)象x的 equals() 方法定義恰當(dāng)涎劈,那么 x.clone().equals(x) 應(yīng)該成立。

為了獲取對(duì)象的一份拷貝阅茶,我們可以直接利用Object類的clone()方法蛛枚,具體步驟如下:

  1. 在派生類中覆蓋基類的 clone() 方法,并聲明為public脸哀;
  2. 在派生類的 clone() 方法中坤候,調(diào)用 super.clone()
  3. 派生類需實(shí)現(xiàn)Cloneable接口企蹭。

此時(shí)白筹,Object類相當(dāng)于抽象原型類,所有實(shí)現(xiàn)了Cloneable接口的類相當(dāng)于具體原型類谅摄。

淺克隆與深克隆

看下面的示例

public class Pig implements Cloneable{
    private String name;
    private Date birthday;
    // ...getter, setter, construct
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Pig pig = (Pig)super.clone();
        return pig;
    }
    @Override
    public String toString() {
        return "Pig{" +
                "name='" + name + '\'' +
                ", birthday=" + birthday +
                '}'+super.toString();
    }
}

測試

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Date birthday = new Date(0L);
        Pig pig1 = new Pig("佩奇",birthday);
        Pig pig2 = (Pig) pig1.clone();
        System.out.println(pig1);
        System.out.println(pig2);

        pig1.getBirthday().setTime(666666666666L);

        System.out.println(pig1);
        System.out.println(pig2);
    }
}

輸出如下

Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.designpattern.clone.Pig@27973e9b
Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.designpattern.clone.Pig@312b1dae
Pig{name='佩奇', birthday=Sat Feb 16 09:11:06 CST 1991}com.designpattern.clone.Pig@27973e9b
Pig{name='佩奇', birthday=Sat Feb 16 09:11:06 CST 1991}com.designpattern.clone.Pig@312b1dae

我們照著上一小節(jié)說的實(shí)現(xiàn) Cloneable徒河,調(diào)用 super.clone(); 進(jìn)行克隆,中間我們對(duì) pig1 對(duì)象設(shè)置了一個(gè)時(shí)間戳送漠,從輸出中我們可以發(fā)現(xiàn)什么問題呢顽照?

我們可以發(fā)現(xiàn):

  • pig1pig2 的內(nèi)存地址不同
  • 對(duì) pig1 設(shè)置了時(shí)間,同事 pig2 的時(shí)間也改變了

我們通過 debug 來看一下

debug查看對(duì)象地址

發(fā)現(xiàn)如下:

  • pig1 與 pig2 地址不一樣
  • pig1 的 birthday 與 pig2 的 birthday 一樣

這里引出淺拷貝與深拷貝。

在Java語言中代兵,數(shù)據(jù)類型分為值類型(基本數(shù)據(jù)類型)和引用類型尼酿,值類型包括int、double植影、byte裳擎、boolean、char等簡單數(shù)據(jù)類型思币,引用類型包括類鹿响、接口、數(shù)組等復(fù)雜類型谷饿。

淺克隆和深克隆的主要區(qū)別在于是否支持引用類型的成員變量的復(fù)制惶我,下面將對(duì)兩者進(jìn)行詳細(xì)介紹。

淺克虏┩丁:

  • 在淺克隆中绸贡,如果原型對(duì)象的成員變量是值類型,將復(fù)制一份給克隆對(duì)象毅哗;如果原型對(duì)象的成員變量是引用類型恃轩,則將引用對(duì)象的地址復(fù)制一份給克隆對(duì)象,也就是說原型對(duì)象和克隆對(duì)象的成員變量指向相同的內(nèi)存地址黎做。

  • 簡單來說叉跛,在淺克隆中,當(dāng)對(duì)象被復(fù)制時(shí)只復(fù)制它本身和其中包含的值類型的成員變量蒸殿,而引用類型的成員對(duì)象并沒有復(fù)制筷厘。

  • 在Java語言中,通過覆蓋Object類的clone()方法可以實(shí)現(xiàn)淺克隆宏所。

深克滤盅蕖:

  • 在深克隆中,無論原型對(duì)象的成員變量是值類型還是引用類型爬骤,都將復(fù)制一份給克隆對(duì)象充石,深克隆將原型對(duì)象的所有引用對(duì)象也復(fù)制一份給克隆對(duì)象。

  • 簡單來說霞玄,在深克隆中骤铃,除了對(duì)象本身被復(fù)制外,對(duì)象所包含的所有成員變量也將復(fù)制坷剧。

  • 在Java語言中惰爬,如果需要實(shí)現(xiàn)深克隆,可以通過序列化(Serialization)等方式來實(shí)現(xiàn)惫企。需要注意的是能夠?qū)崿F(xiàn)序列化的對(duì)象其類必須實(shí)現(xiàn)Serializable接口撕瞧,否則無法實(shí)現(xiàn)序列化操作。

實(shí)現(xiàn)深克隆

方式一,手動(dòng)對(duì)引用對(duì)象進(jìn)行克麓园妗:

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Pig pig = (Pig)super.clone();

        //深克隆
        pig.birthday = (Date) pig.birthday.clone();
        return pig;
    }

方式二巩掺,通過序列化的方式:

public class Pig implements Serializable {
    private String name;
    private Date birthday;
    // ...省略 getter, setter等

    protected Object deepClone() throws CloneNotSupportedException, IOException, ClassNotFoundException {
        //將對(duì)象寫入流中
        ByteArrayOutputStream bao = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bao);
        oos.writeObject(this);

        //將對(duì)象從流中取出
        ByteArrayInputStream bis = new ByteArrayInputStream(bao.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (ois.readObject());
    }
}
序列化方式的深克隆結(jié)果

破壞單例模式

餓漢式單例模式如下:

public class HungrySingleton implements Serializable, Cloneable {

    private final static HungrySingleton hungrySingleton;

    static {
        hungrySingleton = new HungrySingleton();
    }
    private HungrySingleton() {
        if (hungrySingleton != null) {
            throw new RuntimeException("單例構(gòu)造器禁止反射調(diào)用");
        }
    }
    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }
    private Object readResolve() {
        return hungrySingleton;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

使用反射獲取對(duì)象,測試如下

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        Method method = hungrySingleton.getClass().getDeclaredMethod("clone");
        method.setAccessible(true);
        HungrySingleton cloneHungrySingleton = (HungrySingleton) method.invoke(hungrySingleton);
        System.out.println(hungrySingleton);
        System.out.println(cloneHungrySingleton);
    }
}

輸出

com.designpattern.HungrySingleton@34c45dca
com.designpattern.HungrySingleton@52cc8049

可以看到页畦,通過原型模式胖替,我們把單例模式給破壞了,現(xiàn)在有兩個(gè)對(duì)象了

為了防止單例模式被破壞寇漫,我們可以:不實(shí)現(xiàn) Cloneable 接口;或者把 clone 方法改為如下

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return getInstance();
    }

原型模式的典型應(yīng)用

  1. Object 類中的 clone 接口
  2. Cloneable 接口的實(shí)現(xiàn)類殉摔,可以看到至少一千多個(gè)州胳,找?guī)讉€(gè)例子譬如:
Cloneable接口的實(shí)現(xiàn)類

ArrayList 對(duì) clone 的重寫如下:

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }
    //...省略
}

調(diào)用 super.clone(); 之后把 elementData 數(shù)據(jù) copy 了一份

同理,我們看看 HashMap 對(duì) clone 方法的重寫:

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
    @Override
    public Object clone() {
        HashMap<K,V> result;
        try {
            result = (HashMap<K,V>)super.clone();
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
        result.reinitialize();
        result.putMapEntries(this, false);
        return result;
    }
    // ...省略...
}

mybatis 中的 org.apache.ibatis.cache.CacheKey 對(duì) clone 方法的重寫:

public class CacheKey implements Cloneable, Serializable {
    private List<Object> updateList;
    public CacheKey clone() throws CloneNotSupportedException {
        CacheKey clonedCacheKey = (CacheKey)super.clone();
        clonedCacheKey.updateList = new ArrayList(this.updateList);
        return clonedCacheKey;
    }
    // ... 省略...
}

這里又要注意逸月,updateListList<Object> 類型栓撞,所以可能是值類型的List,也可能是引用類型的List碗硬,克隆的結(jié)果需要注意是否為深克隆或者淺克隆

使用原始模式的時(shí)候一定要注意為深克隆還是淺克隆瓤湘。

原型模式總結(jié)

原型模式的主要優(yōu)點(diǎn)如下:

  • 當(dāng)創(chuàng)建新的對(duì)象實(shí)例較為復(fù)雜時(shí),使用原型模式可以簡化對(duì)象的創(chuàng)建過程恩尾,通過復(fù)制一個(gè)已有實(shí)例可以提高新實(shí)例的創(chuàng)建效率弛说。
  • 擴(kuò)展性較好,由于在原型模式中提供了抽象原型類翰意,在客戶端可以針對(duì)抽象原型類進(jìn)行編程木人,而將具體原型類寫在配置文件中,增加或減少產(chǎn)品類對(duì)原有系統(tǒng)都沒有任何影響冀偶。
  • 原型模式提供了簡化的創(chuàng)建結(jié)構(gòu)醒第,工廠方法模式常常需要有一個(gè)與產(chǎn)品類等級(jí)結(jié)構(gòu)相同的工廠等級(jí)結(jié)構(gòu),而原型模式就不需要這樣进鸠,原型模式中產(chǎn)品的復(fù)制是通過封裝在原型類中的克隆方法實(shí)現(xiàn)的稠曼,無須專門的工廠類來創(chuàng)建產(chǎn)品。
  • 可以使用深克隆的方式保存對(duì)象的狀態(tài)客年,使用原型模式將對(duì)象復(fù)制一份并將其狀態(tài)保存起來霞幅,以便在需要的時(shí)候使用(如恢復(fù)到某一歷史狀態(tài)),可輔助實(shí)現(xiàn)撤銷操作量瓜。

原型模式的主要缺點(diǎn)如下:

  • 需要為每一個(gè)類配備一個(gè)克隆方法蝗岖,而且該克隆方法位于一個(gè)類的內(nèi)部,當(dāng)對(duì)已有的類進(jìn)行改造時(shí)榔至,需要修改源代碼抵赢,違背了“開閉原則”。
  • 在實(shí)現(xiàn)深克隆時(shí)需要編寫較為復(fù)雜的代碼,而且當(dāng)對(duì)象之間存在多重的嵌套引用時(shí)铅鲤,為了實(shí)現(xiàn)深克隆划提,每一層對(duì)象對(duì)應(yīng)的類都必須支持深克隆,實(shí)現(xiàn)起來可能會(huì)比較麻煩邢享。

適用場景:

  • 創(chuàng)建新對(duì)象成本較大(如初始化需要占用較長的時(shí)間鹏往,占用太多的CPU資源或網(wǎng)絡(luò)資源),新的對(duì)象可以通過原型模式對(duì)已有對(duì)象進(jìn)行復(fù)制來獲得骇塘,如果是相似對(duì)象伊履,則可以對(duì)其成員變量稍作修改。
  • 如果系統(tǒng)要保存對(duì)象的狀態(tài)款违,而對(duì)象的狀態(tài)變化很小唐瀑,或者對(duì)象本身占用內(nèi)存較少時(shí),可以使用原型模式配合備忘錄模式來實(shí)現(xiàn)插爹。
  • 需要避免使用分層次的工廠類來創(chuàng)建分層次的對(duì)象哄辣,并且類的實(shí)例對(duì)象只有一個(gè)或很少的幾個(gè)組合狀態(tài),通過復(fù)制原型對(duì)象得到新實(shí)例可能比使用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例更加方便赠尾。

參考:
劉偉:設(shè)計(jì)模式Java版
慕課網(wǎng)java設(shè)計(jì)模式精講 Debug 方式+內(nèi)存分析

后記

歡迎評(píng)論力穗、轉(zhuǎn)發(fā)、分享气嫁,您的支持是我最大的動(dòng)力

更多內(nèi)容可訪問我的個(gè)人博客:http://laijianfeng.org

關(guān)注【小旋鋒】微信公眾號(hào)当窗,及時(shí)接收博文推送

關(guān)注_小旋鋒_微信公眾號(hào)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市寸宵,隨后出現(xiàn)的幾起案子超全,更是在濱河造成了極大的恐慌,老刑警劉巖邓馒,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘶朱,死亡現(xiàn)場離奇詭異,居然都是意外死亡光酣,警方通過查閱死者的電腦和手機(jī)疏遏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來救军,“玉大人财异,你說我怎么就攤上這事〕猓” “怎么了戳寸?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拷泽。 經(jīng)常有香客問我疫鹊,道長袖瞻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任拆吆,我火速辦了婚禮聋迎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘枣耀。我一直安慰自己霉晕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布捞奕。 她就那樣靜靜地躺著牺堰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪颅围。 梳的紋絲不亂的頭發(fā)上伟葫,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音谷浅,去河邊找鬼扒俯。 笑死奶卓,一個(gè)胖子當(dāng)著我的面吹牛一疯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播夺姑,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼墩邀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了盏浙?” 一聲冷哼從身側(cè)響起眉睹,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎废膘,沒想到半個(gè)月后竹海,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丐黄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年斋配,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灌闺。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡艰争,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出桂对,到底是詐尸還是另有隱情甩卓,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布蕉斜,位于F島的核電站逾柿,受9級(jí)特大地震影響缀棍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鹿寻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一睦柴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧毡熏,春花似錦坦敌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至财搁,卻和暖如春蘸炸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背尖奔。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工搭儒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人提茁。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓淹禾,卻偏偏與公主長得像,于是被迫代替她去往敵國和親茴扁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子铃岔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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