結(jié)構(gòu)模式-代理模式(The Proxy Pattern)

本文大部分內(nèi)容翻譯至《Pro Design Pattern In Swift》By Adam Freeman读恃,一些地方做了些許修改,并將代碼升級(jí)到了Swift2.0,翻譯不當(dāng)之處望多包涵灼芭。

代理模式(The Proxy Pattern)

為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問厂庇。在某些情況下区端,一個(gè)對(duì)象不適合或者不能直接引用另一個(gè)對(duì)象沈善,而代理對(duì)象可以在客戶端和目標(biāo)對(duì)象之間起到中介的作用。


示例工程

OS X Command Line Tool 工程:

main.swift

import Foundation

func getHeader(header:String) {
    let url = NSURL(string: "http://www.apress.com")
    let request = NSURLRequest(URL: url!)
    
    NSURLSession.sharedSession().dataTaskWithRequest(request,
        completionHandler: {data, response, error in
            if let httpResponse = response as? NSHTTPURLResponse {
                if let headerValue = httpResponse.allHeaderFields[header] as? NSString {
                    print("\(header): \(headerValue)")
                }
            }
    }).resume()
}

let headers = ["Content-Length", "Content-Encoding"]
for header in headers {
    getHeader(header)
}

NSFileHandle.fileHandleWithStandardInput().availableData

main.swift中對(duì)Apress的主頁進(jìn)行HTTP請(qǐng)求并打印Content-Length 和 Content-Encoding 的值炼绘,運(yùn)行程序可以看到下面輸出:

Content-Encoding: gzip
Content-Length: 27003

你也可能看見Content-Length先輸出嗅战。這是因?yàn)镕oundation框架的HTTP請(qǐng)求是異步( asynchronous)和并發(fā)的(concurrent),這意味著任何一個(gè)請(qǐng)求都可能先完成然后第一個(gè)輸出結(jié)果。


理解代理模式解決的問題

代理模式主要用來解決三個(gè)不同的問題俺亮。

理解遠(yuǎn)程對(duì)象問題

遠(yuǎn)程對(duì)象問題就是當(dāng)你需要處理網(wǎng)絡(luò)資源時(shí)驮捍,例如一個(gè)網(wǎng)頁或者網(wǎng)絡(luò)服務(wù)。main.swift中的代碼去獲取一個(gè)網(wǎng)頁脚曾,但是它并沒有將提供的機(jī)制分離出來东且。在代碼中沒有抽象和封裝,這導(dǎo)致了如果我們修改實(shí)現(xiàn)的話會(huì)影響到其它的代碼本讥。

理解昂貴花銷問題

像HTTP請(qǐng)求那樣的需要昂貴開銷的任務(wù)珊泳。例如需要大量計(jì)算,大量?jī)?nèi)存消耗拷沸,需要消耗設(shè)備電量(GPS),帶寬要求色查,運(yùn)行時(shí)間等。

對(duì)于HTTP請(qǐng)求來說撞芍,主要的代價(jià)是運(yùn)行時(shí)間和帶寬秧了,和服務(wù)器生成并返回response。main.swift中并沒有對(duì)HTTP請(qǐng)求做任何優(yōu)化序无,也沒有考慮過用戶验毡,網(wǎng)絡(luò),或者服務(wù)器接受請(qǐng)求等帶來的沖突愉镰。

理解訪問權(quán)限問題

限制訪問一個(gè)對(duì)象通常存在于多用戶的應(yīng)用中米罚。你不能改變想保護(hù)對(duì)象的定義因?yàn)槟銢]有代碼權(quán)限或者對(duì)象有其它的依賴钧汹。

理解代理模式

代理模式可以用在當(dāng)一個(gè)對(duì)象需要用來代表其他的資源丈探。如下面的圖,資源可以是一些抽象拔莱,例如一個(gè)網(wǎng)頁碗降,或者其他對(duì)象。



解決遠(yuǎn)程對(duì)象問題

用代理模式來代表遠(yuǎn)程對(duì)象或是資源是從分布式系統(tǒng)開始的塘秦,例如CORBA讼渊。CORBA提供了一個(gè)暴露了和服務(wù)器對(duì)象相同方法的本地對(duì)象。本地對(duì)象是代理尊剔,并且調(diào)用了一個(gè)和遠(yuǎn)程對(duì)象相關(guān)聯(lián)的方法爪幻。CORBA十分注意代理對(duì)象和遠(yuǎn)程對(duì)象的映射并處理參數(shù)和結(jié)果。

CORBA并沒有流行起來,但是隨著HTTP成為了傳輸選擇和RESTful服務(wù)的流行挨稿,代理模式變得很重要仇轻。代理模式可以讓操作遠(yuǎn)程資源變得十分容易。



代理對(duì)象隱藏了如何訪問遠(yuǎn)程資源的細(xì)節(jié)奶甘,僅僅提供了它的數(shù)據(jù)篷店。


解決昂貴開銷問題

代理可以通過將運(yùn)算和使用去耦來減小開銷。在示例工程中臭家,我們可以將不同的HTTP頭值請(qǐng)求放在一次請(qǐng)求中疲陕。


解決訪問權(quán)限問題

代理可以被當(dāng)作一個(gè)對(duì)象的外包裝,增加一個(gè)額外的邏輯來強(qiáng)制執(zhí)行一些約束钉赁。



實(shí)現(xiàn)代理模式

實(shí)現(xiàn)代理模式根據(jù)解決的問題不同而不同蹄殃。

實(shí)現(xiàn)解決遠(yuǎn)程對(duì)象問題

實(shí)現(xiàn)用代理模式去訪問一個(gè)遠(yuǎn)程對(duì)象的關(guān)鍵是要分離出請(qǐng)求對(duì)象需要遠(yuǎn)程對(duì)象提供的特征。
1.定義協(xié)議

Proxy.swift

protocol HttpHeaderRequest {
    func getHeader(url:String, header:String) -> String?
}

2.定義代理實(shí)現(xiàn)類

Proxy.swift

import Foundation
protocol HttpHeaderRequest {
    func getHeader(url:String, header:String) -> String?
}

class HttpHeaderRequestProxy : HttpHeaderRequest {
    private let semaphore = dispatch_semaphore_create(0)
    
    func getHeader(url: String, header: String) -> String? {
        var headerValue:String?
        let nsUrl = NSURL(string: url)
        let request = NSURLRequest(URL: nsUrl!)
    
        NSURLSession.sharedSession().dataTaskWithRequest(request,
            completionHandler: {data, response, error in
                if let httpResponse = response as? NSHTTPURLResponse {
                    headerValue = httpResponse.allHeaderFields[header] as? String
                }
                dispatch_semaphore_signal(self.semaphore)
        }).resume()
    
        dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER)
        return headerValue
    }
}

HttpHeaderRequestProxy類實(shí)現(xiàn)了HttpHeaderRequest 協(xié)議橄霉。getHeader方法用了Foundation框架去發(fā)動(dòng)HTTP請(qǐng)求窃爷,同時(shí)增加了GCD信號(hào)量用來覆蓋異步請(qǐng)求的問題。

Tip:在真正的項(xiàng)目中我并不建議在同步的方法中去覆蓋異步操作姓蜂,并不僅僅是因?yàn)镾wift閉包使得操作異步任務(wù)很容易按厘。

3.使用遠(yuǎn)程對(duì)象代理

main.swift

import Foundation
let url = "http://www.apress.com"
let headers = ["Content-Length", "Content-Encoding"]
let proxy = HttpHeaderRequestProxy()

for header in headers {
    if let val = proxy.getHeader(url, header:header) {
        print("\(header): \(val)")
    }
}
NSFileHandle.fileHandleWithStandardInput().availableData

實(shí)現(xiàn)解決昂貴花銷問題

有很多種方法可以優(yōu)化昂貴花銷的操作,比較常用的如緩存钱慢,延遲加載逮京,或者如享元模式的其他設(shè)計(jì)模式。

示例工程中昂貴的操作就是HTTP請(qǐng)求束莫,減小HTTP請(qǐng)求次數(shù)會(huì)得到一個(gè)本質(zhì)的改善效果懒棉。顯然示例中的最佳優(yōu)化方法是對(duì)于想獲得多個(gè)不同的HTTP頭文件時(shí)只發(fā)起一次HTTP請(qǐng)求。

Proxy.swift

import Foundation
protocol HttpHeaderRequest {
    func getHeader(url:String, header:String) -> String?
}

class HttpHeaderRequestProxy : HttpHeaderRequest {
    private let queue = dispatch_queue_create("httpQ", DISPATCH_QUEUE_SERIAL)
    private let semaphore = dispatch_semaphore_create(0)
    private var cachedHeaders = [String:String]()
    
    func getHeader(url: String, header: String) -> String? {
        var headerValue:String?
        dispatch_sync(self.queue){[weak self] in
            if let cachedValue = self!.cachedHeaders[header] {
                headerValue = "\(cachedValue) (cached)"
            }else {
                let nsUrl = NSURL(string: url)
                let request = NSURLRequest(URL: nsUrl!)
        
                NSURLSession.sharedSession().dataTaskWithRequest(request,
                    completionHandler: {data, response, error in
                    if let httpResponse = response as? NSHTTPURLResponse {
                        let headers = httpResponse.allHeaderFields as! [String: String]
                        for (name, value) in headers {
                            self!.cachedHeaders[name] = value
                        }
                        headerValue = httpResponse.allHeaderFields[header] as? String
                    }
                    dispatch_semaphore_signal(self!.semaphore)
                }).resume()
                dispatch_semaphore_wait(self!.semaphore, DISPATCH_TIME_FOREVER)
            }
        }
        return headerValue
    }
}

getHeader方法創(chuàng)建了一個(gè)緩存字典用來滿足隨后的請(qǐng)求览绿,運(yùn)行程序我們可以得到下面的結(jié)果:

Content-Length: 26992
Content-Encoding: gzip (cached)

注意:HttpHeaderRequestProxy 類增加了一個(gè)GCD同步隊(duì)列來確保一次請(qǐng)求就更新字典的緩存數(shù)據(jù)策严。

延遲操作

另一個(gè)常用的方法就是盡可能長(zhǎng)的延遲執(zhí)行昂貴花銷的操作。這樣做的好處是昂貴的花銷可能被取消饿敲,壞處是耦合性強(qiáng)妻导。

Proxy.swift

import Foundation
protocol HttpHeaderRequest {
    init(url:String)
    func getHeader(header:String, callback:(String, String?) -> Void )
    func execute()
}

class HttpHeaderRequestProxy : HttpHeaderRequest {
    let url:String
    var headersRequired:[String: (String, String?) -> Void]
    
    required init(url: String) {
        self.url = url
        self.headersRequired = Dictionary<String, (String, String?) -> Void>()
    }
    
    func getHeader(header: String, callback: (String, String?) -> Void) {
        self.headersRequired[header] = callback;
    }

    func execute() {
        let nsUrl = NSURL(string: url)
        let request = NSURLRequest(URL: nsUrl!)
        NSURLSession.sharedSession().dataTaskWithRequest(request,
            completionHandler: {data, response, error in
            if let httpResponse = response as? NSHTTPURLResponse {
                let headers = httpResponse.allHeaderFields as! [String: String]
                for (header, callback) in self.headersRequired {
                    callback(header, headers[header])
                }
            }
        }).resume()
    }
}

如果用戶在調(diào)用execute方法之前因某種原因放棄了,那么HTTP請(qǐng)求就不會(huì)執(zhí)行怀各。

main.swift

import Foundation
let url = "http://www.apress.com"
let headers = ["Content-Length", "Content-Encoding"]
let proxy = HttpHeaderRequestProxy(url: url)

for header in headers {
    proxy.getHeader(header, callback: {header, val in
    if (val != nil) {
        print("\(header): \(val!)")
    }
    });
}
proxy.execute()

NSFileHandle.fileHandleWithStandardInput().availableData

執(zhí)行程序倔韭,得到下面結(jié)果:

Content-Encoding: gzip
Content-Length: 26992

實(shí)現(xiàn)解決訪問權(quán)限問題

創(chuàng)建授權(quán)資源

Auth.swift

class UserAuthentication {
    var user:String?
    var authenticated:Bool = false
    static let sharedInstance = UserAuthentication()
    
    private init() {
        // do nothing - stops instances being created
    }
    
    func authenticate(user:String, pass:String) {
        if (pass == "secret") {
            self.user = user
            self.authenticated = true
        } else {
            self.user = nil
            self.authenticated = false
        }
    }
}

UserAuthentication用單例模式來提供用戶認(rèn)證,事實(shí)上用戶的密碼是secret的時(shí)候認(rèn)證成功瓢对。在真實(shí)的項(xiàng)目中寿酌,認(rèn)證是很復(fù)雜的,可能會(huì)有自己的代理硕蛹。

創(chuàng)建代理對(duì)象

接下來就是創(chuàng)建代理對(duì)象:

Proxy.swift

import Foundation
protocol HttpHeaderRequest {
    init(url:String)
    func getHeader(header:String, callback:(String, String?) -> Void )
    func execute()
}

class AccessControlProxy : HttpHeaderRequest {
    private let wrappedObject: HttpHeaderRequest
    
    required init(url:String) {
        wrappedObject = HttpHeaderRequestProxy(url: url)
    }
    
    func getHeader(header: String, callback: (String, String?) -> Void) {
        wrappedObject.getHeader(header, callback: callback)
    }
   
    func execute() {
        if (UserAuthentication.sharedInstance.authenticated) {
            wrappedObject.execute()
        } else {
            fatalError("Unauthorized")
        }
    }
}

private class HttpHeaderRequestProxy : HttpHeaderRequest {
    let url:String
    var headersRequired:[String: (String, String?) -> Void]
    
    required init(url: String) {
        self.url = url
        self.headersRequired = Dictionary<String, (String, String?) -> Void>()
    }
    
    func getHeader(header: String, callback: (String, String?) -> Void) {
        self.headersRequired[header] = callback;
    }

    func execute() {
        let nsUrl = NSURL(string: url)
        let request = NSURLRequest(URL: nsUrl!)
        NSURLSession.sharedSession().dataTaskWithRequest(request,
            completionHandler: {data, response, error in
            if let httpResponse = response as? NSHTTPURLResponse {
                let headers = httpResponse.allHeaderFields as! [String: String]
                for (header, callback) in self.headersRequired {
                    callback(header, headers[header])
                }
            }
        }).resume()
    }
}

注意到 HttpHeaderRequestProxy 類前面的private醇疼,因?yàn)閷?duì)于代理類來說子類也沒有任何意義硕并。

應(yīng)用代理

main.swift

import Foundation
let url = "http://www.apress.com"
let headers = ["Content-Length", "Content-Encoding"]
let proxy = AccessControlProxy(url: url)
for header in headers {
    proxy.getHeader(header){header, val in
        if (val != nil) {
            print("\(header): \(val!)")
        }
    }
}
UserAuthentication.sharedInstance.authenticate("bob", pass: "secret")
proxy.execute()

NSFileHandle.fileHandleWithStandardInput().availableData

運(yùn)行程序:

Content-Encoding: gzip
Content-Length: 26992

代理模式的變形

代理類可以用來引用計(jì)數(shù)( reference counting),當(dāng)資源要求主動(dòng)式管理或者當(dāng)你需要引用數(shù)到一定的時(shí)候做一些分類的時(shí)候變得很有用秧荆。為了說明這個(gè)問題鲤孵,我們創(chuàng)建了另一個(gè)示例項(xiàng)目ReferenceCounting:

NetworkRequest.swift

import Foundation
protocol NetworkConnection {
    func connect()
    func disconnect()
    func sendCommand(command:String)
}

class NetworkConnectionFactory {
    class func createNetworkConnection() -> NetworkConnection {
        return NetworkConnectionImplementation()
    }
}

private class NetworkConnectionImplementation : NetworkConnection {
    typealias me = NetworkConnectionImplementation
    
    static let sharedQueue:dispatch_queue_t = dispatch_queue_create("writeQ",DISPATCH_QUEUE_SERIAL)
    
    func connect() { me.writeMessage("Connect") }
        
    func disconnect() { me.writeMessage("Disconnect") }
        
    func sendCommand(command:String) {
        me.writeMessage("Command: \(command)")
        NSThread.sleepForTimeInterval(1)
        me.writeMessage("Command completed: \(command)")
    }
        
    private class func writeMessage(msg:String) {
        dispatch_async(self.sharedQueue){ _ in
            print(msg)
        }
    }
}

NetworkConnection協(xié)議定義的方法用來操作一個(gè)假象的服務(wù)器。connect用來建立和服務(wù)器的連接辰如,sendCommand方法用來操作服務(wù)器普监,當(dāng)任務(wù)完成調(diào)用disconnect 方法斷開連接。

NetworkConnectionImplementation類實(shí)現(xiàn)了這個(gè)協(xié)議并且輸出調(diào)試日志琉兜。用單例模式創(chuàng)建了一個(gè)GCD串行隊(duì)列凯正,這樣兩個(gè)對(duì)象同時(shí)去輸出日志就不會(huì)出現(xiàn)問題。

同時(shí)用工廠模式來提供對(duì)NetworkConnectionImplementation類的實(shí)例的入口豌蟋,因?yàn)槲覀兛梢钥匆奛etworkConnectionImplementation前面的private關(guān)鍵字使得其他文件無法訪問廊散。

main.swift

import Foundation
let queue = dispatch_queue_create("requestQ", DISPATCH_QUEUE_CONCURRENT)

for count in 0 ..< 3 {
    let connection = NetworkConnectionFactory.createNetworkConnection()
    dispatch_async(queue){ _ in
        connection.connect()
        connection.sendCommand("Command: \(count)")
        connection.disconnect()
    }
}
NSFileHandle.fileHandleWithStandardInput().availableData

運(yùn)行程序:

Connect
Connect
Connect
Command: Command: 0
Command: Command: 1
Command: Command: 2
Command completed: Command: 1
Disconnect
Command completed: Command: 2
Disconnect
Command completed: Command: 0
Disconnect

實(shí)現(xiàn)引用計(jì)數(shù)代理

在這種情況中,引用計(jì)數(shù)代理可以用來網(wǎng)絡(luò)連接的生命周期梧疲,所以可以服務(wù)不同的請(qǐng)求允睹。

NetworkRequest.swift

import Foundation
protocol NetworkConnection {
    func connect()
    func disconnect()
    func sendCommand(command:String)
}

class NetworkConnectionFactory {
        
    static let sharedWrapper =  NetworkRequestProxy()
    
    private init(){
        // do nothing
    }
}

private class NetworkConnectionImplementation : NetworkConnection {
    typealias me = NetworkConnectionImplementation
    
    static let sharedQueue:dispatch_queue_t = dispatch_queue_create("writeQ",DISPATCH_QUEUE_SERIAL)
    
    func connect() { me.writeMessage("Connect") }
        
    func disconnect() { me.writeMessage("Disconnect") }
        
    func sendCommand(command:String) {
        me.writeMessage("Command: \(command)")
        NSThread.sleepForTimeInterval(1)
        me.writeMessage("Command completed: \(command)")
    }
        
    private class func writeMessage(msg:String) {
        dispatch_async(self.sharedQueue){ _ in
            print(msg)
        }
    }
}
    

    class NetworkRequestProxy : NetworkConnection {
        
        private let wrappedRequest:NetworkConnection
        private let queue = dispatch_queue_create("commandQ", DISPATCH_QUEUE_SERIAL)
        private var referenceCount:Int = 0
        private var connected = false
        
        init() {
            wrappedRequest = NetworkConnectionImplementation()
        }
        
        func connect() { /* do nothing */ }
        
        func disconnect() { /* do nothing */ }
        
        func sendCommand(command: String) {
            self.referenceCount++
            
            dispatch_sync(self.queue){[weak self]in
                if (!self!.connected && self!.referenceCount > 0) {
                    self!.wrappedRequest.connect()
                    self!.connected = true
                }
                self!.wrappedRequest.sendCommand(command)
                self!.referenceCount--
            
                if (self!.connected && self!.referenceCount == 0) {
                    self!.wrappedRequest.disconnect()
                    self!.connected = false
                }
            }
        }
}

我修改了工廠模式類,現(xiàn)在用單例模式返回一個(gè)NetworkRequestProxy 類的實(shí)例幌氮。 NetworkRequestProxy實(shí)現(xiàn)了NetworkRequest協(xié)議同時(shí)它是NetworkConnectionImplementation對(duì)象的一個(gè)外層類缭受。

這里的引用計(jì)數(shù)代理的目的是為了將 connect和disconnect方法剝離請(qǐng)求并且保持連接直到等待的命令操作完成為止。我們用串行隊(duì)列來保證每個(gè)時(shí)間點(diǎn)只有一個(gè)命令在運(yùn)行该互,并且保證了引用計(jì)數(shù)不會(huì)受并發(fā)訪問的影響米者。

main.swift

import Foundation
let queue = dispatch_queue_create("requestQ", DISPATCH_QUEUE_CONCURRENT)

for count in 0 ..< 3 {
    let connection = NetworkConnectionFactory.sharedWrapper
    dispatch_async(queue){ _ in
        connection.connect()
        connection.sendCommand("Command: \(count)")
        connection.disconnect()
    }
}
NSFileHandle.fileHandleWithStandardInput().availableData

運(yùn)行程序:

Connect
Command: Command: 0
Command completed: Command: 0
Command: Command: 1
Command completed: Command: 1
Command: Command: 2
Command completed: Command: 2
Disconnect

從輸出結(jié)果我們可以看出,command現(xiàn)在在一次連接中串行的執(zhí)行宇智。代理減少了并發(fā)訪問的次數(shù)蔓搞,但是同時(shí)串行化了每一個(gè)操作,這意味著會(huì)運(yùn)行時(shí)間變長(zhǎng)了随橘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末喂分,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子机蔗,更是在濱河造成了極大的恐慌蒲祈,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜒车,死亡現(xiàn)場(chǎng)離奇詭異讳嘱,居然都是意外死亡幔嗦,警方通過查閱死者的電腦和手機(jī)酿愧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來邀泉,“玉大人嬉挡,你說我怎么就攤上這事钝鸽。” “怎么了庞钢?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵拔恰,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我基括,道長(zhǎng)颜懊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任风皿,我火速辦了婚禮河爹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘桐款。我一直安慰自己咸这,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布魔眨。 她就那樣靜靜地躺著媳维,像睡著了一般。 火紅的嫁衣襯著肌膚如雪遏暴。 梳的紋絲不亂的頭發(fā)上侄刽,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音朋凉,去河邊找鬼唠梨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛侥啤,可吹牛的內(nèi)容都是我干的当叭。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼盖灸,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蚁鳖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赁炎,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤醉箕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后徙垫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讥裤,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年姻报,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了己英。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡吴旋,死狀恐怖损肛,靈堂內(nèi)的尸體忽然破棺而出厢破,到底是詐尸還是另有隱情,我是刑警寧澤治拿,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布摩泪,位于F島的核電站,受9級(jí)特大地震影響劫谅,放射性物質(zhì)發(fā)生泄漏见坑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一捏检、第九天 我趴在偏房一處隱蔽的房頂上張望鳄梅。 院中可真熱鬧,春花似錦未檩、人聲如沸戴尸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孙蒙。三九已至,卻和暖如春悲雳,著一層夾襖步出監(jiān)牢的瞬間挎峦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工合瓢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坦胶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓晴楔,卻偏偏與公主長(zhǎng)得像顿苇,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子税弃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理纪岁,服務(wù)發(fā)現(xiàn),斷路器则果,智...
    卡卡羅2017閱讀 134,628評(píng)論 18 139
  • 1 場(chǎng)景問題# 1.1 訪問多條數(shù)據(jù)## 考慮這樣一個(gè)實(shí)際應(yīng)用:要一次性訪問多條數(shù)據(jù)幔翰。 這個(gè)功能的背景是這樣的;在...
    七寸知架構(gòu)閱讀 2,983評(píng)論 1 52
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,916評(píng)論 6 13
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,130評(píng)論 30 470
  • If the bell rings Please bury me in feathers When night f...
    梅照閱讀 170評(píng)論 0 0