31. 觀察者模式(Observer模式)詳解

在現(xiàn)實(shí)世界中,許多對象并不是獨(dú)立存在的掰曾,其中一個(gè)對象的行為發(fā)生改變可能會(huì)導(dǎo)致一個(gè)或者多個(gè)其他對象的行為也發(fā)生改變旭蠕。例如,某種商品的物價(jià)上漲時(shí)會(huì)導(dǎo)致部分商家高興,而消費(fèi)者傷心掏熬;還有佑稠,當(dāng)我們開車到交叉路口時(shí),遇到紅燈會(huì)停旗芬,遇到綠燈會(huì)行舌胶。這樣的例子還有很多,例如疮丛,股票價(jià)格與股民幔嫂、微信公眾號與微信用戶、氣象局的天氣預(yù)報(bào)與聽眾誊薄、小偷與警察等履恩。

在軟件世界也是這樣,例如呢蔫,Excel 中的數(shù)據(jù)與折線圖切心、餅狀圖、柱狀圖之間的關(guān)系片吊;MVC 模式中的模型與視圖的關(guān)系绽昏;事件模型中的事件源與事件處理者。所有這些俏脊,如果用觀察者模式來實(shí)現(xiàn)就非常方便而涉。

模式的定義與特點(diǎn)

觀察者(Observer)模式的定義:指多個(gè)對象間存在一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí)联予,所有依賴于它的對象都得到通知并被自動(dòng)更新啼县。這種模式有時(shí)又稱作發(fā)布-訂閱模式、模型-視圖模式沸久,它是對象行為型模式季眷。

觀察者模式是一種對象行為型模式,其主要優(yōu)點(diǎn)如下卷胯。

  1. 降低了目標(biāo)與觀察者之間的耦合關(guān)系子刮,兩者之間是抽象耦合關(guān)系。
  2. 目標(biāo)與觀察者之間建立了一套觸發(fā)機(jī)制窑睁。

它的主要缺點(diǎn)如下挺峡。

  1. 目標(biāo)與觀察者之間的依賴關(guān)系并沒有完全解除,而且有可能出現(xiàn)循環(huán)引用担钮。
  2. 當(dāng)觀察者對象很多時(shí)橱赠,通知的發(fā)布會(huì)花費(fèi)很多時(shí)間,影響程序的效率箫津。

模式的結(jié)構(gòu)與實(shí)現(xiàn)

實(shí)現(xiàn)觀察者模式時(shí)要注意具體目標(biāo)對象和具體觀察者對象之間不能直接調(diào)用狭姨,否則將使兩者之間緊密耦合起來宰啦,這違反了面向?qū)ο蟮脑O(shè)計(jì)原則。

1. 模式的結(jié)構(gòu)

觀察者模式的主要角色如下饼拍。

  1. 抽象主題(Subject)角色:也叫抽象目標(biāo)類赡模,它提供了一個(gè)用于保存觀察者對象的聚集類和增加、刪除觀察者對象的方法师抄,以及通知所有觀察者的抽象方法漓柑。
  2. 具體主題(Concrete Subject)角色:也叫具體目標(biāo)類,它實(shí)現(xiàn)抽象目標(biāo)中的通知方法叨吮,當(dāng)具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí)欺缘,通知所有注冊過的觀察者對象。
  3. 抽象觀察者(Observer)角色:它是一個(gè)抽象類或接口挤安,它包含了一個(gè)更新自己的抽象方法谚殊,當(dāng)接到具體主題的更改通知時(shí)被調(diào)用。
  4. 具體觀察者(Concrete Observer)角色:實(shí)現(xiàn)抽象觀察者中定義的抽象方法蛤铜,以便在得到目標(biāo)的更改通知時(shí)更新自身的狀態(tài)嫩絮。

觀察者模式的結(jié)構(gòu)圖如圖 1 所示。

觀察者模式的結(jié)構(gòu)圖

圖1 觀察者模式的結(jié)構(gòu)圖

2. 模式的實(shí)現(xiàn)

觀察者模式的實(shí)現(xiàn)代碼如下:

package observer;
import java.util.*;
public class ObserverPattern
{
    public static void main(String[] args)
    {
        Subject subject=new ConcreteSubject();
        Observer obs1=new ConcreteObserver1();
        Observer obs2=new ConcreteObserver2();
        subject.add(obs1);
        subject.add(obs2);
        subject.notifyObserver();
    }
}
//抽象目標(biāo)
abstract class Subject
{
    protected List<Observer> observers=new ArrayList<Observer>();   
    //增加觀察者方法
    public void add(Observer observer)
    {
        observers.add(observer);
    }    
    //刪除觀察者方法
    public void remove(Observer observer)
    {
        observers.remove(observer);
    }   
    public abstract void notifyObserver(); //通知觀察者方法
}
//具體目標(biāo)
class ConcreteSubject extends Subject
{
    public void notifyObserver()
    {
        System.out.println("具體目標(biāo)發(fā)生改變...");
        System.out.println("--------------");       

        for(Object obs:observers)
        {
            ((Observer)obs).response();
        }

    }          
}
//抽象觀察者
interface Observer
{
    void response(); //反應(yīng)
}
//具體觀察者1
class ConcreteObserver1 implements Observer
{
    public void response()
    {
        System.out.println("具體觀察者1作出反應(yīng)围肥!");
    }
}
//具體觀察者1
class ConcreteObserver2 implements Observer
{
    public void response()
    {
        System.out.println("具體觀察者2作出反應(yīng)剿干!");
    }
}

程序運(yùn)行結(jié)果如下:

具體目標(biāo)發(fā)生改變...
--------------
具體觀察者1作出反應(yīng)!
具體觀察者2作出反應(yīng)穆刻!

模式的應(yīng)用實(shí)例

【例1】利用觀察者模式設(shè)計(jì)一個(gè)程序置尔,分析“人民幣匯率”的升值或貶值對進(jìn)口公司的進(jìn)口產(chǎn)品成本或出口公司的出口產(chǎn)品收入以及公司的利潤率的影響。

分析:當(dāng)“人民幣匯率”升值時(shí)氢伟,進(jìn)口公司的進(jìn)口產(chǎn)品成本降低且利潤率提升榜轿,出口公司的出口產(chǎn)品收入降低且利潤率降低;當(dāng)“人民幣匯率”貶值時(shí)朵锣,進(jìn)口公司的進(jìn)口產(chǎn)品成本提升且利潤率降低谬盐,出口公司的出口產(chǎn)品收入提升且利潤率提升。

這里的匯率(Rate)類是抽象目標(biāo)類诚些,它包含了保存觀察者(Company)的 List 和增加/刪除觀察者的方法飞傀,以及有關(guān)匯率改變的抽象方法 change(int number);而人民幣匯率(RMBrate)類是具體目標(biāo)诬烹, 它實(shí)現(xiàn)了父類的 change(int number) 方法砸烦,即當(dāng)人民幣匯率發(fā)生改變時(shí)通過相關(guān)公司;公司(Company)類是抽象觀察者绞吁,它定義了一個(gè)有關(guān)匯率反應(yīng)的抽象方法 response(int number)幢痘;進(jìn)口公司(ImportCompany)類和出口公司(ExportCompany)類是具體觀察者類,它們實(shí)現(xiàn)了父類的 response(int number) 方法掀泳,即當(dāng)它們接收到匯率發(fā)生改變的通知時(shí)作為相應(yīng)的反應(yīng)雪隧。圖 2 所示是其結(jié)構(gòu)圖。

人民幣匯率分析程序的結(jié)構(gòu)圖

圖2 人民幣匯率分析程序的結(jié)構(gòu)圖

程序代碼如下:

package observer;
import java.util.*;
public class RMBrateTest
{
    public static void main(String[] args)
    {
        Rate rate=new RMBrate();         
        Company watcher1=new ImportCompany(); 
        Company watcher2=new ExportCompany();           
        rate.add(watcher1); 
        rate.add(watcher2);           
        rate.change(10);
        rate.change(-9);
    }
}
//抽象目標(biāo):匯率
abstract class Rate
{
    protected List<Company> companys=new ArrayList<Company>();   
    //增加觀察者方法
    public void add(Company company)
    {
        companys.add(company);
    }    
    //刪除觀察者方法
    public void remove(Company company)
    {
        companys.remove(company);
    }   
    public abstract void change(int number);
}
//具體目標(biāo):人民幣匯率
class RMBrate extends Rate 
{
    public void change(int number)
    {       
        for(Company obs:companys)
        {
            ((Company)obs).response(number);
        }       
    }

}
//抽象觀察者:公司
interface Company
{
    void response(int number);
}
//具體觀察者1:進(jìn)口公司 
class ImportCompany implements Company 
{
    public void response(int number) 
    {
        if(number>0)
        {
            System.out.println("人民幣匯率升值"+number+"個(gè)基點(diǎn)员舵,降低了進(jìn)口產(chǎn)品成本,提升了進(jìn)口公司利潤率。"); 
        }
        else if(number<0)
        {
              System.out.println("人民幣匯率貶值"+(-number)+"個(gè)基點(diǎn)护昧,提升了進(jìn)口產(chǎn)品成本倍啥,降低了進(jìn)口公司利潤率。"); 
        }
    } 
} 
//具體觀察者2:出口公司
class ExportCompany implements Company 
{
    public void response(int number) 
    {
        if(number>0)
        {
            System.out.println("人民幣匯率升值"+number+"個(gè)基點(diǎn)韭邓,降低了出口產(chǎn)品收入措近,降低了出口公司的銷售利潤率。"); 
        }
        else if(number<0)
        {
              System.out.println("人民幣匯率貶值"+(-number)+"個(gè)基點(diǎn)女淑,提升了出口產(chǎn)品收入瞭郑,提升了出口公司的銷售利潤率。"); 
        }
    } 
}

程序運(yùn)行結(jié)果如下:

人民幣匯率升值10個(gè)基點(diǎn)鸭你,降低了進(jìn)口產(chǎn)品成本屈张,提升了進(jìn)口公司利潤率。
人民幣匯率升值10個(gè)基點(diǎn)袱巨,降低了出口產(chǎn)品收入阁谆,降低了出口公司的銷售利潤率。
人民幣匯率貶值9個(gè)基點(diǎn)愉老,提升了進(jìn)口產(chǎn)品成本场绿,降低了進(jìn)口公司利潤率。
人民幣匯率貶值9個(gè)基點(diǎn)嫉入,提升了出口產(chǎn)品收入焰盗,提升了出口公司的銷售利潤率。

觀察者模式在軟件幵發(fā)中用得最多的是窗體程序設(shè)計(jì)中的事件處理咒林,窗體中的所有組件都是“事件源”姨谷,也就是目標(biāo)對象,而事件處理程序類的對象是具體觀察者對象映九。下面以一個(gè)學(xué)校鈴聲的事件處理程序?yàn)槔蜗妫榻B Windows 中的“事件處理模型”的工作原理。

【例2】利用觀察者模式設(shè)計(jì)一個(gè)學(xué)校鈴聲的事件處理程序件甥。

分析:在本實(shí)例中捌议,學(xué)校的“鈴”是事件源和目標(biāo),“老師”和“學(xué)生”是事件監(jiān)聽器和具體觀察者引有,“鈴聲”是事件類瓣颅。學(xué)生和老師來到學(xué)校的教學(xué)區(qū),都會(huì)注意學(xué)校的鈴譬正,這叫事件綁定宫补;當(dāng)上課時(shí)間或下課時(shí)間到檬姥,會(huì)觸發(fā)鈴發(fā)聲,這時(shí)會(huì)生成“鈴聲”事件粉怕;學(xué)生和老師聽到鈴聲會(huì)開始上課或下課健民,這叫事件處理。這個(gè)實(shí)例非常適合用觀察者模式實(shí)現(xiàn)贫贝,圖 3 給出了學(xué)校鈴聲的事件模型秉犹。

學(xué)校鈴聲的事件模型圖

圖3 學(xué)校鈴聲的事件模型圖

現(xiàn)在用“觀察者模式”來實(shí)現(xiàn)該事件處理模型。首先稚晚,定義一個(gè)鈴聲事件(RingEvent)類崇堵,它記錄了鈴聲的類型(上課鈴聲/下課鈴聲);再定義一個(gè)學(xué)校的鈴(BellEventSource)類客燕,它是事件源鸳劳,是觀察者目標(biāo)類,該類里面包含了監(jiān)聽器容器 listener也搓,可以綁定監(jiān)聽者(學(xué)生或老師)棍辕,并且有產(chǎn)生鈴聲事件和通知所有監(jiān)聽者的方法;然后还绘,定義一聲事件監(jiān)聽者(BellEventListener)類楚昭,它是抽象觀察者,它包含了鈴聲事件處理方法 heardBell(RingEvent e)拍顷;最后抚太,定義老師類(TeachEventListener)和學(xué)生類(StuEventListener),它們是事件監(jiān)聽器昔案,是具體觀察者尿贫,聽到鈴聲會(huì)去上課或下課。圖 4 給出了學(xué)校鈴聲事件處理程序的結(jié)構(gòu)踏揣。

學(xué)校鈴聲事件處理程序的結(jié)構(gòu)圖

圖4 學(xué)校鈴聲事件處理程序的結(jié)構(gòu)圖

程序代碼如下:

package observer;
import java.util.*;
public class BellEventTest
{
    public static void main(String[] args)
    {
        BellEventSource bell=new BellEventSource();    //鈴(事件源)    
        bell.addPersonListener(new TeachEventListener()); //注冊監(jiān)聽器(老師)
        bell.addPersonListener(new StuEventListener());    //注冊監(jiān)聽器(學(xué)生)
        bell.ring(true);   //打上課鈴聲
        System.out.println("------------");   
        bell.ring(false);  //打下課鈴聲
    }
}
//鈴聲事件類:用于封裝事件源及一些與事件相關(guān)的參數(shù)
class RingEvent extends EventObject
{   
    private static final long serialVersionUID=1L;
    private boolean sound;    //true表示上課鈴聲,false表示下課鈴聲
    public RingEvent(Object source,boolean sound)
    {
        super(source);
        this.sound=sound;
    }   
    public void setSound(boolean sound)
    {
        this.sound=sound;
    }
    public boolean getSound()
    {
        return this.sound;
    }
}
//目標(biāo)類:事件源庆亡,鈴
class BellEventSource
{    
    private List<BellEventListener> listener; //監(jiān)聽器容器
    public BellEventSource()
    { 
        listener=new ArrayList<BellEventListener>();        
    }
    //給事件源綁定監(jiān)聽器 
    public void addPersonListener(BellEventListener ren)
    { 
        listener.add(ren); 
    }
    //事件觸發(fā)器:敲鐘,當(dāng)鈴聲sound的值發(fā)生變化時(shí)捞稿,觸發(fā)事件又谋。
    public void ring(boolean sound)
    {
        String type=sound?"上課鈴":"下課鈴";
        System.out.println(type+"響!");
        RingEvent event=new RingEvent(this, sound);     
        notifies(event);    //通知注冊在該事件源上的所有監(jiān)聽器                
    }   
    //當(dāng)事件發(fā)生時(shí),通知綁定在該事件源上的所有監(jiān)聽器做出反應(yīng)(調(diào)用事件處理方法)
    protected void notifies(RingEvent e)
    { 
        BellEventListener ren=null; 
        Iterator<BellEventListener> iterator=listener.iterator(); 
        while(iterator.hasNext())
        { 
            ren=iterator.next(); 
            ren.heardBell(e); 
        } 
    }
}
//抽象觀察者類:鈴聲事件監(jiān)聽器
interface  BellEventListener extends EventListener
{
    //事件處理方法娱局,聽到鈴聲
    public void heardBell(RingEvent e);
}
//具體觀察者類:老師事件監(jiān)聽器
class TeachEventListener implements BellEventListener
{
    public void heardBell(RingEvent e)
    {        
        if(e.getSound())
        {
            System.out.println("老師上課了...");           
        }
        else
        {
            System.out.println("老師下課了...");   
        }          
    }
}
//具體觀察者類:學(xué)生事件監(jiān)聽器
class StuEventListener implements BellEventListener
{
    public void heardBell(RingEvent e)
    {        
        if(e.getSound())
        {
            System.out.println("同學(xué)們彰亥,上課了...");           
        }
        else
        {
            System.out.println("同學(xué)們,下課了...");   
        }          
    }
}

程序運(yùn)行結(jié)果如下:

上課鈴響衰齐!
老師上課了...
同學(xué)們任斋,上課了...
------------
下課鈴響!
老師下課了...
同學(xué)們耻涛,下課了...

模式的應(yīng)用場景

通過前面的分析與應(yīng)用實(shí)例可知觀察者模式適合以下幾種情形废酷。

  1. 對象間存在一對多關(guān)系瘟檩,一個(gè)對象的狀態(tài)發(fā)生改變會(huì)影響其他對象。
  2. 當(dāng)一個(gè)抽象模型有兩個(gè)方面澈蟆,其中一個(gè)方面依賴于另一方面時(shí)墨辛,可將這二者封裝在獨(dú)立的對象中以使它們可以各自獨(dú)立地改變和復(fù)用。

模式的擴(kuò)展

Java 中丰介,通過 java.util.Observable 類和 java.util.Observer 接口定義了觀察者模式背蟆,只要實(shí)現(xiàn)它們的子類就可以編寫觀察者模式實(shí)例鉴分。

1. Observable類

Observable 類是抽象目標(biāo)類哮幢,它有一個(gè) Vector 向量,用于保存所有要通知的觀察者對象志珍,下面來介紹它最重要的 3 個(gè)方法橙垢。

  1. void addObserver(Observer o) 方法:用于將新的觀察者對象添加到向量中。
  2. void notifyObservers(Object arg) 方法:調(diào)用向量中的所有觀察者對象的 update伦糯。方法柜某,通知它們數(shù)據(jù)發(fā)生改變。通常越晚加入向量的觀察者越先得到通知敛纲。
  3. void setChange() 方法:用來設(shè)置一個(gè) boolean 類型的內(nèi)部標(biāo)志位喂击,注明目標(biāo)對象發(fā)生了變化。當(dāng)它為真時(shí)淤翔,notifyObservers() 才會(huì)通知觀察者翰绊。

2. Observer 接口

Observer 接口是抽象觀察者,它監(jiān)視目標(biāo)對象的變化旁壮,當(dāng)目標(biāo)對象發(fā)生變化時(shí)监嗜,觀察者得到通知,并調(diào)用 void update(Observable o,Object arg) 方法抡谐,進(jìn)行相應(yīng)的工作裁奇。

【例3】利用 Observable 類和 Observer 接口實(shí)現(xiàn)原油期貨的觀察者模式實(shí)例。

分析:當(dāng)原油價(jià)格上漲時(shí)麦撵,空方傷心刽肠,多方局興;當(dāng)油價(jià)下跌時(shí)免胃,空方局興五垮,多方傷心。本實(shí)例中的抽象目標(biāo)(Observable)類在 Java 中已經(jīng)定義杜秸,可以直接定義其子類放仗,即原油期貨(OilFutures)類,它是具體目標(biāo)類撬碟,該類中定義一個(gè) SetPriCe(float price) 方法诞挨,當(dāng)原油數(shù)據(jù)發(fā)生變化時(shí)調(diào)用其父類的 notifyObservers(Object arg) 方法來通知所有觀察者莉撇;另外,本實(shí)例中的抽象觀察者接口(Observer)在 Java 中已經(jīng)定義惶傻,只要定義其子類棍郎,即具體觀察者類(包括多方類 Bull 和空方類 Bear),并實(shí)現(xiàn) update(Observable o,Object arg) 方法即可银室。圖 5 所示是其結(jié)構(gòu)圖涂佃。

原油期貨的觀察者模式實(shí)例的結(jié)構(gòu)圖

圖5 原油期貨的觀察者模式實(shí)例的結(jié)構(gòu)圖

程序代碼如下:

package observer;
import java.util.Observer;
import java.util.Observable;
public class CrudeOilFutures
{
    public static void main(String[] args)
    {
        OilFutures oil=new OilFutures();
        Observer bull=new Bull(); //多方
        Observer bear=new Bear(); //空方
        oil.addObserver(bull);
        oil.addObserver(bear);
        oil.setPrice(10);
        oil.setPrice(-8);
    }
}
//具體目標(biāo)類:原油期貨
class OilFutures extends Observable
{
    private float price;   
    public float getPrice()
    {
        return this.price; 
    }
    public void setPrice(float price)
    {
        super.setChanged() ;  //設(shè)置內(nèi)部標(biāo)志位,注明數(shù)據(jù)發(fā)生變化 
        super.notifyObservers(price);    //通知觀察者價(jià)格改變了 
        this.price=price ; 
    }
}
//具體觀察者類:多方
class Bull implements Observer
{   
    public void update(Observable o,Object arg)
    {
        Float price=((Float)arg).floatValue();
        if(price>0)
        {
            System.out.println("油價(jià)上漲"+price+"元蜈敢,多方高興了辜荠!");
        }
        else
        {
            System.out.println("油價(jià)下跌"+(-price)+"元,多方傷心了抓狭!");
        }
    }
}
//具體觀察者類:空方
class Bear implements Observer
{   
    public void update(Observable o,Object arg)
    {
        Float price=((Float)arg).floatValue();
        if(price>0)
        {
            System.out.println("油價(jià)上漲"+price+"元伯病,空方傷心了!");
        }
        else
        {
            System.out.println("油價(jià)下跌"+(-price)+"元否过,空方高興了午笛!");
        }
    }
}

程序運(yùn)行結(jié)果如下:

油價(jià)上漲10.0元,空方傷心了苗桂!
油價(jià)上漲10.0元药磺,多方高興了!
油價(jià)下跌8.0元煤伟,空方高興了癌佩!
油價(jià)下跌8.0元,多方傷心了持偏!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末驼卖,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子鸿秆,更是在濱河造成了極大的恐慌酌畜,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卿叽,死亡現(xiàn)場離奇詭異桥胞,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)考婴,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門贩虾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沥阱,你說我怎么就攤上這事缎罢。” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵策精,是天一觀的道長舰始。 經(jīng)常有香客問我,道長咽袜,這世上最難降的妖魔是什么丸卷? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮询刹,結(jié)果婚禮上谜嫉,老公的妹妹穿的比我還像新娘。我一直安慰自己凹联,他們只是感情好沐兰,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著匕垫,像睡著了一般僧鲁。 火紅的嫁衣襯著肌膚如雪虐呻。 梳的紋絲不亂的頭發(fā)上象泵,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音斟叼,去河邊找鬼偶惠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛朗涩,可吹牛的內(nèi)容都是我干的忽孽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼谢床,長吁一口氣:“原來是場噩夢啊……” “哼兄一!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起识腿,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤出革,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后渡讼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骂束,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年成箫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了展箱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹬昌,死狀恐怖混驰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤栖榨,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布竞慢,位于F島的核電站,受9級特大地震影響治泥,放射性物質(zhì)發(fā)生泄漏筹煮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一居夹、第九天 我趴在偏房一處隱蔽的房頂上張望败潦。 院中可真熱鬧,春花似錦准脂、人聲如沸劫扒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沟饥。三九已至,卻和暖如春湾戳,著一層夾襖步出監(jiān)牢的瞬間贤旷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工砾脑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留幼驶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓韧衣,卻偏偏與公主長得像盅藻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子畅铭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345