訪問者模式

訪問者模式剖毯,是行為型設(shè)計模式之一。訪問者模式是一種將數(shù)據(jù)操作與數(shù)據(jù)結(jié)構(gòu)分離的設(shè)計模式堂淡,它可以算是 23 中設(shè)計模式中最復(fù)雜的一個馋缅,但它的使用頻率并不是很高,大多數(shù)情況下绢淀,你并不需要使用訪問者模式萤悴,但是當你一旦需要使用它時,那你就是需要使用它了皆的。

訪問者模式的基本想法是覆履,軟件系統(tǒng)中擁有一個由許多對象構(gòu)成的、比較穩(wěn)定的對象結(jié)構(gòu)费薄,這些對象的類都擁有一個 accept 方法用來接受訪問者對象的訪問硝全。訪問者是一個接口,它擁有一個 visit 方法楞抡,這個方法對訪問到的對象結(jié)構(gòu)中不同類型的元素做出不同的處理伟众。在對象結(jié)構(gòu)的一次訪問過程中,我們遍歷整個對象結(jié)構(gòu)拌倍,對每一個元素都實施 accept 方法赂鲤,在每一個元素的 accept 方法中會調(diào)用訪問者的 visit 方法噪径,從而使訪問者得以處理對象結(jié)構(gòu)的每一個元素,我們可以針對對象結(jié)構(gòu)設(shè)計不同的訪問者類來完成不同的操作数初,達到區(qū)別對待的效果找爱。

定義及使用場景

定義:封裝一些作用于某種數(shù)據(jù)結(jié)構(gòu)中的各元素的操作,它可以在不改變這個數(shù)據(jù)結(jié)構(gòu)的前提下定義作用于這些元素的新的操作泡孩。

可以對定義這么理解:有這么一個操作车摄,它是作用于一些元素之上的,而這些元素屬于某一個對象結(jié)構(gòu)仑鸥。同時這個操作是在不改變各元素類的前提下吮播,在這個前提下定義新操作是訪問者模式精髓中的精髓。

使用場景:
(1)對象結(jié)構(gòu)比較穩(wěn)定眼俊,但經(jīng)常需要在此對象結(jié)構(gòu)上定義新的操作意狠。

(2)需要對一個對象結(jié)構(gòu)中的對象進行很多不同的且不相關(guān)的操作,而需要避免這些操作“污染”這些對象的類疮胖,也不希望在增加新操作時修改這些類环戈。

UML圖

這里寫圖片描述

(1)Visitor:接口或者抽象類,它定義了對每一個元素(Element)訪問的行為澎灸,它的參數(shù)就是可以訪問的元素院塞,它的方法數(shù)理論上來講與元素個數(shù)是一樣的,因此性昭,訪問者模式要求元素的類族要穩(wěn)定拦止,如果經(jīng)常添加、移除元素類糜颠,必然會導(dǎo)致頻繁地修改Visitor接口汹族,如果這樣則不適合使用訪問者模式。

(2)ConcreteVisitor1括蝠、ConcreteVisitor2:具體的訪問類鞠抑,它需要給出對每一個元素類訪問時所產(chǎn)生的具體行為。

(3)Element:元素接口或者抽象類忌警,它定義了一個接受訪問者的方法(Accept),其意義是指每一個元素都要可以被訪問者訪問秒梳。

(4)ConcreteElementA法绵、ConcreteElementB:具體的元素類,它提供接受訪問方法的具體實現(xiàn)酪碘,而這個具體的實現(xiàn)朋譬,通常情況下是使用訪問者提供的訪問該元素類的方法。

(5)ObjectStructure:定義當中所說的對象結(jié)構(gòu)兴垦,對象結(jié)構(gòu)是一個抽象表述徙赢,它內(nèi)部管理了元素集合字柠,并且可以迭代這些元素供訪問者訪問。

訪問者模式的簡單例子

我們都知道財務(wù)都是有賬本的狡赐,這個賬本就可以作為一個對象結(jié)構(gòu)窑业,而它其中的元素有兩種,收入和支出枕屉,這滿足我們訪問者模式的要求常柄,即元素的個數(shù)是穩(wěn)定的,因為賬本中的元素只能是收入和支出搀擂。

而查看賬本的人可能有這樣幾種西潘,比如老板,會計事務(wù)所的注會哨颂,財務(wù)主管喷市,等等。而這些人在看賬本的時候顯然目的和行為是不同的威恼。

首先我們給出單子的接口东抹,它只有一個方法accept。

//單個單子的接口(相當于Element)
public interface Bill {
 
    void accept(AccountBookViewer viewer);
 
}

其中的方法參數(shù)AccountBookViewer是一個賬本訪問者接口沃测,接下來也就是實現(xiàn)類缭黔,收入單子和消費單子,或者說收入和支出類蒂破。

//消費的單子
public class ConsumeBill implements Bill{
 
    private double amount;
 
    private String item;
 
    public ConsumeBill(double amount, String item) {
        super();
        this.amount = amount;
        this.item = item;
    }
 
    public void accept(AccountBookViewer viewer) {
        viewer.view(this);
    }
 
    public double getAmount() {
        return amount;
    }
 
    public String getItem() {
        return item;
    }
 
}
//收入單子
public class IncomeBill implements Bill{
 
    private double amount;
 
    private String item;
 
    public IncomeBill(double amount, String item) {
        super();
        this.amount = amount;
        this.item = item;
    }
 
    public void accept(AccountBookViewer viewer) {
        viewer.view(this);
    }
 
    public double getAmount() {
        return amount;
    }
 
    public String getItem() {
        return item;
    }
 
}

上面最關(guān)鍵的還是里面的accept方法馏谨,它直接讓訪問者訪問自己,這相當于一次靜態(tài)分派(文章最后進行解釋)附迷,當然我們也可以不使用重載而直接給方法不同的名稱惧互。

接下來是賬本訪問者接口

//賬單查看者接口(相當于Visitor)
public interface AccountBookViewer {
 
    //查看消費的單子
    void view(ConsumeBill bill);
 
    //查看收入的單子
    void view(IncomeBill bill);
 
}

這兩個方法是重載方法,就是在上面的元素類當中用到的喇伯,當然你也可以按照訪問者模式類圖當中的方式去做喊儡,將兩個方法分別命名為viewConsumeBill和viewIncomeBill,而一般建議按照類圖上來做的

訪問者的實現(xiàn)

//老板類稻据,查看賬本的類之一
public class Boss implements AccountBookViewer{
 
    private double totalIncome;
 
    private double totalConsume;
 
    //老板只關(guān)注一共花了多少錢以及一共收入多少錢艾猜,其余并不關(guān)心
    public void view(ConsumeBill bill) {
        totalConsume += bill.getAmount();
    }
 
    public void view(IncomeBill bill) {
        totalIncome += bill.getAmount();
    }
 
    public double getTotalIncome() {
        System.out.println("老板查看一共收入多少,數(shù)目是:" + totalIncome);
        return totalIncome;
    }
 
    public double getTotalConsume() {
        System.out.println("老板查看一共花費多少捻悯,數(shù)目是:" + totalConsume);
        return totalConsume;
    }
 
}
//注冊會計師類匆赃,查看賬本的類之一
public class CPA implements AccountBookViewer{
 
    //注會在看賬本時,如果是支出今缚,則如果支出是工資算柳,則需要看應(yīng)該交的稅交了沒
    public void view(ConsumeBill bill) {
        if (bill.getItem().equals("工資")) {
            System.out.println("注會查看工資是否交個人所得稅。");
        }
    }
    //如果是收入姓言,則所有的收入都要交稅
    public void view(IncomeBill bill) {
        System.out.println("注會查看收入交稅了沒瞬项。");
    }
 
}

老板只關(guān)心收入和支出的總額蔗蹋,而注會只關(guān)注該交稅的是否交稅

接下來是賬本類,它是當前訪問者模式例子中的對象結(jié)構(gòu)

//賬本類(相當于ObjectStruture)
public class AccountBook {
    //單子列表
    private List<Bill> billList = new ArrayList<Bill>();
    //添加單子
    public void addBill(Bill bill){
        billList.add(bill);
    }
    //供賬本的查看者查看賬本
    public void show(AccountBookViewer viewer){
        for (Bill bill : billList) {
            bill.accept(viewer);
        }
    }
}

賬本類當中有一個列表囱淋,這個列表是元素(Bill)的集合猪杭,這便是對象結(jié)構(gòu)的通常表示,它一般會是一堆元素的集合绎橘,不過這個集合不一定是列表胁孙,也可能是樹,鏈表等等任何數(shù)據(jù)結(jié)構(gòu)称鳞,甚至是若干個數(shù)據(jù)結(jié)構(gòu)涮较。其中show方法,就是賬本類的精髓冈止,它會枚舉每一個元素狂票,讓訪問者訪問。

測試客戶端

public class Client {
 
    public static void main(String[] args) {
        AccountBook accountBook = new AccountBook();
        //添加兩條收入
        accountBook.addBill(new IncomeBill(10000, "賣商品"));
        accountBook.addBill(new IncomeBill(12000, "賣廣告位"));
        //添加兩條支出
        accountBook.addBill(new ConsumeBill(1000, "工資"));
        accountBook.addBill(new ConsumeBill(2000, "材料費"));
 
        AccountBookViewer boss = new Boss();
        AccountBookViewer cpa = new CPA();
 
        //兩個訪問者分別訪問賬本
        accountBook.show(cpa);
        accountBook.show(boss);
 
        ((Boss) boss).getTotalConsume();
        ((Boss) boss).getTotalIncome();
    }
}

上面的代碼中熙暴,可以這么理解闺属,賬本以及賬本中的元素是非常穩(wěn)定的,這些幾乎不可能改變周霉,而最容易改變的就是訪問者這部分掂器。

訪問者模式最大的優(yōu)點就是增加訪問者非常容易,我們從代碼上來看俱箱,如果要增加一個訪問者国瓮,你只需要做一件事即可,那就是寫一個類狞谱,實現(xiàn)AccountBookViewer接口乃摹,然后就可以直接調(diào)用AccountBook的show方法去訪問賬本了。

如果沒使用訪問者模式跟衅,一定會增加許多if else孵睬,而且每增加一個訪問者,你都需要改你的if else伶跷,代碼會顯得非常臃腫掰读,而且非常難以擴展和維護。

靜態(tài)分派以及動態(tài)分派

變量被聲明時的類型叫做變量的靜態(tài)類型(Static Type)撩穿,有些人又把靜態(tài)類型叫做明顯類型(Apparent Type)磷支;而變量所引用的對象的真實類型又叫做變量的實際類型(Actual Type)。比如:

List list = null;
list = new ArrayList();

聲明了一個變量list食寡,它的靜態(tài)類型(也叫明顯類型)是List,而它的實際類型是ArrayList廓潜。根據(jù)對象的類型而對方法進行的選擇抵皱,就是分派(Dispatch)善榛,分派(Dispatch)又分為兩種,即靜態(tài)分派和動態(tài)分派呻畸。靜態(tài)分派(Static Dispatch)發(fā)生在編譯時期移盆,分派根據(jù)靜態(tài)類型信息發(fā)生。

靜態(tài)分派
靜態(tài)分派就是按照變量的靜態(tài)類型進行分派伤为,從而確定方法的執(zhí)行版本咒循,靜態(tài)分派在編譯時期就可以確定方法的版本。而靜態(tài)分派最典型的應(yīng)用就是方法重載

public class Main {
 
    public void test(String string){
        System.out.println("string");
    }
 
    public void test(Integer integer){
        System.out.println("integer");
    }
 
    public static void main(String[] args) {
        String string = "1";
        Integer integer = 1;
        Main main = new Main();
        main.test(integer);
        main.test(string);
    }
}

在靜態(tài)分派判斷的時候绞愚,我們根據(jù)多個判斷依據(jù)(即參數(shù)類型和個數(shù))判斷出了方法的版本叙甸,那么這個就是多分派的概念,因為我們有一個以上的考量標準位衩,也可以稱為宗量裆蒸。所以JAVA是靜態(tài)多分派的語言。

動態(tài)分派
對于動態(tài)分派糖驴,與靜態(tài)相反僚祷,它不是在編譯期確定的方法版本,而是在運行時才能確定贮缕。而動態(tài)分派最典型的應(yīng)用就是多態(tài)的特性

interface Person{
    void test();
}
class Man implements Person{
    public void test(){
        System.out.println("男人");
    }
}
class Woman implements Person{
    public void test(){
        System.out.println("女人");
    }
}
public class Main {
 
    public static void main(String[] args) {
        Person man = new Man();
        Person woman = new Woman();
        man.test();
        woman.test();
    }
}

這段程序輸出結(jié)果為依次打印男人和女人辙谜,然而這里的test方法版本,就無法根據(jù)man和woman的靜態(tài)類型去判斷了感昼,他們的靜態(tài)類型都是Person接口装哆,根本無從判斷。

顯然抑诸,產(chǎn)生的輸出結(jié)果烂琴,就是因為test方法的版本是在運行時判斷的,這就是動態(tài)分派蜕乡。

動態(tài)分派判斷的方法是在運行時獲取到man和woman的實際引用類型奸绷,再確定方法的版本,而由于此時判斷的依據(jù)只是實際引用類型层玲,只有一個判斷依據(jù)号醉,所以這就是單分派的概念,這時我們的考量標準只有一個宗量辛块,即變量的實際引用類型畔派。相應(yīng)的,這說明JAVA是動態(tài)單分派的語言润绵。

訪問者模式中的偽動態(tài)雙分派

訪問者模式中使用的是偽動態(tài)雙分派线椰,所謂的動態(tài)雙分派就是在運行時依據(jù)兩個實際類型去判斷一個方法的運行行為,而訪問者模式實現(xiàn)的手段是進行了兩次動態(tài)單分派來達到這個效果尘盼。

回到上面例子當中賬本類中的accept方法

for (Bill bill : billList) {
            bill.accept(viewer);
        }

這里就是依據(jù)biil和viewer兩個實際類型決定了view方法的版本憨愉,從而決定了accept方法的動作烦绳。

分析accept方法的調(diào)用過程
1.當調(diào)用accept方法時,根據(jù)bill的實際類型決定是調(diào)用ConsumeBill還是IncomeBill的accept方法配紫。

2.這時accept方法的版本已經(jīng)確定烈钞,假如是ConsumeBill钳吟,它的accept方法是調(diào)用下面這行代碼闷串。

 public void accept(AccountBookViewer viewer) {
        viewer.view(this);
    }
}

此時的this是ConsumeBill類型佑力,所以對應(yīng)于AccountBookViewer接口的view(ConsumeBill bill)方法,此時需要再根據(jù)viewer的實際類型確定view方法的版本植袍,如此一來惧眠,就完成了動態(tài)雙分派的過程。

以上的過程就是通過兩次動態(tài)雙分派奋单,第一次對accept方法進行動態(tài)分派锉试,第二次對view(類圖中的visit方法)方法進行動態(tài)分派,從而達到了根據(jù)兩個實際類型確定一個方法的行為的效果览濒。

而原本我們的做法呆盖,通常是傳入一個接口,直接使用該接口的方法贷笛,此為動態(tài)單分派应又,就像策略模式一樣。在這里乏苦,show方法傳入的viewer接口并不是直接調(diào)用自己的view方法株扛,而是通過bill的實際類型先動態(tài)分派一次,然后在分派后確定的方法版本里再進行自己的動態(tài)分派汇荐。

注意:這里確定view(ConsumeBill bill)方法是靜態(tài)分派決定的洞就,所以這個并不在此次動態(tài)雙分派的范疇內(nèi),而且靜態(tài)分派是在編譯期就完成的掀淘,所以view(ConsumeBill bill)方法的靜態(tài)分派與訪問者模式的動態(tài)雙分派并沒有任何關(guān)系旬蟋。動態(tài)雙分派說到底還是動態(tài)分派,是在運行時發(fā)生的革娄,它與靜態(tài)分派有著本質(zhì)上的區(qū)別倾贰,不可以說一次動態(tài)分派加一次靜態(tài)分派就是動態(tài)雙分派,而且訪問者模式的雙分派本身也是另有所指拦惋。

這里的this的類型不是動態(tài)確定的匆浙,你寫在哪個類當中,它的靜態(tài)類型就是哪個類厕妖,這是在編譯期就確定的首尼,不確定的是它的實際類型,請各位區(qū)分開這一點。

對訪問者模式的一些思考

假設(shè)我們上面的例子當中再添加一個財務(wù)主管饰恕,而財務(wù)主管不管你是支出還是收入挠羔,都要詳細的查看你的單子的項目以及金額井仰,簡單點說就是財務(wù)主管類的兩個view方法的代碼是一樣的埋嵌。

這里的將兩個view方法抽取的方案是,我們可以將元素提煉出層次結(jié)構(gòu)俱恶,針對層次結(jié)構(gòu)提供操作的方法雹嗦,這樣就實現(xiàn)了優(yōu)點當中最后兩點提到的針對層次定義操作以及跨越層次定義操作。

//單個單子的接口(相當于Element)
public interface Bill {
 
    void accept(Viewer viewer);
 
}
//抽象單子類合是,一個高層次的單子抽象
public abstract class AbstractBill implements Bill{
 
    protected double amount;
 
    protected String item;
 
    public AbstractBill(double amount, String item) {
        super();
        this.amount = amount;
        this.item = item;
    }
 
    public double getAmount() {
        return amount;
    }
 
    public String getItem() {
        return item;
    }
 
}
//收入單子
public class IncomeBill extends AbstractBill{
 
    public IncomeBill(double amount, String item) {
        super(amount, item);
    }
 
    public void accept(Viewer viewer) {
        if (viewer instanceof AbstractViewer) {
            ((AbstractViewer)viewer).viewIncomeBill(this);
            return;
        }
        viewer.viewAbstractBill(this);
    }
 
}
//消費的單子
public class ConsumeBill extends AbstractBill{
 
    public ConsumeBill(double amount, String item) {
        super(amount, item);
    }
 
    public void accept(Viewer viewer) {
        if (viewer instanceof AbstractViewer) {
            ((AbstractViewer)viewer).viewConsumeBill(this);
            return;
        }
        viewer.viewAbstractBill(this);
    }
 
}

這是元素類的層次結(jié)構(gòu)了罪,可以看到,我們的accept當中出現(xiàn)了if判斷聪全,這里的判斷是在判斷一個層次泊藕,這段代碼是不會被更改的。

訪問者層次

//超級訪問者接口(它支持定義高層操作)
public interface Viewer{
 
    void viewAbstractBill(AbstractBill bill);
 
}
//比Viewer接口低一個層次的訪問者接口
public abstract class AbstractViewer implements Viewer{
 
    //查看消費的單子
    abstract void viewConsumeBill(ConsumeBill bill);
 
    //查看收入的單子
    abstract void viewIncomeBill(IncomeBill bill);
 
    public final void viewAbstractBill(AbstractBill bill){}
}
//老板類难礼,查看賬本的類之一娃圆,作用于最低層次結(jié)構(gòu)
public class Boss extends AbstractViewer{
 
    private double totalIncome;
 
    private double totalConsume;
 
    //老板只關(guān)注一共花了多少錢以及一共收入多少錢,其余并不關(guān)心
    public void viewConsumeBill(ConsumeBill bill) {
        totalConsume += bill.getAmount();
    }
 
    public void viewIncomeBill(IncomeBill bill) {
        totalIncome += bill.getAmount();
    }
 
    public double getTotalIncome() {
        System.out.println("老板查看一共收入多少蛾茉,數(shù)目是:" + totalIncome);
        return totalIncome;
    }
 
    public double getTotalConsume() {
        System.out.println("老板查看一共花費多少讼呢,數(shù)目是:" + totalConsume);
        return totalConsume;
    }
 
}
//注冊會計師類,查看賬本的類之一谦炬,作用于最低層次結(jié)構(gòu)
public class CPA extends AbstractViewer{
 
    //注會在看賬本時悦屏,如果是支出,則如果支出是工資键思,則需要看應(yīng)該交的稅交了沒
    public void viewConsumeBill(ConsumeBill bill) {
        if (bill.getItem().equals("工資")) {
            System.out.println("注會查看是否交個人所得稅础爬。");
        }
    }
    //如果是收入,則所有的收入都要交稅
    public void viewIncomeBill(IncomeBill bill) {
        System.out.println("注會查看收入交稅了沒吼鳞。");
    }
 
}
//財務(wù)主管類看蚜,查看賬本的類之一,作用于高層的層次結(jié)構(gòu)
public class CFO implements Viewer {
 
    //財務(wù)主管對每一個單子都要核對項目和金額
    public void viewAbstractBill(AbstractBill bill) {
        System.out.println("財務(wù)主管查看賬本時赖条,每一個都核對項目和金額失乾,金額是" + bill.getAmount() + ",項目是" + bill.getItem());
    }
 
}

財務(wù)主管(CFO)是針對AbstractBill這一層定義的操作纬乍,而原來的老板(Boss)和注冊會計師(CPA)都是針對ConsumeBill和IncomeBill這一層定義的操作碱茁,這時已經(jīng)產(chǎn)生了跨越層次結(jié)構(gòu)的行為,老板和注冊會計師都跨過了抽象單子這一層仿贬,直接針對具體的單子定義操作纽竣。

賬本類沒有變化,最后看客戶端的使用

public class Client {
 
    public static void main(String[] args) {
        AccountBook accountBook = new AccountBook();
        //添加兩條收入
        accountBook.addBill(new IncomeBill(10000, "賣商品"));
        accountBook.addBill(new IncomeBill(12000, "賣廣告位"));
        //添加兩條支出
        accountBook.addBill(new ConsumeBill(1000, "工資"));
        accountBook.addBill(new ConsumeBill(2000, "材料費"));
 
        Viewer boss = new Boss();
        Viewer cpa = new CPA();
        Viewer cfo = new CFO();
 
        //兩個訪問者分別訪問賬本
        accountBook.show(cpa);
        accountBook.show(boss);
        accountBook.show(cfo);
 
        ((Boss) boss).getTotalConsume();
        ((Boss) boss).getTotalIncome();
    }
}

回想一下,要是再出現(xiàn)和財務(wù)主管一樣對所有單子都是一樣操作的人蜓氨,我們就不需要復(fù)制代碼了聋袋,只需要讓他實現(xiàn)Viewer接口就可以了,而如果要像老板和注會一樣區(qū)分單子的具體類型穴吹,則繼承AbstractViewer就可以幽勒。

總結(jié)

優(yōu)點:

1、使得數(shù)據(jù)結(jié)構(gòu)和作用于結(jié)構(gòu)上的操作解耦港令,使得操作集合可以獨立變化啥容。

2、添加新的操作或者說訪問者會非常容易顷霹。

3咪惠、將對各個元素的一組操作集中在一個訪問者類當中。

4淋淀、使得類層次結(jié)構(gòu)不改變的情況下遥昧,可以針對各個層次做出不同的操作,而不影響類層次結(jié)構(gòu)的完整性朵纷。

5炭臭、可以跨越類層次結(jié)構(gòu),訪問不同層次的元素類柴罐,做出相應(yīng)的操作徽缚。

缺點:

1、增加新的元素會非常困難革屠。

2凿试、實現(xiàn)起來比較復(fù)雜,會增加系統(tǒng)的復(fù)雜性似芝。

3那婉、破壞封裝,如果將訪問行為放在各個元素中党瓮,則可以不暴露元素的內(nèi)部結(jié)構(gòu)和狀態(tài)详炬,但使用訪問者模式的時候,為了讓訪問者能獲取到所關(guān)心的信息寞奸,元素類不得不暴露出一些內(nèi)部的狀態(tài)和結(jié)構(gòu)呛谜,就像收入和支出類必須提供訪問金額和單子的項目的方法一樣。

適用性:

1枪萄、數(shù)據(jù)結(jié)構(gòu)穩(wěn)定隐岛,作用于數(shù)據(jù)結(jié)構(gòu)的操作經(jīng)常變化的時候。

2瓷翻、當一個數(shù)據(jù)結(jié)構(gòu)中聚凹,一些元素類需要負責與其不相關(guān)的操作的時候割坠,為了將這些操作分離出去,以減少這些元素類的職責時妒牙,可以使用訪問者模式彼哼。

3、有時在對數(shù)據(jù)結(jié)構(gòu)上的元素進行操作的時候湘今,需要區(qū)分具體的類型敢朱,這時使用訪問者模式可以針對不同的類型,在訪問者類中定義不同的操作象浑,從而去除掉類型判斷蔫饰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市愉豺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌茫因,老刑警劉巖蚪拦,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異冻押,居然都是意外死亡驰贷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門洛巢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來括袒,“玉大人,你說我怎么就攤上這事稿茉∏旅蹋” “怎么了?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵漓库,是天一觀的道長恃慧。 經(jīng)常有香客問我,道長渺蒿,這世上最難降的妖魔是什么痢士? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮茂装,結(jié)果婚禮上怠蹂,老公的妹妹穿的比我還像新娘。我一直安慰自己少态,他們只是感情好城侧,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著况增,像睡著了一般赞庶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天歧强,我揣著相機與錄音澜薄,去河邊找鬼。 笑死摊册,一個胖子當著我的面吹牛肤京,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茅特,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼忘分,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了白修?” 一聲冷哼從身側(cè)響起妒峦,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎兵睛,沒想到半個月后肯骇,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡祖很,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年笛丙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片假颇。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡胚鸯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出笨鸡,到底是詐尸還是另有隱情姜钳,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布镜豹,位于F島的核電站傲须,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏趟脂。R本人自食惡果不足惜泰讽,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昔期。 院中可真熱鬧已卸,春花似錦、人聲如沸硼一。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽般贼。三九已至愧哟,卻和暖如春奥吩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蕊梧。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工霞赫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肥矢。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓端衰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親甘改。 傳聞我的和親對象是個殘疾皇子旅东,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

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

  • 定義 訪問者模式是對象的行為模式。訪問者模式的目的是封裝一些施加于某種數(shù)據(jù)結(jié)構(gòu)元素之上的操作十艾。一旦這些操作需要修改...
    步積閱讀 1,227評論 0 3
  • 目錄 本文的結(jié)構(gòu)如下: 引言 什么是訪問者模式 模式的結(jié)構(gòu) 典型代碼 訪問者模式中的偽動態(tài)雙分派 代碼示例 訪問者...
    w1992wishes閱讀 862評論 0 6
  • 一抵代、簡述 訪問者模式是一種將數(shù)據(jù)操作和數(shù)據(jù)結(jié)構(gòu)分離的設(shè)計模式,是23種設(shè)計模式中非常復(fù)雜的一種疟羹,而且使用頻率并不高...
    MrTrying閱讀 1,201評論 1 9
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月主守,有人笑有人哭,有人歡樂有人憂愁榄融,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,535評論 28 53
  • 信任包括信任自己和信任他人 很多時候救湖,很多事情愧杯,失敗、遺憾鞋既、錯過力九,源于不自信,不信任他人 覺得自己做不成邑闺,別人做不...
    吳氵晃閱讀 6,187評論 4 8