設(shè)計(jì)模式之創(chuàng)建型模式

引言

GoF的《設(shè)計(jì)模式》一書總結(jié)了面向?qū)ο筌浖幸恍氋F的設(shè)計(jì)經(jīng)驗(yàn)乱凿,系統(tǒng)地對(duì)它們命名徒蟆、解釋和評(píng)價(jià)段审,并以編目分類的形式將它們展現(xiàn)出來,這就是廣為流傳的23個(gè)設(shè)計(jì)模式的由來型凳。

模式是一項(xiàng)管理復(fù)雜度的技術(shù)甘畅,幾乎所有模式都遵循兩個(gè)原則:

  • 針對(duì)接口編程蓄氧,而不是實(shí)現(xiàn)喉童。
  • 多用組合堂氯,少用繼承。

很多模式看上去很類似晶框,這是因?yàn)閷?shí)現(xiàn)各種模式的方式一般就是繼承和組合。對(duì)外暴露一個(gè)通用接口畴蒲,既易于使用又隱藏實(shí)現(xiàn)細(xì)節(jié),內(nèi)部用各種子類來實(shí)現(xiàn)不同功能蔫骂,支持?jǐn)U展變化辽旋,并盡量用對(duì)象組合來實(shí)現(xiàn)解耦。所以你可以認(rèn)為23個(gè)模式就是根據(jù)不同的使用場景變著法兒地聲明接口然后繼承實(shí)現(xiàn)最后再花式組合罷了溶其。

模式依據(jù)其設(shè)計(jì)目的可以分為三大類——?jiǎng)?chuàng)建型(Creational)束铭、結(jié)構(gòu)型(Structural)和行為型(Behavioral)。本文主要論述幾個(gè)創(chuàng)建型模式之間的區(qū)別與聯(lián)系懈万。

《設(shè)計(jì)模式》一書的副標(biāo)題是“可復(fù)用面向?qū)ο筌浖幕A(chǔ)”嫡秕,所以顯然這23個(gè)設(shè)計(jì)模式是用于面向?qū)ο筌浖O(shè)計(jì)的昆咽,而眾所周知窟哺,最適合面向?qū)ο筮@種范式的領(lǐng)域其實(shí)是 GUI 編程領(lǐng)域(這也是《設(shè)計(jì)模式》中大部分應(yīng)用實(shí)例都是一些 GUI 框架的原因)浮声,所以本文也主要以 iOS 開發(fā)為例進(jìn)行說明。示例語言選用靜態(tài)語言 Swift(其實(shí)個(gè)人認(rèn)為設(shè)計(jì)模式主要還是針對(duì)靜態(tài)語言屉符,很多模式在動(dòng)態(tài)語言中都用處不大)。

創(chuàng)建型模式簡介

創(chuàng)建型模式將實(shí)例化對(duì)象的部分從系統(tǒng)中獨(dú)立出來,它們將系統(tǒng)具體使用哪些類的信息封裝起來虑凛,并隱藏了這些類是如何被創(chuàng)建和組合的,對(duì)外只提供一個(gè)通用接口。

創(chuàng)建型模式有五種——Abstract Factory(抽象工廠)、Builder(生成器)胧辽、Factory Method(工廠方法)凡蚜、Prototype(原型)、Singleton(單例)。我個(gè)人認(rèn)為抽象工廠模式和生成者模式的抽象層級(jí)最高,因?yàn)樗鼈兌伎梢苑謩e用工廠方法和原型實(shí)現(xiàn)。而工廠方法和原型是同一個(gè)層級(jí)的,它們?cè)诖蠖鄶?shù)時(shí)候是互斥的驱还,一般不能結(jié)合使用闷沥。至于單例,就是保證某個(gè)類只實(shí)例化一次而已,想用在哪兒都行(只要符合實(shí)際需求)展蒂。

抽象工廠側(cè)重于創(chuàng)建一系列同一風(fēng)格的產(chǎn)品团赏,每個(gè)產(chǎn)品都有一個(gè)抽象接口杯聚,使用者并不知道它使用的是具體哪種風(fēng)格的產(chǎn)品抒痒。而生成器側(cè)重于一步步構(gòu)建一個(gè)復(fù)雜產(chǎn)品幌绍,這個(gè)復(fù)雜產(chǎn)品不需要有一個(gè)公共接口,使用者知道它具體得到了一個(gè)什么產(chǎn)品故响。

抽象方法定義一個(gè)用于創(chuàng)建對(duì)象的接口傀广,子類重寫創(chuàng)建方法,被創(chuàng)建的產(chǎn)品會(huì)有一個(gè)抽象接口彩届,所以使用者并不知道具體得到的是什么產(chǎn)品伪冰。原型將某個(gè)實(shí)例對(duì)象作為“原型”,通過復(fù)制這個(gè)原型來創(chuàng)建新的對(duì)象樟蠕,由于可以動(dòng)態(tài)指定原型贮聂,所以可以在運(yùn)行期改變創(chuàng)建的產(chǎn)品靠柑。

一個(gè)簡單案例

假設(shè)我們現(xiàn)在要構(gòu)建兩個(gè)界面,界面的構(gòu)成元素都是一個(gè) Label 和 Button吓懈。一個(gè)界面在打開應(yīng)用的時(shí)候顯示病往,Label 和 Button 會(huì)顯示“Hello……”,另一個(gè)在應(yīng)用關(guān)閉前顯示骄瓣,Label 和 Button 會(huì)顯示“Goodbye……”停巷。而且不止是顯示的文字,連同背景色榕栏、位置畔勤、大小等等屬性都會(huì)不同。于是我們考慮自定義幾個(gè) Label 和 Button:

//MARK: - Hello 系列產(chǎn)品
class HelloButton: UIButton {
    init() {
        let frame = CGRect(x: 50, y: 200, width: 300, height: 50)
        super.init(frame: frame)
        backgroundColor = UIColor.greenColor()
        setTitle("Hello, I am a button.", forState: .Normal)
        setTitleColor(UIColor.redColor(), forState: .Normal)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

class HelloLabel: UILabel {
    init() {
        let frame = CGRect(x: 50, y: 300, width: 300, height: 50)
        super.init(frame: frame)
        backgroundColor = UIColor.yellowColor()
        text = "Hello, I am a label."
        textAlignment = .Center
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}


//MARK: - Goodbye 系列產(chǎn)品
class GoodbyeButton: UIButton {
    init() {
        let frame = CGRect(x: 50, y: 400, width: 300, height: 20)
        super.init(frame: frame)
        backgroundColor = UIColor.redColor()
        setTitle("Goodbye, don't forget I'm a button.", forState: .Normal)
        setTitleColor(UIColor.greenColor(), forState: .Normal)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}

class GoodbyeLabel: UILabel {
    init() {
        let frame = CGRect(x: 100, y: 500, width: 200, height: 100)
        super.init(frame: frame)
        backgroundColor = UIColor.blackColor()
        text = "Goodbye, don't forget I'm a label."
        textColor = UIColor.whiteColor()
        font = UIFont.systemFontOfSize(10)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

然后我們定義一個(gè)用來組合界面視圖的類:

class PageView: UIView {
    init() {
        super.init(frame: UIScreen.mainScreen().bounds)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

稍后我會(huì)介紹用不同的模式來創(chuàng)建產(chǎn)品扒磁。

Factory Method(工廠方法)

現(xiàn)在我們給 PageView 加上用來創(chuàng)建 Label 和 Button 的工廠方法庆揪,并在構(gòu)造器中調(diào)用工廠方法。工廠方法可以是抽象方法也可以有一個(gè)默認(rèn)實(shí)現(xiàn)妨托,這里我給出一個(gè)默認(rèn)實(shí)現(xiàn):

class PageView: UIView {
    init() {
        super.init(frame: UIScreen.mainScreen().bounds)
        
        let label = createLabel()
        let button = createButton()
        
        addSubview(label)
        addSubview(button)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func createLabel() -> UILabel {
        return UILabel()
    }
    
    func createButton() -> UIButton {
        return UIButton()
    }
}

這樣我們要?jiǎng)?chuàng)建 HelloPageView 和 GoodbyepageView 的時(shí)候只要重寫工廠方法就好了:

class HelloPageView: PageView {
    override func createLabel() -> UILabel {
        return HelloLabel()
    }
    override func createButton() -> UIButton {
        return HelloButton()
    }
}

class GoodbyePageView: PageView {
    override func createLabel() -> UILabel {
        return GoodbyeLabel()
    }
    override func createButton() -> UIButton {
        return GoodbyeButton()
    }
}

常規(guī)的工廠方法有個(gè)顯而易見的缺點(diǎn)就是當(dāng)需要進(jìn)行不同產(chǎn)品的組合的時(shí)候缸榛,容易導(dǎo)致類爆炸。譬如現(xiàn)在我們只是需要“HelloLabel + HelloButton”和“GoodByeLabel + GoodbyeButton”兰伤,但如果我們還需要“ HelloLabel + GoodbyeButton”和“ GoodByeLabel + HelloButton”這樣的組合内颗,那就又得新建兩個(gè) PageView 的子類。

解決這個(gè)問題的方法是可以使用參數(shù)化的工廠方法敦腔,可以給工廠方法傳遞一個(gè)參數(shù)(標(biāo)識(shí)符)均澳,然后根據(jù)標(biāo)識(shí)符來實(shí)例化特定的產(chǎn)品,這樣我們就不需要各種 PageView 子類了符衔。但是一旦擴(kuò)充了新產(chǎn)品(增加了新的XXXLabel或者XXXButton)找前,就得去修改相應(yīng)的工廠方法以支持新產(chǎn)品。這時(shí)候如果是支持范型的語言判族,就可以使用范型參數(shù)來解決這個(gè)問題(前提是工廠方法中沒有針對(duì)某個(gè)特定子類產(chǎn)品的操作)躺盛,我們把 PageView 改成一個(gè)范型類:

class PageView<L: UILabel, B: UIButton>: UIView {
    init() {
        super.init(frame: UIScreen.mainScreen().bounds)
        
        let label = createLabel()
        let button = createButton()
        
        addSubview(label)
        addSubview(button)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func createLabel() -> L {
        return L()
    }
    
    func createButton() -> B {
        return B()
    }
}

這樣就可以在 Controller 中指定要返回那種類型的 PageView,可以任意組合 Label 和Button:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let pageView = PageView<HelloLabel, HelloButton>()
        view.addSubview(pageView)
    }
}

效果如下:

HelloPage.png

若要使用 GoodPage形帮,只需要把PageView<HelloLabel, HelloButton>()換成PageView<GoodbyeLabel, GoodbyeButton>()槽惫,運(yùn)行效果就變成:

GoodbyePage.png

Prototype(原型)

原型模式顧名思義就是將某個(gè)實(shí)例對(duì)象當(dāng)做原型,通過復(fù)制它來創(chuàng)建其他同類型的對(duì)象沃缘。要使用原型模式需要給產(chǎn)品類設(shè)置一個(gè)用來克隆自身實(shí)例的函數(shù)躯枢,雖然很多語言或者標(biāo)準(zhǔn)庫都有 copy 函數(shù),對(duì)克隆對(duì)象提供了一些原生支持槐臀,但你還得考慮深拷貝和淺拷貝的問題锄蹂,前者同時(shí)拷貝對(duì)象內(nèi)部的狀態(tài),后者則通過指針共享狀態(tài)水慨。

像 Self得糜、JavaScript 這樣基于原型的語言可以說處處都用到了原型模式敬扛,而像SmallTalk、OC朝抖、Ruby 等動(dòng)態(tài)語言中啥箭,類本身可以當(dāng)作對(duì)象傳遞并用其創(chuàng)建實(shí)例對(duì)象,甚至在 Swift 中也可以直接用所謂的元類型(SomeClass.Type)來初始化一個(gè)對(duì)象治宣,所以我覺得這個(gè)原型模式在很多時(shí)候并不實(shí)用急侥。它最大的優(yōu)點(diǎn)是靈活性,可以動(dòng)態(tài)指定要?jiǎng)?chuàng)建的對(duì)象侮邀,而這點(diǎn)坏怪,可以通過傳遞“元類型”或者利用范型輕易做到。

Abstract Factory(抽象工廠)

抽象工廠通常是利用工廠方法來實(shí)現(xiàn)的绊茧,也可以利用范型或者原型铝宵。它的核心思路就是單獨(dú)抽象出一個(gè)工廠類,通過對(duì)象組合华畏,系統(tǒng)委托這個(gè)工廠類來創(chuàng)建一系列產(chǎn)品鹏秋。沒錯(cuò),這個(gè)模式的重點(diǎn)就在于強(qiáng)調(diào)了“一系列”這三個(gè)字亡笑。如果你的最終目的是要把這一系列產(chǎn)品組合成一個(gè)產(chǎn)品侣夷,那就應(yīng)該用 Builder 模式。

所以我上面舉的那個(gè)實(shí)例其實(shí)用 Builder 模式比較合適况芒,當(dāng)然惜纸,我這里也可以強(qiáng)行用抽象工廠做一下,只要把最后組裝產(chǎn)品那一步留到外部好了绝骚。

//MARK: - 抽象工廠
protocol UIFactory {
    func createLabel() -> UILabel
    func createButton() -> UIButton
}

//MARK: - 具體工廠
class HelloUIFactory: UIFactory {
    func createLabel() -> UILabel {
        return HelloLabel()
    }
    
    func createButton() -> UIButton {
        return HelloButton()
    }
}

class GoodbyeUIFactory: UIFactory {
    func createLabel() -> UILabel {
        return GoodbyeLabel()
    }
    
    func createButton() -> UIButton {
        return GoodbyeButton()
    }
}

然后修改 PageView,構(gòu)造器以一個(gè) UIFactory 對(duì)象為參數(shù):

class pageView: UIView {
    init(factory: UIFactory) {
        super.init(frame: UIScreen.mainScreen().bounds)
        
        let label = factory.createLabel()
        let button = factory.createButton()
        
        addSubview(label)
        addSubview(button)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

如果要生成一個(gè) HelloPaveView 并顯示祠够,只需要在 Controller 的 ViewDidLoad 方法中這樣寫就好了:

let pageView = PageView(factory: HelloUIFactory())
view.addSubview(pageView)

當(dāng)然跟工廠方法一樣压汪,為了避免類繼承層次過深,也可以使用范型版本的工廠古瓤,只不過這樣在使用的時(shí)候就需要明確指出需要?jiǎng)?chuàng)建的產(chǎn)品類型了:

//用范型控制產(chǎn)品類型止剖,不需要定義一堆 UIFactory 子類。
class GenericUIFactory<L: UILabel, B: UIButton>: UIFactory { 
    func createLabel() -> UILabel {
        return L()
    }
    
    func createButton() -> UIButton {
        return B()
    }
}

使用:

let pageView = PageView(factory: GenericUIFactory<HelloLabel, HelloButton>())

Builder(生成器)

生成器模式同樣需要用到對(duì)象組合落君,director 對(duì)象委托 builder 對(duì)象一步步構(gòu)建出一個(gè)復(fù)雜對(duì)象穿香。先定義一個(gè) Director 類:

class Director {
    func createPageViewWithBuilder(builder: Builder) {
        builder.createButton()
        builder.createLabel()
    }
}

Builder 定義如下:

protocol Builder {
    func createLabel()
    func createButton()
}

注意這個(gè) Builder 的協(xié)議并沒有聲明返回產(chǎn)品的方法,因?yàn)橛?Builder 構(gòu)造出來的產(chǎn)品往往差別很大绎速,并沒有一個(gè)統(tǒng)一的接口皮获,所以只需要在子類中聲明一個(gè)返回特定產(chǎn)品的方法即可(當(dāng)然本例中其實(shí)最終構(gòu)造的產(chǎn)品都是UIView,是可以提供一個(gè)統(tǒng)一接口的)纹冤。下面是 Builder 子類實(shí)現(xiàn):


class HelloPageBuilder: Builder {
    var helloPageView: UIView
    
    init() {
        helloPageView = UIView()
    }
    
    func createLabel() {
        helloPageView.addSubview(HelloLabel())
    }
    
    func createButton() {
        helloPageView.addSubview(HelloButton())
    }
    
    func getHelloPageView() -> UIView {
        return helloPageView
    }
}

class GoodbyePageBuilder: Builder {
    var goodbyePageView: UIView
    
    init() {
        goodbyePageView = UIView()
    }
    
    func createLabel() {
        goodbyePageView.addSubview(GoodbyeLabel())
    }
    
    func createButton() {
        goodbyePageView.addSubview(GoodbyeButton())
    }
    
    func getGoodbyePageView() -> UIView {
        return goodbyePageView
    }
}

使用:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        let director = Director()
        let builder = HelloPageBuilder()
        director.createPageViewWithBuilder(builder)
        let pageView = builder.getHelloPageView()
        view.addSubview(pageView)
    }
}

上述的 Builder 也用了工廠方法來實(shí)現(xiàn)洒宝,同樣你可以根據(jù)實(shí)際情況使用范型或者原型模式來實(shí)現(xiàn)购公。

Singleton(單例)

單例實(shí)在是太簡單了,無非就是確保只實(shí)例化某個(gè)類一次雁歌。在某些語言中宏浩,使用單例時(shí)得注意線程安全。但在 Swift 中靠瞎,只要使用let聲明一個(gè)常量比庄,用它指向一個(gè)實(shí)例,它的 immutable 性質(zhì)可以保證線程安全乏盐,然后把對(duì)應(yīng)的構(gòu)造器設(shè)為 private 就可以了佳窑,像這樣:

private let instance = HelloUIFactory()
class HelloUIFactory: UIFactory {

    private init() {}
    
    class func singleInstance() -> HelloUIFactory {
        return instance
    }
    
    func createLabel() -> UILabel {
        return HelloLabel()
    }
    
    func createButton() -> UIButton {
        return HelloButton()
    }
}

有一點(diǎn)需要注意,Swift 的private關(guān)鍵字的作用域是以文件為單位的丑勤,而不是類华嘹,所以雖然把HelloUiFactory類的構(gòu)造器聲明為private了,但在本文件內(nèi)(哪怕在HelloUiFactory類外部)法竞,還是可以實(shí)例化該類耙厚。

使用單例:

let factory = HelloUIFactory.singleInstance()

一般像 factory 啊 builder 啊 prototype 啊等等其實(shí)都只要一個(gè)實(shí)例就夠了,所以你喜歡的話很多地方都可以用單例模式岔霸。

后記

創(chuàng)建型模式就介紹到這里薛躬,接下來會(huì)再寫一篇結(jié)構(gòu)型模式介紹和一篇行為型模式介紹〈粝福可能你覺得很多模式平常根本用不到型宝,沒關(guān)系,理解并就行了絮爷。等哪天你看別人的源碼的時(shí)候看著看著福至心靈:“耶趴酣?這不是XXX模式么?”坑夯,或者等你的項(xiàng)目規(guī)模大到一定程度的時(shí)候腦中靈光一閃:“這里用XXX模式似乎不錯(cuò)~”的時(shí)候岖寞,你就知道模式有什么用了。當(dāng)然柜蜈,時(shí)代在發(fā)展仗谆,很多現(xiàn)代語言或者標(biāo)準(zhǔn)庫已經(jīng)集成了一些模式,不需要自己費(fèi)力去實(shí)現(xiàn)了淑履。還有很多場景隶垮,哪怕可以使用模式也需要進(jìn)行一定的變通,不要照搬照抄秘噪、強(qiáng)行套用狸吞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捷绒,更是在濱河造成了極大的恐慌瑰排,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暖侨,死亡現(xiàn)場離奇詭異椭住,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)字逗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門京郑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人葫掉,你說我怎么就攤上這事些举。” “怎么了俭厚?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵户魏,是天一觀的道長。 經(jīng)常有香客問我挪挤,道長叼丑,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任扛门,我火速辦了婚禮鸠信,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘论寨。我一直安慰自己星立,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布葬凳。 她就那樣靜靜地躺著绰垂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪火焰。 梳的紋絲不亂的頭發(fā)上辕坝,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音荐健,去河邊找鬼。 笑死琳袄,一個(gè)胖子當(dāng)著我的面吹牛江场,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播窖逗,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼址否,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起佑附,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤樊诺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后音同,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體词爬,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年权均,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了顿膨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叽赊,死狀恐怖恋沃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情必指,我是刑警寧澤囊咏,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站塔橡,受9級(jí)特大地震影響梅割,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谱邪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一炮捧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧惦银,春花似錦咆课、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至迅栅,卻和暖如春殊校,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背读存。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來泰國打工为流, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人让簿。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓敬察,卻偏偏與公主長得像,于是被迫代替她去往敵國和親尔当。 傳聞我的和親對(duì)象是個(gè)殘疾皇子莲祸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

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