【設(shè)計(jì)模式(八)】結(jié)構(gòu)型模式之組合模式

個(gè)人學(xué)習(xí)筆記分享,當(dāng)前能力有限朽基,請(qǐng)勿貶低布隔,菜鳥互學(xué),大佬繞道

如有勘誤稼虎,歡迎指出和討論衅檀,本文后期也會(huì)進(jìn)行修正和補(bǔ)充


前言

image-20201021162209259

這個(gè)是我隨手截的文件目錄,這樣的結(jié)構(gòu)都很眼熟吧霎俩?

一個(gè)個(gè)文件哀军,組成一個(gè)文件夾沉眶,文件和文件夾又可以組成更大的文件夾,進(jìn)而形成一個(gè)樹形結(jié)構(gòu)

那么排苍,我們?cè)邳c(diǎn)開的時(shí)候沦寂,需要先確認(rèn)目標(biāo)是文件夾或者文件,文件就打開淘衙,文件夾則是展開下一級(jí)

也就是說我們對(duì)于"部分"與“整體”采取了不同的方案传藏,但是這樣帶來了一些不必要的麻煩,我們只想打開這個(gè)目標(biāo)彤守,具體怎么打開那是你們自己的事情

進(jìn)而言之毯侦,客戶只關(guān)心對(duì)目標(biāo)進(jìn)行操作,并不關(guān)心因?yàn)槟繕?biāo)不同而導(dǎo)致的差異具垫。用戶對(duì)于目標(biāo)的“部分”與“整體”是一致對(duì)待的侈离。

比如,刪除目標(biāo)筝蚕,客戶只需要點(diǎn)擊刪除即可卦碾,并不關(guān)心具體邏輯,實(shí)際上如果是文件就直接刪除起宽,如果是文件夾需要先刪除下一層級(jí)的所有目標(biāo)洲胖。

復(fù)制、粘貼坯沪、移動(dòng)這類操作同理

換個(gè)例子绿映,我們告訴一個(gè)部門明天放假,只需要告知負(fù)責(zé)人即可

至于這個(gè)部門腐晾,包括一整個(gè)公司分部叉弦,還是研發(fā)部,還是研發(fā)小組藻糖,還是說就負(fù)責(zé)人一個(gè)人淹冰,我么并不需要關(guān)心,這是負(fù)責(zé)人該關(guān)心的事情

事實(shí)上如果這個(gè)部門不止負(fù)責(zé)人一個(gè)人的話颖御,他大概率也是轉(zhuǎn)告下一層部門的負(fù)責(zé)人而已(套娃榄棵??)

因此潘拱,你看,我們告知一個(gè)人拧略,或者告知任何一個(gè)部門芦岂,都是一樣的,并不需要先確定是哪層的負(fù)責(zé)人


這就是組合模式垫蛆,又稱部分整體模式禽最,用于將一組相似的對(duì)象作為單一的對(duì)象整體腺怯,進(jìn)而將部分與整體構(gòu)造成樹形結(jié)構(gòu)。

這種模式創(chuàng)建了一個(gè)包含自己對(duì)象組的類川无,并提供操作相同對(duì)象組的方式呛占。

組合模式定義了如何將容器對(duì)象和葉子對(duì)象進(jìn)行==遞歸==組合,使得客戶在使用的過程中無須進(jìn)行區(qū)分懦趋,可以對(duì)他們進(jìn)行一致的處理


1.介紹

使用目的:將對(duì)象組合成樹形結(jié)構(gòu)以表示"部分-整體"的層次結(jié)構(gòu)晾虑,進(jìn)而使客戶可能夠?qū)误w對(duì)象或者組合對(duì)象的使用具有一致性

使用時(shí)機(jī):希望用戶能夠忽略組合對(duì)象與單個(gè)對(duì)象的區(qū)別,進(jìn)行統(tǒng)一的處理

解決問題:將“部分”與“整體”區(qū)別對(duì)待會(huì)帶來不必要的麻煩

實(shí)現(xiàn)方法:將容器對(duì)象和葉子對(duì)象進(jìn)行==遞歸==組合仅叫,使得客戶在使用的過程中無須進(jìn)行區(qū)分帜篇,可以對(duì)他們進(jìn)行一致的處理

應(yīng)用實(shí)例:

  • 對(duì)于文件/文件夾的刪除、復(fù)制诫咱、剪切笙隙、粘貼、移動(dòng)等操作
  • 向一個(gè)個(gè)人/部門傳遞消息或者指令坎缭,只需要告知負(fù)責(zé)人即可
  • 需求展示一個(gè)無限層級(jí)的目錄竟痰,如圖書管理系統(tǒng)(曾經(jīng)遇到的需求,層級(jí)未知掏呼,最后干脆做成了無限層級(jí))

優(yōu)點(diǎn)

  1. 客戶對(duì)于“部分”和“整體”的操作具有一致性坏快,無疑提高了用戶體驗(yàn)
  2. 高層代碼調(diào)用簡單方便,也簡化了客戶端代碼
  3. 節(jié)點(diǎn)自由度增加哄尔,可以選擇僅變更自己假消,或變更所有子節(jié)點(diǎn)
  4. 組合內(nèi)部增加新的節(jié)點(diǎn)很方便,不需要修改結(jié)構(gòu)的源代碼岭接,滿足“開閉原則”

缺點(diǎn)

  1. 所有節(jié)點(diǎn)都是實(shí)現(xiàn)類富拗,而不是接口,違背了依賴倒置原則
  2. 設(shè)計(jì)較為復(fù)雜鸣戴,需要理清不同層級(jí)之間的關(guān)系
  3. 難以使用集成的方法進(jìn)行擴(kuò)展


2.結(jié)構(gòu)

主要包含3個(gè)角色

  • 抽象構(gòu)件(Component)角色:聲明樹枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)的公共接口啃沪,并實(shí)現(xiàn)默認(rèn)行為。

    根據(jù)是否聲明訪問和管理子類的接口窄锅,分為透明模式和安全模式

  • 樹葉構(gòu)件(Leaf)角色:組合中的葉節(jié)點(diǎn)對(duì)象创千,它沒有子節(jié)點(diǎn),用于實(shí)現(xiàn)抽象構(gòu)件角色中聲明的公共接口入偷。

  • 樹枝構(gòu)件(Composite)角色:組合中的分支節(jié)點(diǎn)對(duì)象追驴,它有子節(jié)點(diǎn)。它實(shí)現(xiàn)了抽象構(gòu)件角色中聲明的接口疏之,同時(shí)還需要存儲(chǔ)和管理子節(jié)點(diǎn)殿雪。

其實(shí)也可以將三者融為一體,一個(gè)類就搞定了锋爪,但是不利于擴(kuò)展丙曙,功能較少的時(shí)候可以這樣做

圖就不花了爸业,這套娃的結(jié)構(gòu)根本無從下手


3.實(shí)現(xiàn)

這里給出三種示例,分別是簡單組合模式亏镰、透明模式和安全模式

3.1.簡單組合模式

不利于擴(kuò)展扯旷,但代碼簡單,適用于功能較少的機(jī)構(gòu)

之所以列出來說索抓,是因?yàn)檫@種其實(shí)才是最常見的钧忽,尤其是算法中經(jīng)常用到,包括鏈表也是使用的這種結(jié)構(gòu)

3.1.1.示例1

模擬業(yè)務(wù)如下:

  • 鏈表由節(jié)點(diǎn)連接構(gòu)成
  • 每個(gè)節(jié)點(diǎn)存儲(chǔ)一個(gè)值和下一個(gè)節(jié)點(diǎn)纸兔,下一個(gè)節(jié)點(diǎn)可能為空

代碼很簡單直接貼了惰瓜,經(jīng)常刷算法題的都能默寫下來了

package com.company.test.composite;

import lombok.Data;

@Data
class Node {
    public int val;
    public Node next;

    public Node(int val, Node next) {
        this.val = val;
        this.next = next;
    }

    public void show() {
        if (next == null) {
            //為最后一個(gè)節(jié)點(diǎn),打印本身的值并轉(zhuǎn)行
            System.out.println(val);
        } else {
            //不為最后一個(gè)節(jié)點(diǎn)汉矿,打印本身的值崎坊,并打印下一個(gè)節(jié)點(diǎn)
            System.out.print(val + " -> ");
            next.show();
        }
    }
}

public class SimpleCompositeTest {
    public static void main(String[] args) {
        Node node1 = new Node(1, null);
        Node node2 = new Node(2, node1);
        Node node3 = new Node(3, node2);
        Node node4 = new Node(4, node3);

        node1.show();
        node2.show();
        node3.show();
        node4.show();
    }
}

運(yùn)行結(jié)果

image-20201021183018514

我們?cè)谶@里舍棄了抽象構(gòu)建,而且樹葉構(gòu)件和樹枝構(gòu)件使用同一個(gè)類實(shí)現(xiàn)即可洲拇,通過next是否為空判斷是否是葉子節(jié)點(diǎn)


3.1.2.示例2

模擬業(yè)務(wù)如下

  • 職員信息包括4個(gè)數(shù)據(jù):姓名奈揍、職位、薪水赋续、下級(jí)人員
  • 職員信息提供接口進(jìn)行打印男翰,可以打印當(dāng)前職員信息,也可以同時(shí)打印所有下級(jí)人員信息

結(jié)構(gòu)與示例1類似纽乱,故不多做解釋

package com.company.test.composite;

import lombok.Data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Data
class Employee {
    private String name;
    private String dept;
    private int salary;

    private List<Employee> subordinate;

    public Employee(String name, String dept, int salary, List<Employee> subordinate) {
        this.name = name;
        this.dept = dept;
        this.salary = salary;
        this.subordinate = subordinate;
    }

    public String toString() {
        String subordinateNames = subordinate.stream().map(Employee::getName).collect(Collectors.joining(", "));
        return ("Employee :[ "
                + "Name : " + name
                + ", dept : " + dept
                + ", salary : " + salary
                + ", subordinate : " + subordinateNames
                + " ]");
    }

    public void showCurrent() {
        System.out.println(this.toString());
    }

    public void showAll() {
        showCurrent();
        subordinate.forEach((m) -> {
            m.showAll();
        });
    }
}

public class SimpleCompositeTest1 {
    public static void main(String[] args) {
        Employee clerk1 = new Employee("clerk1", "clerk", 10000, new ArrayList<>());
        Employee clerk2 = new Employee("clerk2", "clerk", 10000, new ArrayList<>());

        Employee manager1 = new Employee("manager1", "manager", 50000, Arrays.asList(new Employee[]{clerk1, clerk2}));
        Employee manager2 = new Employee("manager2", "manager", 50000, new ArrayList<>());

        Employee ceo = new Employee("Jobs", "ceo", 150000, Arrays.asList(new Employee[]{manager1, manager2}));

        ceo.showAll();
    }
}

運(yùn)行結(jié)果

image-20201022144641361


3.2.透明組合模式

透明模式是把組合使用的方法放到抽象類中蛾绎,不管葉子對(duì)象還是樹枝對(duì)象都有相同的結(jié)構(gòu)

這樣做的好處就是葉子節(jié)點(diǎn)和樹枝節(jié)點(diǎn)對(duì)于外界沒有區(qū)別,它們具備完全一致的行為接口鸦列。

但因?yàn)長eaf類本身不具備add()租冠、remove()方法的功能,所以實(shí)現(xiàn)它是沒有意義的

  1. 定義抽象構(gòu)件角色Component

    abstract class Component {
        protected String name;
    
        public Component(String name) {
            this.name = name;
        }
    
        public abstract void add(Component component);
    
        public abstract void remove(Component component);
    
        public abstract List<Component> getChildren();
    
        public abstract void show(int depth);
    }
    
  2. 定義樹葉構(gòu)件Leaf

    class Leaf extends Component {
    
        public Leaf(String name) {
            super(name);
        }
    
        @Override
        public void add(Component component) {
            //空實(shí)現(xiàn)薯嗤,拋出“不支持請(qǐng)求”異常
            throw new UnsupportedOperationException();
        }
    
        @Override
        public void remove(Component component) {
            //空實(shí)現(xiàn)顽爹,拋出“不支持請(qǐng)求”異常
            throw new UnsupportedOperationException();
        }
    
        @Override
        public List<Component> getChildren() {
            return null;
        }
    
        @Override
        public void show(int depth) {
            while (depth-- > 0) {
                System.out.print("-");
            }
            System.out.println(name);
        }
    }
    
  3. 定義樹枝構(gòu)件Composite

    class Composite extends Component {
    
        List<Component> children = new ArrayList<>();
    
        public Composite(String name) {
            super(name);
        }
    
        @Override
        public void add(Component component) {
            children.add(component);
        }
    
        @Override
        public void remove(Component component) {
            children.remove(component);
        }
    
        @Override
        public List<Component> getChildren() {
            return children;
        }
    
        @Override
        public void show(int depth) {
            int nowDepth = depth;
            while (depth-- > 0) {
                System.out.print("-");
            }
            System.out.println(name);
    
            children.forEach(m -> {
                m.show(nowDepth + 1);
            });
        }
    }
    

完整代碼

package com.company.test.composite;

import java.util.ArrayList;
import java.util.List;

abstract class Component {
    protected String name;

    public Component(String name) {
        this.name = name;
    }

    public abstract void add(Component component);

    public abstract void remove(Component component);

    public abstract List<Component> getChildren();

    public abstract void show(int depth);
}

class Leaf extends Component {

    public Leaf(String name) {
        super(name);
    }

    @Override
    public void add(Component component) {
        //空實(shí)現(xiàn),拋出“不支持請(qǐng)求”異常
        throw new UnsupportedOperationException();
    }

    @Override
    public void remove(Component component) {
        //空實(shí)現(xiàn)骆姐,拋出“不支持請(qǐng)求”異常
        throw new UnsupportedOperationException();
    }

    @Override
    public List<Component> getChildren() {
        return null;
    }

    @Override
    public void show(int depth) {
        while (depth-- > 0) {
            System.out.print("-");
        }
        System.out.println(name);
    }
}

class Composite extends Component {

    List<Component> children = new ArrayList<>();

    public Composite(String name) {
        super(name);
    }

    @Override
    public void add(Component component) {
        children.add(component);
    }

    @Override
    public void remove(Component component) {
        children.remove(component);
    }

    @Override
    public List<Component> getChildren() {
        return children;
    }

    @Override
    public void show(int depth) {
        int nowDepth = depth;
        while (depth-- > 0) {
            System.out.print("-");
        }
        System.out.println(name);

        children.forEach(m -> {
            m.show(nowDepth + 1);
        });
    }
}

public class ClearCompositeTest {
    public static void main(String[] args) {
        Component leaf1 = new Leaf("leaf1");
        Component leaf2 = new Leaf("leaf2");

        Component composite1=new Composite("composite1");
        composite1.add(leaf1);
        composite1.add(leaf2);

        Component leaf3 = new Leaf("leaf3");

        Component composite3=new Composite("composite3");
        composite3.add(composite1);
        composite3.add(leaf3);

        composite3.show(1);
    }
}

運(yùn)行結(jié)果

image-20201022154459402

如圖镜粤,組裝了一個(gè)目錄,并將其打印出來

可以看到玻褪,樹葉和樹枝擁有同樣的功能肉渴,但樹葉的部分功能并沒有正常執(zhí)行(拋出異常或空實(shí)現(xiàn))带射,這樣會(huì)帶來安全性問題

安全組合模式就是為了解決這種情況


3.3.安全組合模式

在該方式中黄虱,將管理子構(gòu)件的方法移到樹枝構(gòu)件中,抽象構(gòu)件和樹葉構(gòu)件沒有對(duì)子對(duì)象的管理方法

這樣就避免了上一種方式的安全性問題庸诱,但由于葉子和分支有不同的接口捻浦,客戶端在調(diào)用時(shí)要知道樹葉對(duì)象和樹枝對(duì)象的存在,所以失去了透明性

結(jié)構(gòu)一樣的桥爽,就直接貼代碼了朱灿,自己對(duì)比一下

package com.company.test.composite;

import java.util.ArrayList;
import java.util.List;

abstract class Component {
    protected String name;

    public Component(String name) {
        this.name = name;
    }

    public abstract void add(Component component);

    public abstract void remove(Component component);

    public abstract List<Component> getChildren();

    public abstract void show(int depth);
}

class Leaf extends Component {

    public Leaf(String name) {
        super(name);
    }

    @Override
    public void add(Component component) {
        //空實(shí)現(xiàn),拋出“不支持請(qǐng)求”異常
        throw new UnsupportedOperationException();
    }

    @Override
    public void remove(Component component) {
        //空實(shí)現(xiàn)钠四,拋出“不支持請(qǐng)求”異常
        throw new UnsupportedOperationException();
    }

    @Override
    public List<Component> getChildren() {
        return null;
    }

    @Override
    public void show(int depth) {
        while (depth-- > 0) {
            System.out.print("-");
        }
        System.out.println(name);
    }
}

class Composite extends Component {

    List<Component> children = new ArrayList<>();

    public Composite(String name) {
        super(name);
    }

    @Override
    public void add(Component component) {
        children.add(component);
    }

    @Override
    public void remove(Component component) {
        children.remove(component);
    }

    @Override
    public List<Component> getChildren() {
        return children;
    }

    @Override
    public void show(int depth) {
        int nowDepth = depth;
        while (depth-- > 0) {
            System.out.print("-");
        }
        System.out.println(name);

        children.forEach(m -> {
            m.show(nowDepth + 1);
        });
    }
}

public class ClearCompositeTest {
    public static void main(String[] args) {
        Component leaf1 = new Leaf("leaf1");
        Component leaf2 = new Leaf("leaf2");

        Component composite1=new Composite("composite1");
        composite1.add(leaf1);
        composite1.add(leaf2);

        Component leaf3 = new Leaf("leaf3");

        Component composite3=new Composite("composite3");
        composite3.add(composite1);
        composite3.add(leaf3);

        composite3.show(1);
    }
}

運(yùn)行結(jié)果

image-20201022155542888

4.透明組合模式與安全組合模式的區(qū)別

透明模式:

  • 只需要在定義的時(shí)候確定是樹葉或者樹枝盗扒,使用的時(shí)候樹葉和樹枝可以當(dāng)做同一個(gè)對(duì)象使用
  • 樹葉實(shí)現(xiàn)了所有功能,但部分功能實(shí)際上并不擁有缀去,需要拋出異陈略睿或者空實(shí)現(xiàn),會(huì)帶來安全性問題

安全模式

  • 使用時(shí)需要知道是樹葉或者樹枝缕碎,部分功能可能存在差異
  • 所有功能都正常實(shí)現(xiàn)了褥影,所以不會(huì)帶來透明模式的安全性問題
  • 因?yàn)樾枰朗枪?jié)點(diǎn)類型,使用不便咏雌,一定程度上違背了初衷

簡單點(diǎn)說凡怎,一種是葉節(jié)點(diǎn)與樹枝節(jié)點(diǎn)具備一致的行為接口但有空實(shí)現(xiàn)的透明模式,另一種是樹枝節(jié)點(diǎn)單獨(dú)擁有用來組合的方法但調(diào)用不便的安全模式

使用哪種赊抖,自行取舍咯统倒,如果是圖方便,簡單組合模式就可以滿足很多需求氛雪,如果需要保證安全房匆,就需要使用安全組合模式,但是最符合初衷的應(yīng)該是透明組合模式


5.擴(kuò)展使用

5.1.將節(jié)點(diǎn)進(jìn)一步抽象化

模擬文件夾目錄报亩,包括文件夾和文件

package com.company.test.composite;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Data
abstract class Files {
    protected String name;

    public Files(String name) {
        this.name = name;
    }

    public abstract void check();

    public abstract void copyFiles();
}

abstract class File extends Files {
    public File(String name) {
        super(name);
    }

    @Override
    public void copyFiles() {
        System.out.println("copy file: " + name);
    }
}

class Text extends File {

    public Text(String text) {
        super(text);
    }

    @Override
    public void check() {
        System.out.println("show text: " + name);
    }
}

class Mp3 extends File {
    public Mp3(String name) {
        super(name);
    }

    @Override
    public void check() {
        System.out.println("play mp3: " + name);
    }

}

class Folder extends Files {
    public Folder(String name) {
        super(name);
    }

    List<Files> subordinateFiles = new ArrayList<>();

    public void addFiles(Files files) {
        subordinateFiles.add(files);
    }

    public void removeFiles(Files files) {
        subordinateFiles.remove(files);
    }

    @Override
    public void check() {
        String subordinateFileNames = subordinateFiles.stream().map(m -> m.getName()).collect(Collectors.joining(", "));
        System.out.println("open folder: " + name + ", subordinateFiles: " + subordinateFileNames);
    }

    @Override
    public void copyFiles() {
        subordinateFiles.forEach(m -> {
            m.copyFiles();
        });
        System.out.println("copy folder: " + name);
    }
}

public class FileCompositeTest {
    public static void main(String[] args) {
        Text text = new Text("HelloWorld.text");
        Mp3 mp3 = new Mp3("我在昨天的夢(mèng)里又看見了你.mp3");
        Text lyric = new Text("我在昨天的夢(mèng)里又看見了你.text");

        Folder folder = new Folder("我在昨天的夢(mèng)里又看見了你");
        folder.addFiles(mp3);
        folder.addFiles(lyric);

        Folder folder1 = new Folder("empty");

        Folder root = new Folder("root");
        root.addFiles(folder);
        root.addFiles(folder1);
        root.addFiles(text);

        System.out.println("<---------------------------操作文件夾:root------------------------------->");
        root.check();
        root.copyFiles();

        System.out.println("<---------------------------操作文件夾:我在昨天的夢(mèng)里又看見了你------------------------------->");
        folder.check();
        folder.copyFiles();

        System.out.println("<---------------------------操作文件:我在昨天的夢(mèng)里又看見了你.mp3------------------------------->");
        mp3.check();
        mp3.copyFiles();
    }
}

運(yùn)行結(jié)果

image-20201022171736265

文件目錄(模擬)

image-20201022171829390

看浴鸿,無論是mp3文件,或者text文件捆昏,或者folder文件夾赚楚,我們都可以執(zhí)行同樣的check()copyFiles()操作


其余擴(kuò)展使用后續(xù)再追加,暫時(shí)只想到這里就寫到這里


后記

將相似的目標(biāo)提取其共同點(diǎn)骗卜,從而可以進(jìn)行部分一致性操作宠页,而目標(biāo)本身只需要關(guān)注自己的特點(diǎn),將共同點(diǎn)交由接口或者父類處理

其實(shí)這也是多態(tài)和繼承的目的寇仓,所以從學(xué)習(xí)Java開始举户,我們其實(shí)就在按照這種思想設(shè)計(jì)程序,組合模式不過是其中一種方案而已


作者:Echo_Ye

WX:Echo_YeZ

Email :echo_yezi@qq.com

個(gè)人站點(diǎn):在搭了在搭了遍烦。俭嘁。。(右鍵 - 新建文件夾)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末服猪,一起剝皮案震驚了整個(gè)濱河市供填,隨后出現(xiàn)的幾起案子拐云,更是在濱河造成了極大的恐慌,老刑警劉巖近她,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叉瘩,死亡現(xiàn)場離奇詭異,居然都是意外死亡粘捎,警方通過查閱死者的電腦和手機(jī)薇缅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來攒磨,“玉大人泳桦,你說我怎么就攤上這事∶溏郑” “怎么了灸撰?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長漆羔。 經(jīng)常有香客問我梧奢,道長,這世上最難降的妖魔是什么演痒? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任亲轨,我火速辦了婚禮,結(jié)果婚禮上鸟顺,老公的妹妹穿的比我還像新娘惦蚊。我一直安慰自己,他們只是感情好讯嫂,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布蹦锋。 她就那樣靜靜地躺著,像睡著了一般欧芽。 火紅的嫁衣襯著肌膚如雪莉掂。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天千扔,我揣著相機(jī)與錄音憎妙,去河邊找鬼。 笑死曲楚,一個(gè)胖子當(dāng)著我的面吹牛厘唾,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播龙誊,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼抚垃,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鹤树,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤铣焊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后魂迄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體粗截,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年捣炬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绽榛。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡湿酸,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灭美,到底是詐尸還是另有隱情推溃,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布届腐,位于F島的核電站铁坎,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏犁苏。R本人自食惡果不足惜硬萍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望围详。 院中可真熱鬧朴乖,春花似錦、人聲如沸助赞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雹食。三九已至畜普,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間群叶,已是汗流浹背吃挑。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盖呼,地道東北人儒鹿。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像几晤,于是被迫代替她去往敵國和親约炎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350