iOS設(shè)計模式(二)-21種設(shè)計模式

對象創(chuàng)建-Object Creation


1.原型 -Prototype

定義
原型模式是一種簡單的設(shè)計模式媳荒,客戶端知道抽象Prototype類。在運(yùn)行時,抽象Prototype子類的任何對象都可以按照客戶端的意圖來進(jìn)行復(fù)制泼返。因此無需手工創(chuàng)建就可以創(chuàng)造同一類型的多個實例。

類圖

原型模式的類圖

使用場景
在以下情形姨拥,會考慮使用原型模式:

  • 需要創(chuàng)建的對象應(yīng)獨(dú)立于其類型與創(chuàng)建方式
  • 要實例化的類是在運(yùn)行時決定的
  • 不想要一個與產(chǎn)品層次相對應(yīng)的工廠層次(也就是工廠類不需要與產(chǎn)品類一一對應(yīng))
  • 不同類實例間的差異僅是狀態(tài)的若干組合绅喉。因此復(fù)制相應(yīng)數(shù)量的原型比手工實例化更加方便。
  • 類不容易創(chuàng)建叫乌,比如每個組件可把其他組件作為子節(jié)點(diǎn)的組合對象柴罐。復(fù)制已有的組合對象并對副本進(jìn)行修改會更加容易

使用原型模式的常見誤解是“原型對象應(yīng)該是一種象征性對象從來不切實用”,從功能的角度上來看,不管什么對象,只要復(fù)制自身比手工實例化要好,都可以是原型對象.在以下兩種特別常見的情形,我們會考慮使用此Prototype模式:

  1. 有很多相關(guān)的類,其行為略有不同,而且主要差異在于內(nèi)部屬性,如名稱,圖像等
  2. 需要使用組合(樹形)對象作為其他東西的基礎(chǔ),例如,使用組合對象作為組件來構(gòu)建另一個組合對象.
    現(xiàn)實世界中還有許多狀況應(yīng)該應(yīng)用這一模式.使用設(shè)計模式更像藝術(shù)行為而非科學(xué)行為.打破常規(guī),用于創(chuàng)新,更聰明地工作.

此模式的最低限度是生成對象的真實副本(對象復(fù)制,深/淺復(fù)制),以作為同一環(huán)境下其他相關(guān)事物的基礎(chǔ)(原型)

2.工廠方法-Factory Method

定義
工廠方法也稱為虛構(gòu)造器(virtual constructor).它適用的情形是"一個類無法預(yù)期需要生成那個類的對象,想讓其子類來指定所生成的對象".所以工廠方法可以使得一個類的實例化延遲到其子類.

類圖

工廠模式類圖

使用場景
在以下情形,會考慮使用工廠方法模式:

  • 編譯時無法準(zhǔn)確定預(yù)期要創(chuàng)建的對象的類
  • 類想讓其子類決定在運(yùn)行時創(chuàng)建什么
  • 類有若干輔助類為其子類,而你想將返回哪個子類這一信息局部化(原文:A class has some helper classes as its subclasses and you want to localize the knowledge of which one to return)

使用這一模式的最低限度是,工廠方法能給予類在變更返回哪一種對象這一點(diǎn)上更多的靈活性.

3.抽象工廠-Abstract Factory

定義
抽象工廠模式提供一個固定的接口,用于創(chuàng)建一系列有關(guān)聯(lián)或相依存的對象,而不必指定其具體類或其創(chuàng)建的細(xì)節(jié).客戶端與工廠得到的具體對象之間沒有耦合.

類圖

抽象工廠模式類圖

通過上面類圖所示, Client只知道AbstractFactory和AbstractProduct.每個工廠類中,結(jié)構(gòu)與實際操作的細(xì)節(jié)按黑箱對待.甚至產(chǎn)品也不知道誰將負(fù)責(zé)創(chuàng)建它們.只有具體的工廠知道為客戶端創(chuàng)建什么,如何創(chuàng)建.這個模式有一個有趣點(diǎn)是,很多時候它都是用
工廠方法模式來實現(xiàn).工廠方法把實際的創(chuàng)建過程推遲到重載它的子類中.在類圖中,方法createProductA和createProductB是工廠方法.最初的抽象方法什么也不知道.這種抽象非常通用,廣泛用于任何需要抽象創(chuàng)建過程的場合.

抽象工廠模式常與原型模式,單例模式,享元模式等其他一些設(shè)計模式一起使用.

使用場景
抽象工廠與工廠方法模式在許多方面都非常相似.很多人常常搞不清應(yīng)該在什么時候用哪個. 兩個模式都用于相同的目的:創(chuàng)建對象而不讓客戶端知曉返回了什么確切的具體對象.下表為抽象工廠模式與工廠方法模式的對比.

抽象工廠 工廠方法
通過對象組合創(chuàng)建抽象產(chǎn)品 通過類繼承創(chuàng)建抽象產(chǎn)品
創(chuàng)建多系列產(chǎn)品 創(chuàng)建一種產(chǎn)品
必須修改父類的接口才能支持新的產(chǎn)品 子類化創(chuàng)建者并重載工廠方法以創(chuàng)建新產(chǎn)品

4.生成器-Builder

定義
有時,構(gòu)建某些對象有多種不同的方式.如果這些邏輯包含在構(gòu)建這些對象的類的單一方法中,構(gòu)建的邏輯會非澈┘椋荒唐(列如,針對各種構(gòu)建需求的一大片嵌套if-else或者switch-case語句),如果能夠把構(gòu)建過程分解為"客戶-指導(dǎo)者-生成器"(client-director-builder)的關(guān)系,那么過程將更容易管理與復(fù)用.針對此類關(guān)系的設(shè)計模式稱為生成器.

生成器模式: 將一個復(fù)雜對象的構(gòu)建與它的表現(xiàn)分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表現(xiàn)

類圖

生成器模式類圖

  • 在生成器模式中,除了要生成的產(chǎn)品product和客戶client之外,還要兩個關(guān)鍵角色就是:指導(dǎo)者Director,和生成器Builder.
  • 這種模式將產(chǎn)品的創(chuàng)建過程(需要一個什么樣(what)的產(chǎn)品,如何(how)創(chuàng)建這樣的產(chǎn)品)中的how和what分離了
  • Director知道需要什么樣(what)的產(chǎn)品, Builder生成器知道如何(how)創(chuàng)建產(chǎn)品
客戶端-指導(dǎo)者-生成器之間交互的時序圖
  • Builder是個抽象接口,聲明了一個builderPart方法,該builder方法由ConcretBuilder實現(xiàn),以構(gòu)造實際產(chǎn)品(Product).
  • ConcretBuilder有個getResult方法,向客戶端返回構(gòu)造完畢的Product.
  • Director定義了一個construct方法,命令Builder的實例去buildPart.
  • Director和Builder形成了一種聚合關(guān)系,這意味著Builder是一個組成部分,與Director結(jié)合,以使整個模式運(yùn)轉(zhuǎn),但Director并不負(fù)責(zé)Builder的生存期.

使用場景
在以下情形革屠,會考慮使用生成器模式:

  • 需要創(chuàng)建涉及各種部件的復(fù)雜對象.創(chuàng)建對象的算法應(yīng)該獨(dú)立于部件的裝配方式.常見列子是構(gòu)建組合對象
  • 構(gòu)建過程需要以不同的方式(列如,部件或變現(xiàn)的不同組合)構(gòu)建對象.

生成器和抽象工廠的對比
抽象工廠和生成器模式很相似,然后兩者還是有很大的區(qū)別的:

  • 生成器關(guān)注的是分布創(chuàng)建復(fù)雜對象,很多時候同一類型的對象可以以不同的方式創(chuàng)建.
  • 抽象工廠的重點(diǎn)在于創(chuàng)建簡單或復(fù)雜產(chǎn)品的套件
  • 生成器在多步創(chuàng)建過程的最后一步放回產(chǎn)品,而抽象工廠則立即返回產(chǎn)品

表格:生成器模式和抽象工廠模式的主要差異

生成器 抽象工廠
構(gòu)建復(fù)雜對象 構(gòu)建簡單或復(fù)雜對象
以多個步驟創(chuàng)建對象 以單一步驟創(chuàng)建對象
以多種方式構(gòu)建對象 以單一方式構(gòu)建對象
在構(gòu)建過程的最后一步返回產(chǎn)品 立刻返回產(chǎn)品
專注一個特定產(chǎn)品 強(qiáng)調(diào)一套產(chǎn)品

生成器模式的整體思想是:分離"什么"和"如何",使得aDirector能把同一個"什么"(規(guī)格)應(yīng)用到不同的aBuilder,而它懂得"如何"按照給定的規(guī)格構(gòu)建自己特定的產(chǎn)品.

5.單例-Singleton

定義
面向?qū)ο髴?yīng)用程序中的單例類(singleton class)總是返回自己的同一個實例. 它提供了對類的對象的所提供的資源的全局訪問點(diǎn),與這類設(shè)計相關(guān)的設(shè)計模式稱為單例模式.

  • 單例模式幾乎是最簡單的設(shè)計模式了
  • 這一模式意圖使得類的一個對象成為系統(tǒng)中的唯一實例
  • 單例模式:保證一個類僅有個實例,并提供一個訪問它的全局訪問點(diǎn)

類圖

單例模式的靜態(tài)結(jié)構(gòu)圖

使用場景
在以下情形,會考慮使用單例模式:

  • 類只能有一個實例,而且必須從一個為人熟知的訪問點(diǎn)對其進(jìn)行訪問,比如工廠方法
  • 這個唯一的實例只能通過子類化進(jìn)行擴(kuò)展,而且擴(kuò)展的對象不會破壞客戶端代碼

接口適配-Interface Adaptation

6.適配器-Adapter

定義

  • 適配器模式是用于連接兩種不同種類的對象,使其毫無問題地協(xié)同工作.有時它也被稱為"包裝器(wrapper)"
  • 思想很簡單:適配器實現(xiàn)客戶端所需要的某種接口的行為.同時,它又連接到另一個具有(完全)不同接口與行為的對象.
  • 一邊是客戶端懂得如何使用的目標(biāo)接口,另一邊是客戶端一無所知的被試配者,適配器站在兩者之間,所以適配器的主要作用是把被試配者的行為傳遞給管道另一端的客戶端

類圖
按照實現(xiàn)適配器模式的兩種方式分為兩種

  • 類適配器


    類適配器的類圖
    • Adapter是一個Target類型,同時也是一個Adaptee類型.Adapter重載Target的request方法.
    • Adapter沒有重載Adaptee的specificRequest方法,而是在Adapter的request方法的實現(xiàn)中,調(diào)用超類的specificRequest方法.request方法在運(yùn)行時向超類發(fā)送[super specificRequest]消息.super就是Adaptee,它在Adapter的request方法的作用域內(nèi),按照自己的方式執(zhí)行specificRequesst方法.
    • 只有當(dāng)Target是協(xié)議而不是類時,類適配器才能夠使用OC來實現(xiàn).
  • 對象適配器


    對象適配器的類圖
    • 與類適配器不同,對象適配器不繼承被適配者,而是組合了一個對它的引用.所以Adapter和Adaptee之間的關(guān)系從"屬于"變成了"包含".
    • Adapter需要保持一個對Adapter的引用. 在request方法中,Adapter發(fā)送[adaptee specificRequest]消息給引用adaptee,以間接訪問它的行為,然后實現(xiàn)客戶端請求的其余部分
    • 由于Adapter與Adaptee之間是一種"包含"的關(guān)系,用Adapter去適配Adaptee的子類也沒有什么問題.

類適配和對象適配器的對比
類適配器與對象適配器是實現(xiàn)適配器模式的不同方式,但是達(dá)成的目的相同.設(shè)計中采用適配器模式時應(yīng)該選擇哪一種呢? 請看下表:類適配器和對象適配器的特征對比

類適配器 對象適配器
只針對單一的具體Adaptee類,把Adaptee適配到Target 可以適配多個Adaptee及其子類
易于重載Adaptee的行為,因為是通過直接的子類化進(jìn)行適配 難以重載Adaptee的行為,需要借助于子類的對象而不是Adaptee本身
只有一個Adapter對象,無需額外的指針間接訪問Adaptee 需要額外的指針以間接訪問Adaptee并適配其行為

提示,OC中委托模式(Delegate)屬于對象適配器

使用場景
在以下情形排宰,會考慮使用適配器模式:

  • 已有類的接口與需求不匹配
  • 想要一個可復(fù)用的類,該類能夠同可能帶有不兼容接口的其他類協(xié)作
  • 需要適配一個類的幾個不同子類, 可是讓每個子類去子類化一個類適配器有不現(xiàn)實.那么可以使用對象適配(也叫委托)來適配其父類的接口

適配器模式:將一個類的接口轉(zhuǎn)換成客戶希望的另一個接口,適配器模式使得原來由于接口不兼容而不能一起工作的那些類可以一起工作.

7.橋接-Bridge

定義
橋接模式的目的是把抽象層次結(jié)構(gòu)從器實現(xiàn)中分離出來,使其能夠獨(dú)立變更.抽象層定義了供客戶端使用的上層的抽象接口.實現(xiàn)層次結(jié)構(gòu)定義了供抽象層次使用的底層接口.實現(xiàn)類的引用被封裝于抽象層的實例中時,橋接就形成了.

類圖

橋接模式類圖

  • Abstraction是定義了供客戶端使用的上層抽象接口的父接口.它有一個對Implementor實例的引用.
  • Implementor是定義了實現(xiàn)類的接口,這個接口不必和Abstraction的接口一致,其實兩個接口可以相當(dāng)?shù)牟煌? Implementor的接口提供基本的操作,而Abstraction的上層操作基于這些基本操作
  • 當(dāng)客戶端向Abstraction的實例發(fā)送operation消息時,這個方法向imp發(fā)送的operationImp消息.底下的實際ConcreteImplementator(A/B)將作出反應(yīng)并接受任務(wù).

作用

  • 想要往系統(tǒng)中添加新的ConcreteImplementator時,所需要做的只是為Implementor創(chuàng)建一個新的實現(xiàn)類,響應(yīng)operationImp消息并在其中任何具體的操作.不過,這對Abstraction方面不會有任何影響.
  • 如果想修改Abstraction的接口或者創(chuàng)建更細(xì)化的Abstraction類,也能做到不影響橋接的另一頭.

橋接模式:將抽象部分與它的實現(xiàn)部分分離,使它們都可以獨(dú)立地變化

使用場景
在以下情形屠阻,會考慮使用橋接模式:

  • 不想在抽象與其實現(xiàn)之間形成固定的綁定關(guān)系(這樣就能在運(yùn)行時切換實現(xiàn));
  • 抽象及其實現(xiàn)都應(yīng)可以通過子類化獨(dú)立進(jìn)行擴(kuò)展
  • 對抽象的實現(xiàn)進(jìn)行修改不應(yīng)該影響客戶端代碼
  • 如果每個實現(xiàn)需要額外的子類以細(xì)化抽象,則說明有必要把他們分成兩個部分
  • 想在帶有不同抽象接口的多個對象之間共享一個實現(xiàn).

8.外觀-Facade

定義
很多舊的面向?qū)ο髴?yīng)用程序中,可能有許多類分散于帶有各種功能的系統(tǒng)之中.要把這些類用于某個功能,需要知道全部細(xì)節(jié)才能在一組算法中使用它們.如果從邏輯上將其中一些類組合成一個簡化的接口,可以讓這些類更易于使用.為子類系統(tǒng)中一組不同接口提供統(tǒng)一接口的一種方式稱為外觀模式.

結(jié)構(gòu)圖

一個外觀實現(xiàn)的示例結(jié)構(gòu)圖

  • 外觀模式為子系統(tǒng)中一組不同的接口提供統(tǒng)一的接口.外觀定義了上層接口,通過降低復(fù)雜度和隱藏子系統(tǒng)間的通信及依賴關(guān)系,讓子系統(tǒng)更易于使用.
  • 外觀模式起到整個子系統(tǒng)入口的作用.有些客戶端只需要子系統(tǒng)的某些基本行為,而對子系統(tǒng)的類不做太多定制,外觀為這樣的客戶端提供簡化的接口.
  • 只有需要從某些子系統(tǒng)的類定制更多行為的客戶端,才會關(guān)注外觀背后的細(xì)節(jié).

例子:乘客打車去目的地,只要發(fā)送一個指令"我要去xx地",就可以簡化司機(jī)開車,開什么車,怎樣開車,走什么路線這樣一個復(fù)雜的過程. 下面是這個列子的使用外觀模式實現(xiàn)的類圖

出租車?yán)拥念悎D

使用場景
在以下情形,會考慮使用外觀模式:

  • 子系統(tǒng)正逐漸變的復(fù)雜. 應(yīng)用模式的過程中演化出許多類.可以使用外觀為這些子系統(tǒng)類提供一個較簡單的接口.
  • 可以使用外觀對子系統(tǒng)進(jìn)行分層. 每個子系統(tǒng)級別有一個外觀作為入口點(diǎn). 讓它們通過其外觀進(jìn)行通信,可以簡化它們的依賴關(guān)系.

外觀模式:為系統(tǒng)中的一組接口提供一個統(tǒng)一的接口. 外觀定義了一個高層接口,讓子系統(tǒng)更易于使用.

對象去耦-Decoupling of Objects

9.中介者-Mediator ※※※

定義

  • 面向?qū)ο蟮脑O(shè)計鼓勵把行為分散到不同對象中.這種分散可能導(dǎo)致對象之間的相互關(guān)聯(lián).在最糟糕的情況下,所有對象都彼此了解相互操作.
  • 雖然把行為分散到不同對象增強(qiáng)了可復(fù)用性,但是增加的相互關(guān)聯(lián)又減少了獲得的益處.增加的關(guān)聯(lián)使得對象很難或不能依賴其他對象的情況下工作.應(yīng)用程序的整體行為可能難以進(jìn)行任何重大修改,因為行為分布于許多對象.于是結(jié)果可能是創(chuàng)建越來越多的子類,以支持應(yīng)用程序的任何新行為
  • 中介者模式用于定義一個集中的場所,對象間的交互可以在一個中介者對象處理.其他對象不必彼此交互,因此減少了它們之間的依存關(guān)系.

中介者模式:用一個對象來封裝一系列對象的交互方式. 中介者使各個對象不需要顯式地相互引用,從而使其耦合松散,而且可以獨(dú)立地改變它們之間的交互

類圖

一個中介者設(shè)計模式例子的類圖

  • 抽象的Mediator定義了用于同Colleague交互的一般行為
  • 具體的同事colleague是以明確定義的方式進(jìn)行相互交互通信的對象,并且彼此緊密依存. ConcreteMediator為Concrete Colleague定義了更加具體的行為,因此可以子類化Mediator,把各種Colleague交互算法應(yīng)用到相同或不同的Colleague類型.如果應(yīng)用程序只需要一個中介者,有時抽象的Mediator可以省略.
  • Colleague的實例有一個Mediator實例的引用,同時Mediator的實例知道參與這個組織的每個對象.

運(yùn)行時中介者模式的一種可能的對象結(jié)構(gòu)圖:


對象圖顯示了運(yùn)行時中介者模式的對象結(jié)構(gòu)

使用場景
在以下情形额各,會考慮使用中介者模式:

  • 對象間的交互雖定義明確然而非常復(fù)雜,導(dǎo)致一組對象彼此相互依賴而且難以理解
  • 因為對象引用了許多其他對象并與其通訊,導(dǎo)致對象難以復(fù)用;
  • 想要定制一個分布在許多個類中的邏輯或行為,又不想生成太多子類

10.觀察者-Observer

定義

  • 觀察者模式也叫發(fā)布-訂閱模式. 如它的別名所指那樣,它很像雜志訂閱.當(dāng)從雜志發(fā)行商訂閱雜志的時候,讀者把名字和郵寄地址提供給發(fā)行商,這樣新的一期就能送到讀者手上.
  • 觀察者模式可以消除不同對象間的耦合(或者用其他不同的行為來擴(kuò)展現(xiàn)有的行為).通過這一模式,不同對象可以協(xié)同工作,同時它們也可以被復(fù)用于其他地方.

觀察者模式: 定義對象間的一種一對多的依賴關(guān)系,當(dāng)一個對象的狀態(tài)發(fā)生改變時,所有依賴于它的對象都得到通知并被自動更新.

類圖

觀察者類圖

  • 觀察者模式是一種發(fā)布-訂閱模型. Observer從Subject訂閱通知. ConreteObserver實現(xiàn)抽象Observer并重載Update方法.
  • 一旦Subject的實例需要通知Observer任何新的變更,Subject會發(fā)送update消息來通知存儲在內(nèi)部表中的所有注冊的Observer
  • 在ConcreteObserver的update方法的實際實現(xiàn)中,Subject的內(nèi)部狀態(tài)可被取得并在以后進(jìn)行處理.
顯示subject和其他observer之間交互的時序圖
  • 使用觀察者模式的一個最明顯的好處是,可以用N個Observer來擴(kuò)展Subject的行為,這些Observer具有處理存儲在Subject中信息的特定實現(xiàn).
  • 它也是一種用于消除不同對象間耦合的一種設(shè)計模式

使用場景
在以下情形,會考慮使用觀察者模式:

  • 有兩種抽象類型相互依賴,將他們封裝在各自的對象中,就可以對它們單獨(dú)進(jìn)行改變和復(fù)用.
  • 對一個對象的改變需要同時改變其他對象,而不知到具體有多少對象有待改變.
  • 一個對象必須通知其他對象,而它又不需要知道其他對象是什么

抽象集合-Abstract Collection

11.組合-Composite

定義

  • 組合模式讓我們可以把相同基類型(base type)的對象組合到樹狀結(jié)構(gòu)中,其中的父節(jié)點(diǎn)包含同類型的子節(jié)點(diǎn). 換句話說,這種樹狀結(jié)構(gòu)形成"部分-整體"的層次結(jié)構(gòu).
  • 是一種既包含對象的組合(容器)又包含作為"葉節(jié)點(diǎn)"的單個對象的一種層次結(jié)構(gòu).
  • 每個組合體包含的其他節(jié)點(diǎn),可以是葉節(jié)點(diǎn)或者是其他組合體.這種關(guān)系在這個層次結(jié)構(gòu)中遞歸重復(fù).
  • 每個組合或葉節(jié)點(diǎn)有相同的基類型,同樣的操作可應(yīng)用于他們中的每一個,而不必在客戶端作類型檢查.
  • 客戶端對組合與葉節(jié)點(diǎn)進(jìn)行操作是可以忽略它們之間的差距.
一個典型的組合對象結(jié)構(gòu)
組合結(jié)構(gòu)模式的類圖
  • 基接口(base interface)是定義了Leaf類和Composite類的共同操作的Component
  • 有些操作只對Composite類有意義,這樣是為了不暴露內(nèi)部細(xì)節(jié)給客戶端

組合模式: 將對象組合成樹形結(jié)構(gòu)以表示"部分-整體"的層次結(jié)構(gòu). 組合使得用戶對單個對象和組合對象的使用具有一致性

使用場景
在以下情形吧恃,會考慮使用組合模式:

  • 想獲得對象抽象的樹形標(biāo)識(部分-整體層次結(jié)構(gòu))
  • 想讓客戶端統(tǒng)一處理組合結(jié)構(gòu)中所有對象.

12.迭代器-Iterator

定義

  • 在面向?qū)ο筌浖?針對抽象集合迭代行為的設(shè)計模式叫做迭代器(Iterator).
  • 迭代器提供了一種順序訪問聚合對象(集合)中元素的方法,而無需暴露結(jié)構(gòu)底層表示和細(xì)節(jié)
  • 遍歷集合中元素的智能從集合本身轉(zhuǎn)移到迭代器對象.
  • 迭代器定義了一個用于訪問集合元素并記錄當(dāng)前元素的接口.
  • 不同的迭代器可以執(zhí)行不同的遍歷策略

類圖

說明List與ListIterator之間關(guān)系的類圖

  • List定義了修改集合以及放回集合中元素個數(shù)的方法
  • ListIterator保持一個對List對象的引用,以便迭代器遍歷結(jié)構(gòu)中的元素并將其返回
  • ListIterator定義了讓客戶端從迭代過程中訪問下一項的方法.
  • 迭代器有個內(nèi)部的index_變量,記錄集合中的當(dāng)前的位置
更進(jìn)一步表示抽象列表與迭代器之間關(guān)系的類圖
  • 抽象的Aggregate定義了createIterator方法,它返回一個Iterator對象.
  • ConcreteAggregate對象子類化Aggregate,重載其createIterator方法并返回ConcreteIterator的實例.
  • Iterator抽象類定義了所有Iterator應(yīng)具有的基本行為,
  • 客戶端會使用定義好的抽象接口來遍歷任何Aggretate類型對象中的元素

迭代器: 提供一種方法順序訪問一個聚合對象中各個元素,而又不需要暴露該對象的內(nèi)部表示

外部迭代器與內(nèi)部迭代器

  • 外部迭代器讓客戶端直接操作迭代過程,所以客戶端需要知道外部迭代器才能使用
  • 另外一種情況是,集合對象(被迭代的目標(biāo)對象)在其內(nèi)部維護(hù)并操作一個內(nèi)部迭代器
  • 提供內(nèi)部迭代器的典型的集合對象為客戶端定義了一個接口,或者從底層的集合一次訪問一個元素,或者向每個元素發(fā)送消息,外部迭代器與內(nèi)部迭代器的區(qū)別總結(jié)在下表:
外部迭代器 內(nèi)部迭代器
客戶端需要知道外部迭代器才能使用,但是它為客戶端提供了更多的控制 客戶端不需要知道任何外部迭代器,而是可以通過集合對象的特殊接口,或者一次訪問一個元素,或者向集合中的每個元素發(fā)送消息
客戶端創(chuàng)建并維護(hù)外部迭代器 集合對象本身創(chuàng)建并維護(hù)它的內(nèi)部迭代器
客戶端可以使用不同的外部迭代器實現(xiàn)多種類型的遍歷 集合對象可以在不修改客戶端代碼的情況下,選擇不同的內(nèi)部迭代器

使用場景
在以下情形虾啦,會考慮使用迭代器模式:

  • 需要訪問組合對象的內(nèi)容,而又不暴露其內(nèi)部表示
  • 需要通過多種方式遍歷組合對象
  • 需要提供一個統(tǒng)一的接口,用來遍歷各種類型的組合對象

行為擴(kuò)展-Behavioral Extension

13.訪問者-Visitor

定義
在軟件設(shè)計中,如果架構(gòu)師為了擴(kuò)展類的功能而往一個類里塞進(jìn)了太多方法,類就會變得極為復(fù)雜.更好的做法是創(chuàng)建外部的類來擴(kuò)展它,而對原始代碼不做太多改動.

  • 訪問者模式涉及兩個關(guān)鍵角色(或者說組件): 訪問者和它訪問的元素. 元素可以是任何對象,但通常是"部分-整體"結(jié)構(gòu)中的節(jié)點(diǎn).
  • 部分-整體結(jié)構(gòu)包含組合體與葉節(jié)點(diǎn),或者任何其他復(fù)雜的對象結(jié)構(gòu),元素本身不僅限于這些種類的結(jié)構(gòu)
  • 訪問者知道復(fù)雜結(jié)構(gòu)中每個元素,可以訪問每個元素的節(jié)點(diǎn),并根據(jù)元素的特征,屬性或操作執(zhí)行任何操作.

類圖

顯示訪問者模式的靜態(tài)結(jié)構(gòu)的類圖

  • Visitor協(xié)議聲明了兩個很像的visit*方法,用于訪問和處理各種Element類型的對象.ConcreteVisitor(1或2)實現(xiàn)這一協(xié)議及其抽象方法.
  • Visit*的操作定義了針對特定Element類型的適當(dāng)操作. Client創(chuàng)建ConcreteVisit(1或2)的對象,并將其傳給一個Element對象結(jié)構(gòu).
  • Element對象結(jié)構(gòu)中有一個方法接受一般化的Visistor類型.
承包商例子的類圖,其中承包商是訪問者

訪問者模式的這個承包商版本,反映了從房屋承包商的例子角度的一種實現(xiàn).

  • Plumber(管道工)和Electrician(電工)是訪問者.
  • House是個復(fù)雜的結(jié)構(gòu),包含有Fixable抽象物品對象,Constructor(承包商)可對其進(jìn)行訪問并修理.
  • Plumber可以用其專有個visitPlumbing:操作,訪問House的Plumbing(管路)結(jié)構(gòu).
  • 電工可用他的visitElectrical:操作,以同樣的理由對同一個House的Electrical(電路)組件進(jìn)行訪問.
  • 普通的Contractor好像既會修Plumbing又會修Electrical,但實際上,它把這些工作轉(zhuǎn)包給能實際完成工作的人.

訪問者模式:表示一個作用于對某象結(jié)構(gòu)中的各元素的操作,它讓我們可以在不改變各元素的類的前提下定義作用于這些元素的新操作

使用場景
在以下情形,會考慮使用訪問者模式:

  • 一個復(fù)雜的對象結(jié)構(gòu)包含很多其他對象,他們有不同的接口(比如組合體),但是對這些對象實施一些依賴于其具體類型的操作.
  • 需要對一個組合結(jié)構(gòu)中的對象進(jìn)行很多不相關(guān)的操作,但是不想讓這些操作"污染"這些對象的類,可以將相關(guān)的操作集中起來,定義在一個訪問者類中
  • 定義復(fù)雜結(jié)構(gòu)的類很少修改,但經(jīng)常需要向其添加新的操作.

14.裝飾-Decorator

定義

在面向?qū)ο筌浖O(shè)計中,向?qū)ο筇砑?東西"(行為),而不破壞其原有風(fēng)格,因此增強(qiáng)了的對象是同一類的加強(qiáng)版(如帶相框的照片).任何"增強(qiáng)"(相框)均可以動態(tài)添加和刪除,我們把這種設(shè)計模式叫做"裝飾",裝飾對象可以附加到另一個裝飾對象,也可以附加到原始對象,對其功能進(jìn)行擴(kuò)展,同時保留原始行為不受影響.

類圖

裝飾模式類圖
  • 標(biāo)準(zhǔn)的裝飾模式包括一個抽象Component父類,它為其他具體組件(component)聲明了些操作.
  • 抽象的Component類可被細(xì)化為另一個叫做Decorator的抽象類.
  • Decorator包含了另一個Component的引用.ConcreteDecorator為其他Component或Decorator定義了幾個擴(kuò)展行為,并且在自己的操作中執(zhí)行內(nèi)嵌的Component操作.
由裝飾器擴(kuò)展的功能
  • 默認(rèn)的operation方法只是向內(nèi)嵌的component發(fā)送一個消息.
  • ConcreteDecoratorA和ConcreteDecoratorB重載父類的operation,通過super把自己增加的行為擴(kuò)展給component的operation.
  • 如果只需要向component添加一種職責(zé),那么就可以省掉抽象的Decorator類,讓ConcreteDecorator直接把請求轉(zhuǎn)發(fā)給component.
  • 如果有以此方式連接的對象,那么就好像形成了一種操作鏈,把一種行為添加到另一個種之上

使用場景
在以下情形痕寓,會考慮使用裝飾模式:

  • 想要在不影響其他對象的情況下,以動態(tài),透明的方式給單個對象添加職責(zé)
  • 想要擴(kuò)展一個類的行為,卻做不到.類定義可能被隱藏,無法進(jìn)行子類化; 或者,對類的每個行為的擴(kuò)展,為支持每種功能組合,將產(chǎn)生大量的子類
  • 對類的職責(zé)的擴(kuò)展是可選的.

裝飾模式: 動態(tài)地給一個對象添加一些額外的職責(zé). 就擴(kuò)展功能來說,裝飾模式相比生成子類更為靈活.

改變對象的"外表"和"內(nèi)容"

15.責(zé)任鏈-Chain of Responsibility

定義

  • 責(zé)任鏈模式的主要思想是,對象引用了同一類型的另一個對象,形成一條鏈.鏈中的每個對象實現(xiàn)了同樣的方法,處理對鏈中第一個對象發(fā)起的同一個請求.
  • 如果一個對象不知道如何處理請求,它就把請求傳給下一個響應(yīng)器(即successor)
責(zé)任鏈模式的類圖
  • Handler是上層抽象類,定義了一個方法----HandleRequest,處理它知道如何處理的請求對象.
  • ConcreteHandler1和ConcreteHandler2實現(xiàn)了handleRequest方法,來處理他們認(rèn)識的請求對象. Handler也有一個指向另一個同類型實例的引用,即successor. 當(dāng)調(diào)用Handler實例的handleRequest消息時,如果這個實例不知道如何處理請求,它會用同樣的消息把請求轉(zhuǎn)給successor.
  • 如果successor可以處理,就行了,否則,它就把請求傳給下一個successor(如果有的話)
  • 這個過程會一直進(jìn)行下去,直到請求被傳到鏈中的最后一個Handler.
運(yùn)行時的請求處理程序鏈的一種典型結(jié)構(gòu)
  • aClient有一個對Handler實例的引用,叫aHandler. aHandler是處理程序鏈的第一個對象,即aConcreteHandler,
  • aConcreteHandler用它內(nèi)部的successor引用跟另一個Handler實例連接起來.
  • 用這種策略處理請求的最低要求是,如果不懂如何處理請求,就傳給下個處理程序

使用場景
在以下情形傲醉,會考慮使用責(zé)任鏈模式:

  • 有多個對象可以處理請求,而處理程序只有在運(yùn)行時才能確定
  • 向一組對象發(fā)出請求,而不想顯式指定處理請求的特定程序

責(zé)任鏈模式: 使多個對象都有機(jī)會處理請求,從而避免請求的發(fā)送者和接收者之間發(fā)生耦合. 此模式將這些對象連成一條鏈,并沿著這條鏈傳遞請求,直到有一個對象處理它為止

算法封裝-Algorithm Encapsulation

16.模板方法-Template Method

定義
模板方法模式是面向?qū)ο筌浖O(shè)計中一種非常簡單的設(shè)計模式.其基本思想是在抽象類的一個方法中定義"標(biāo)準(zhǔn)"算法.在這個方法中調(diào)用的基本操作應(yīng)由子類重載予以實現(xiàn).這個方法被稱為"模板",因為方法定義了的算法缺少一些特有的操作.

模板方法模式: 定義一個操作中算法的骨架,而將一些步驟延遲到子類中.模板方法使子類可以重定義算法的某些特定步驟而不改變該算法的結(jié)構(gòu).

類圖

模板方法模式的類圖

因為方法定義的算法缺少一些特有的操作.上圖顯示了抽象類與具體子類之間的關(guān)系----抽象類定義模板,子類重載基本操作以提供獨(dú)特操作模板方法調(diào)用.

  • AbstractClass不完整地定義了一些方法與算法,留出一些操作未定義.
  • AbstractClass調(diào)用的templateMethod時,方法中為定義的空白部分,由ConcreteClass重載primitiveOperation1/2來填補(bǔ)

使用場景
在以下情形,會考慮使用模板方法:

  • 需要一次性實現(xiàn)算法的不變部分,并將可變的行為留給子類來實現(xiàn).
  • 子類的共同行為應(yīng)該提取出來方法放到公共類中,以避免代碼重復(fù).現(xiàn)有代碼的差別應(yīng)該被分離為新的操作,然后用一個調(diào)用這些新操作的模板方法來替換這些代碼
  • 需要控制子類的擴(kuò)展.可以定義一個在特定點(diǎn)調(diào)用"鉤子(hook)"操作的模板方法.子類可以通過對鉤子操作的實現(xiàn)在這些擴(kuò)展功能.

鉤子操作給出了默認(rèn)行為,子類可對其擴(kuò)展. 默認(rèn)行為通常什么都不做.子類可以重載這個方法,為模板算法提供附加的操作.
模板方法模式中的控制結(jié)構(gòu)流程是倒轉(zhuǎn)的,因為父類的模板方法調(diào)用其子類的操作,而不是子類調(diào)用父類的操作.

模板方法會調(diào)用5種類型的操作:

  • 對具體類或客戶端類的具體操作
  • 對對象類的具體操作.
  • 抽象操作
  • 工廠方法
  • 鉤子操作

17.策略-Strategy

定義

  • 面向?qū)ο筌浖O(shè)計中,我們可以把相關(guān)算法分離為不同的類,成為策略.與這種做法有關(guān)的一種設(shè)計模式稱為策略模式.
  • 策略模式中的一個關(guān)鍵角色就是策略類,它為所有支持的或相關(guān)的算法聲明了一個共同接口.另外還有使用策略接口來實現(xiàn)相關(guān)算法的具體策略類.
  • 場景(context)類對象配置有一個具體策略對象實例,場景對象使用策略接口調(diào)用由具體策略類定義的算法

策略模式: 定義一系列算法,把它們一個個封裝起來,并且使它們可相互替換.該模式使得算法可以獨(dú)立與使用它的客戶端而變化.

類圖

策略模式的結(jié)構(gòu)類圖

  • 一組算法,或者說算法的一個層次結(jié)構(gòu),以ConcreteStrategy(A,B,C)類的形式,共享相同的algorithmInterface接口,這樣Context就能使用相同的接口訪問算法的各種變體.
  • Context的實例可以在運(yùn)行時用不同的ConcreteStrategy對象進(jìn)行配置.這樣可以理解成更換Context對象的"內(nèi)容",因為變更是發(fā)生在對象的內(nèi)部.
  • 裝飾器改變對象的"外表",因為修改是從外面疊加起來.兩者的區(qū)別的詳細(xì)對比可以參考上面的裝飾器模式中的討論
模型-視圖-控制器中的策略模式
模型-視圖-控制器模式中,控制器決定視圖對模型數(shù)據(jù)進(jìn)行顯示的時機(jī)和內(nèi)容. 視圖本身知道如何繪圖,但需要控制器告訴它要顯示的內(nèi)容. 同一個視圖如果與不同的控制合作,數(shù)據(jù)的輸出格式可能一樣,但數(shù)據(jù) 的類型和格式可能隨不同控制器的不同輸出而不同.因此這種情況下的控制器是視圖的策略.在前面的幾節(jié)提到過,控制器與視圖之間是一種基于策略模式的關(guān)系.

使用場景
在以下情形呻率,會考慮使用策略模式:

  • 一個類在其操作中使用多個條件語句來定義許多行為.我們可以相關(guān)的條件分支移到他們自己的策略類中
  • 需要算法的各種變體
  • 需要避免把復(fù)雜的,與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)暴露給客戶端

18.命令-Command

定義

  • 在面向?qū)ο笤O(shè)計中,我們把指令封裝在各種命令對象中.命令對象可以被傳遞并且在制定時刻被不同的客戶端復(fù)用.從這一概念精心設(shè)計而來的設(shè)計模式叫做命令模式
  • 命令對象封裝了如何對目標(biāo)執(zhí)行指令的信息,因此客戶端或調(diào)用者不必了解目標(biāo)的任何細(xì)節(jié),卻仍可以對它執(zhí)行任何已有的操作.
  • 通過把請求封裝成對象,客戶端可以把參數(shù)化并置入隊列或日志中,也能夠支持可撤銷的操作.
  • 命令對象將一個或多個動作綁定到特定的接收器.命令模式消除了作為對象的動作和執(zhí)行它的接收器之間的綁定.

命令模式: 將請求封裝為一個對象,從而可用不同的請求對客戶進(jìn)行參數(shù)化,對請求排對或記錄請求日志,以及支持可撤銷的操作

類圖

展示命令模式結(jié)構(gòu)的類圖

  • Client(客戶端) 創(chuàng)建ConcreteCommand對象并設(shè)定其receiver(接收器)
  • Invoker要求通用命令(實際上是ConcreteCommand)實施請求
  • Command是為Invoker所知的通用接口(協(xié)議)
  • ConcreteCommand起Receiver和對它的操作action之間的中間人的作用
  • Receiver可以是隨著由Command(ConcreteCommand)對象實施的相應(yīng)請求,而執(zhí)行實際操作的任何對象.

使用場景
在以下情形硬毕,會考慮使用命令模式:

  • 想讓應(yīng)用程序支持撤銷和恢復(fù)
  • 想用對象參數(shù)化一個動作以執(zhí)行操作,并用不同命令對象來代替回調(diào)函數(shù)
  • 想要在不同時刻對請求進(jìn)行指定,排列和執(zhí)行.
  • 想要記錄修改日志,這樣在系統(tǒng)故障時,這些修改可在后來重做一遍.
  • 想讓系統(tǒng)支持事務(wù)(transaction),事務(wù)封裝了對數(shù)據(jù)的一系列修改.事務(wù)可以建模為命令對象

性能與對象訪問-Performance and Object Access

19.享元-Flyweight

定義
在面向?qū)ο筌浖O(shè)計中,利用公共對象不僅能節(jié)省資源還能提高性能. 比方說,某個任務(wù)需要一個類的一百萬個實例,但我們可以把這個類的一個實例讓大家共享,而把某些獨(dú)特的信息放在外部,節(jié)省的資源可能相當(dāng)可觀(一個實例與一百萬個實例的差別).共享的對象只提供某些內(nèi)在的信息,而不能用來識別對象.專門用于設(shè)計可共享對象的一種設(shè)計模式叫做享元模式(Flyweight pattern)

  • 實現(xiàn)享元模式需要兩個關(guān)鍵組件,通常是可共享的享元對象和保存它們的池.某種中央對象維護(hù)這個池,并從它返回適當(dāng)?shù)膶嵗?/li>
  • 通過享元模式能夠節(jié)省的空間總量,某些對象的獨(dú)特狀態(tài)(外在狀態(tài))可以拿到外部,在別處管理,其余部分被共享.

享元模式: 運(yùn)用共享技術(shù)有效地支持大量細(xì)粒度的對象

類圖

享元模式類圖

  • Flyweight是兩個具體享元類ConcreteFlyweight和ConcreteFlyweight2的父接口(協(xié)議)
  • 每個ConcreteFlyweight類維護(hù)不能用于識別對象的內(nèi)在狀態(tài)intrinsicState.
  • Flyweight聲明了operation:extrinsicState方法,由這兩個ConcreteFlyweight類實現(xiàn).
  • intrinsicState是享元對象中可被共享的部分,而extrinsicState補(bǔ)充缺少的信息,讓享元中的獨(dú)一無二的信息完成任務(wù)
運(yùn)行時享元對象如何共享的對象圖

使用場景
在以下情形,會考慮使用享元模式:

  • 應(yīng)用程序使用很多對象
  • 在內(nèi)存中保存對象會影響內(nèi)存性能
  • 對象的多數(shù)特有狀態(tài)(外在狀態(tài))可以放到外部而輕量化
  • 移除了外在狀態(tài)之后,可以用較少的共享對象來代替原來的那組對象
  • 應(yīng)用程序不依賴于對象標(biāo)識,因為共享對象不能提供唯一的標(biāo)識

20.代理-Proxy

定義
有以下幾種代理:

  • 遠(yuǎn)程代理(remote proxy)為位于不同地址空間或網(wǎng)絡(luò)上的對象提供本地代表
  • 虛擬代理(virtual proxy)根據(jù)需要創(chuàng)建重型對象
  • 保護(hù)代理(protection proxy)根據(jù)各種訪問權(quán)限控制對原對象的訪問
  • 智能引用代理(smart-reference proxy)通過對真正對象的引用進(jìn)行計數(shù)來管理內(nèi)存. 也用于鎖定真正對象,讓其他對象不能對其進(jìn)行修改

代理模式:為其他對象提供一種代理以控制對這個對象的訪問,通常,代理是一種替代或者占位,它控制對另一些對象的訪問,而這些對象可能是遠(yuǎn)程對象,創(chuàng)建開銷較大的對象,或者是對安全性要求高的對象

類圖

代理模式類圖

  • 當(dāng)client向Proxy對象發(fā)送request消息是,Proxy對象會把這個消息轉(zhuǎn)發(fā)給Proxy對象之中的RequestSubject對象.RealSubjec會實施實際的操作間接的滿足客戶端的需求.
  • 在運(yùn)行時,我們可以想象這樣一個場景:客戶端以抽象類型引用一個對象.這個引用實際上是個Proxy對象.Proxy對象本身有一個對RealSubject實例的引用,以后如果接到請求,此實例將執(zhí)行高強(qiáng)度的工作.場景如下圖:
代理模式在運(yùn)行可能的一種對象結(jié)構(gòu)

使用場景
在以下情形礼仗,會考慮使用代理模式:

  • 需要一個遠(yuǎn)程代理,為位于不同地址空間或者網(wǎng)絡(luò)中的對象提供本地代表
  • 需要一個虛擬代理,來根據(jù)要求創(chuàng)建重型對象.
  • 需要一個保護(hù)代理,來根據(jù)不同訪問權(quán)限控制對原對象的訪問
  • 需要一個只能引用代理,通過對實體對象的引用進(jìn)行計數(shù)來管理內(nèi)存. 也能用于鎖定實體對象,讓其他對象不能修改它.

對象狀態(tài)-State of Object

21.備忘錄-Memento

定義
在響應(yīng)某些事件時, 應(yīng)用程序需要保存自身的狀態(tài),比如當(dāng)用戶保存文檔或程序退出時.例如,游戲退出之前,可能需要保存當(dāng)前會話的狀態(tài),如游戲等級,敵人數(shù)量,可用武器的種類等.游戲再次打開時,玩家可用從離開的地方接著玩.很多時候,保存程序的狀態(tài)真的不需要什么特別奇妙的方法.任何簡單有效的方法都可以,但是同時,保存信息應(yīng)該只對原始程序有意義.原始程序應(yīng)該是能夠解碼它所保存文檔中的信息的唯一實體.這就是備忘錄模式應(yīng)用于游戲/文字處理等程序的軟件設(shè)計中的方式,這些程序需要保存當(dāng)前上下文的復(fù)雜狀態(tài)的快照并在以后恢復(fù).

備忘錄模式: 在不破壞封裝的前提下,捕獲一個對象內(nèi)部狀態(tài),并在該對象之外保存這個狀態(tài),這樣以后就可將該對象恢復(fù)到原先保存的狀態(tài)

類圖

備忘錄模式結(jié)構(gòu)類圖

這個模式中有三個關(guān)鍵角色:原發(fā)器(originator)/備忘錄(memento)和看管人(caretaker).其思想非常簡單,原發(fā)器創(chuàng)建一個包含其狀態(tài)的備忘錄,并傳給看管人.看管人不知如何與備忘錄交互,但會把備忘錄放在安全之處保管好

備忘錄模式的時序圖
  • 當(dāng)看管人請求Originator對象保存其狀態(tài)時,Originator對象將使用其內(nèi)部狀態(tài)創(chuàng)建一個新的Memento實例.然后看管人保管Memento對象,或者把它保存到文件系統(tǒng),一段時間后再把它傳回給Originator對象
  • Originator對象不知道這個Memento對象將如何被保管.看管人也不知道Memento對象里是啥
  • 這樣設(shè)計的關(guān)鍵是維護(hù)Memento對象的私有性,只讓Originator對象訪問保存在Memento對象中的內(nèi)部狀態(tài)(即Originator過去的內(nèi)部狀態(tài)).
  • Memento類應(yīng)該有兩個接口:一個寬接口,給Originator用,一個窄接口,給其他對象用,所以前面的圖中,setState:,state,init這些方法應(yīng)該定義為私有的,不讓Originator和Memento以外的對象使用

使用場景
在以下情形吐咳,會考慮使用備忘錄模式:

  • 需要保存一個對象(或某部分)在某一時刻的狀態(tài),這樣以后就可以回到先前的狀態(tài)
  • 用于獲取狀態(tài)的接口會暴露實現(xiàn)的細(xì)節(jié),需要將其隱藏起來.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逻悠,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子韭脊,更是在濱河造成了極大的恐慌童谒,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沪羔,死亡現(xiàn)場離奇詭異饥伊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)蔫饰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門琅豆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人篓吁,你說我怎么就攤上這事茫因。” “怎么了越除?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵节腐,是天一觀的道長。 經(jīng)常有香客問我摘盆,道長翼雀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任孩擂,我火速辦了婚禮狼渊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘类垦。我一直安慰自己狈邑,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布蚤认。 她就那樣靜靜地躺著米苹,像睡著了一般。 火紅的嫁衣襯著肌膚如雪砰琢。 梳的紋絲不亂的頭發(fā)上蘸嘶,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機(jī)與錄音陪汽,去河邊找鬼训唱。 笑死,一個胖子當(dāng)著我的面吹牛挚冤,可吹牛的內(nèi)容都是我干的况增。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼训挡,長吁一口氣:“原來是場噩夢啊……” “哼澳骤!你這毒婦竟也來了歧强?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤宴凉,失蹤者是張志新(化名)和其女友劉穎誊锭,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弥锄,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丧靡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了籽暇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片温治。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖戒悠,靈堂內(nèi)的尸體忽然破棺而出熬荆,到底是詐尸還是另有隱情,我是刑警寧澤绸狐,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布卤恳,位于F島的核電站,受9級特大地震影響寒矿,放射性物質(zhì)發(fā)生泄漏突琳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一符相、第九天 我趴在偏房一處隱蔽的房頂上張望拆融。 院中可真熱鬧,春花似錦啊终、人聲如沸镜豹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趟脂。三九已至,卻和暖如春例衍,著一層夾襖步出監(jiān)牢的瞬間昔期,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工肄渗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人咬最。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓翎嫡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親永乌。 傳聞我的和親對象是個殘疾皇子惑申,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

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