濃縮解讀《JavaScript設計模式與開發(fā)實踐》①

f2deb48f8c5494ee6870cfaf2af5e0fe99257e32.jpg

面向對象的JavaScript

1.1 動態(tài)類型語言和鴨子類型

  • 按照數(shù)據(jù)類型,編程語言可以分為兩大類:靜態(tài)類型語言動態(tài)類型語言
  • 靜態(tài)類型語言在編譯時就已確定變量的類型,而動態(tài)類型語言要在程序運行時,等變量被賦值后,才確定數(shù)據(jù)類型。
  • 靜態(tài)類型語言的優(yōu)點:
    1. 可以幫助開發(fā)者在編譯時檢查類型錯誤;
    2. 在運行前明確了數(shù)據(jù)類型,編譯器可以針對程序進行優(yōu)化,提升性能;
  • 靜態(tài)類型語言的缺點:強迫開發(fā)者依照契約編寫程序,繁雜的類型聲明會增加更多的代碼,分散開發(fā)者的精力。
  • 動態(tài)類型語言的優(yōu)點: 編寫的代碼量更少,利于閱讀,讓開發(fā)者更專注于業(yè)務邏輯。
  • 動態(tài)類型語言的缺點:
    1. 不區(qū)分數(shù)據(jù)類型的情況下,可能會讓程序難以理解;
    2. 由于無法保證變量的數(shù)據(jù)類型,運行期間可能會發(fā)生于類型相關的錯誤;
  • JavaScript是典型的動態(tài)類型語言,在對變量賦值時不需要考慮它的類型。動態(tài)類型語言對變量類型的寬容給實際編碼帶來了很大的靈活性,這一切構建在鴨子類型(duck typing)的概念上。
  • 鴨子類型有這樣一個故事:國王要組建一個100只鴨子組成的合唱團,找到99只鴨子了,還差一只。最后發(fā)現(xiàn)有一只非常特別的雞,叫聲跟鴨子一模一樣,最后把這只雞加入了合唱團。通俗的說法是指,“如果它走起來像鴨子,叫起來也是鴨子,那么它就是鴨子”。鴨子類型指導思想是說“應該關注對象的行為,而不是對象的本身。也就是說要關注HAS-A,而不是IS-A”。(注意單詞has 和 is)
  • 鴨子類型的概念在動態(tài)類型語言的面相對象設計中至關重要,通過鴨子類型可以實現(xiàn)一個原則“面向接口編程,而不是面向實現(xiàn)編程”。例如,一個對象如果擁有push和po方法,它可以被當做棧來使用;一個對象如果有l(wèi)ength屬性,且可以通過下標對屬性進行贈刪改查,那這個對象就可以當做數(shù)組來使用。(如果A擁有某個對象的接口方法,那就可以認為A是對象的實例)
  • 由于JavaScript中“面向接口編程”的過程與主流的靜態(tài)類型語言不一樣,導致JavaScript在實現(xiàn)設計模式的過程也與主流的靜態(tài)類型語言大相徑庭。

1.2 多態(tài)

1.2.1 什么是多態(tài)?

  • polymorphism [?p?l?'m?:f?z?m](多態(tài))一詞源于希臘文,拆解開來是poly(復數(shù))和morph(形態(tài))兩個單詞的。它實際含義是指“同樣一個操作,作用于不同的對象,可以產生不同的解釋,并返回不同的執(zhí)行結果”
  • 用多態(tài)來舉例:主人有一只貓和一只狗,當主任向它們發(fā)出“叫”的命令時,不同的動物會以自己的方式來發(fā)出叫聲,狗會汪汪叫,貓會喵喵叫。

//定義一個發(fā)聲的方法,傳入一個animal參數(shù)
var makeSound = function(animal){
//判斷animal的實例是什么動物,就發(fā)出什么叫聲
if(animal instanceof Gog){
console.info("汪汪汪");
}else if(animal instanceof Cat){
console.info("喵喵喵");
}
}
//定義兩個動物
var Dog = function(){};
var Cat = function(){};
//調用方法
makeSound(new Dog());
makeSound(new Cat());

但示例1存在這樣的問題:如果要增加一個動物(比如牛),則必須要改動makeSound函數(shù)了。要知道修改代碼總是危險的,修改的地方越多,程序出錯的可能性就越大。并且當動物種類越來越多,makeSound函數(shù)將變得非常巨大。
- 而多態(tài)背后的核心思想是`“將不變的事物和可能變化的事物分離開來”`。例子中,動物都會叫是不變的,但不同類型的動物具體怎么叫是可變的,我們可以將不變的部分隔離出來,把可變的部分封裝起來,讓程序符合開放-封閉原則。

//統(tǒng)一的makeSound函數(shù)調用入口
var markSound = function(animal){
//將具體怎么叫,封裝成動物的方法
animal.sound();
};
//鴨子
var Duck = function(){ };
Duck.prototype.sound = function(){
console.info("嘎嘎嘎");
};
//小雞
var Chicken = function(){ };
Chicken.prototype.sound = function(){
console.info("咯咯咯");
};
makeSound(new Duck()); //嘎嘎嘎
makeSound(new Chicken()); //咯咯咯


#### 1.2.2 多態(tài)引發(fā)的類型檢查問題

- 談到多態(tài),類型檢查是繞不開的話題,但JavaScript是一門不比進行類型檢查的動態(tài)類型語言,不像靜態(tài)類型語言。
- 以Java為例,代碼編譯時會進行嚴格的類型檢查,不能給變量賦予不同類型的值。

String str; //定義一個String類型的變量
str = "abc"; //賦值成功
str = 123; //報錯!

通過Java實現(xiàn)鴨子類型:

//聲明一個鴨子類
public class Duck{
public void makeSound(){
System.out.println("嘎嘎嘎");
}
}
//聲明一個小雞類
public class Chicken{
public void makeSound(){
System.out.println("咯咯咯");
}
}
//呼叫動物類
public class AnimalSound{
public void makeSound(Duck duck){
duck.makeSound();
}
}
//測試類
public class Test{
public static void main(String args[]){
AnimalSound animalSound = new AnimalSound();
animalsound.makeSound(new Duck()); //輸出:嘎嘎嘎
}
}

雖然順利讓鴨子發(fā)出叫聲,但如果想讓小雞叫喚,發(fā)現(xiàn)幾乎是不可能實現(xiàn),因為Animal.makeSound()方法規(guī)定了只接受Duck類型的參數(shù)。
針對這種情況,靜態(tài)類型的編程語言通常被設計成可以`向上轉型`:當給一個類變量賦值時,既可以使用類本身,也可以使用這個類的超類。好比我們描述天上的一直麻雀時,既可以說“有一只麻雀在天上飛”,也可以說“有一只鳥在天上飛”。
- 通過繼承實現(xiàn)多態(tài)的效果是最常用的手段。繼承通常包含`實現(xiàn)繼承`和`接口繼承`,這里通過實現(xiàn)繼承重新調整鴨子類型的代碼。

//定義動物抽象類
public abstract class Animal{
abstract void makeSound(); //makeSound抽象方法
}
//小雞實現(xiàn)類
public class Chicken extends Animal{
public void makeSound(){
System.out.println("咯咯咯");
}
}
//小鴨實現(xiàn)類
public class Duck extends Animal{
public void makeSound(){
System.out.println("嘎嘎嘎");
}
}
//呼叫動物類
public class AnimalSound{
public void makeSound(Animal animal){
animal.makeSound();
}
}
//測試類
public class Test{
public static void main(String args[]){
AnimalSound animalSound = new AnimalSound();
animalsound.makeSound(new Duck()); //輸出:嘎嘎嘎
animalsound.makeSound(new Chicken()); //輸出:咯咯咯
}
}


#### 1.2.3 JavaScript的多態(tài)
- 多態(tài)之所以要把“不變的事物”和“可能改變的事物”分離,是為了消除類型之間的耦合,Java通過向上轉型來實現(xiàn)。而由于JavaScript的變量類型在運行期是可變的,意味著JavaScript對象的多態(tài)性是與生俱來的 。判斷動物是否能發(fā)出叫聲,不需要判斷對象是某種類型的動物,只取決于它有沒有makeSound方法,不存在任何程度的“類型耦合”。

#### 1.2.4 多態(tài)在面向對象程序設計中的作用
- 多態(tài)最根本的作用是消除條件分之語句,將過程化的條件分之語句轉化為對象的多態(tài)性。
- Martin Fowler在《重構:改善既有代碼的設計》書中以拍電影作為多態(tài)的比喻。
* 電影在拍攝時,當導演喊出“action”后,主演門開始講臺詞,燈光師負責打燈,群眾演員假裝中槍倒地,道具師往鏡頭撒雪花。在等到導演的指令后,每個對象都知道自己應該做什么,這就是多態(tài)性。
* 如果不利用對象的多態(tài)性,而是用面向過程的方式上來編寫代碼,那么就相當于:每次電影開始拍攝后,導演要逐個走到每個人的面前,確認它們的職業(yè)分工(類型),然后再告訴他們要做什么。映射到程序當中,那么程序中將充斥著大量條件分之語句。
- 每個對象應該做什么,封裝在成對象內部的一個方法,每個對象負責自己的行為。所以這些對象可以根據(jù)同一個指令,有條不紊地分別進行各自的工作,這正是面向對象的優(yōu)點。

#### 1.2.5 多態(tài)與設計模式
- GoF的《設計模式》一書從面向對象設計的角度出發(fā),通過對封裝、繼承、多態(tài)、組合等多種技術的反復使用,提煉出可重復使用的面向對象設計技巧。多態(tài)是當中的重中之重,絕大多數(shù)設計模式的實現(xiàn)都離不開多態(tài)性的思想。
- 比如命令模式,請求被封裝在一些命令對象中,這使得命令的調用和命令的接受者可以完全解耦開來,當調用execute方法時,不同的命令做不同的事情,從而產生不同的執(zhí)行結果。
- 在組合模式中,對組合對象和葉節(jié)點對象發(fā)出同一個指令時,它們會各自做自己應該做的事情,組合對象把消息繼續(xù)傳遞給下面的葉節(jié)點對象,葉節(jié)點再對指令做出響應。
- 在策略模式中,Context并沒有執(zhí)行算法的能力,而是把職責委托給具體的策略對象。每個策略對象負責的算法被封裝在各自對象的內部。當對這些策略對象發(fā)出計算的指令時,它們會個各自執(zhí)行并響應不同的計算結果。

---

### 1.3 封裝
#### 1.3.1 封裝數(shù)據(jù)
- 很多編程語言是通過語法解析來實現(xiàn)封裝數(shù)據(jù)的,比如Java提供private、public、protected等關鍵字來限定訪問權限。
- 可JavaScript缺乏這些關鍵字的支持,只能依賴變量的作用域來實現(xiàn)public和private的封裝特性。

var myObject = (function(){
var _name = 'sven'; //私有變量
return {
//公開方法
getName : function(){
return _name;
}
};
})();

- (ECMAScripte6標準,提供了let關鍵字來創(chuàng)建塊級作用域)

#### 1.3.2 封裝實現(xiàn)
- 很多人喜歡把封裝理解成封裝數(shù)據(jù),這是一種狹義的定義。其實封裝不僅是隱藏數(shù)據(jù),還包括隱藏實現(xiàn)細節(jié)、設計細節(jié)以及隱藏對象的類型等。
- 封裝實現(xiàn)細節(jié)指的是,使得對象內部的變化對于其他對象而言是不可見的,對象只對自己的行為負責。對象之間的耦合變松散,對象之間只通過暴露的API接口來通訊。這樣一來,即便當我們需要修改對象時,可以任意修改它的內部實現(xiàn),而由于對外接口沒有變化,則不會影響程序的其他功能。
- 比如迭代器each()函數(shù),不用關心它的內部是怎么實現(xiàn)的,只需要知道它的作用是遍歷集合對象。及時each函數(shù)修改了內部源代碼,主要調用方式沒有變化,就不會對調用each()函數(shù)的代碼造影響。

#### 1.3.3 封裝類型
- 封裝類型是類似Java等靜態(tài)類型語言中一種重要的封裝方式。一般通過抽象類和接口來進行。把對象的真正類型隱藏在抽象類或者接口背后,這樣對于調用者來說,就看看呀只關心對象的行為,而不是對象的類型。
- 由于靜態(tài)語言需要想方設法的隱藏對象的類型,也促使了比如工廠方法模式、組合模式等設計模式的誕生。
- JavaScript本身是一門類型模糊的語言。對于JavaScript的設計模式實現(xiàn)來說,不區(qū)分類型是一種失色,也可以說是一種解脫。

#### 1.3.4 封裝變化
- 從設計模式的角度出發(fā),封裝的更高層面體現(xiàn)為封裝變化。
- 《設計模式》提到“找到變化,并封裝之”,《設計模式》一書中總共歸納總結了23中設計模式,這23種設計模式又可以從意圖上區(qū)分為創(chuàng)建型模式、結構型模式和行為型模式。
- 拿創(chuàng)建型模式來說,具體創(chuàng)建什么對象是變化的,創(chuàng)建型模式的目的就是封裝創(chuàng)建對象的變化。而結構型模式封裝的是對象之間的組合關系。行為型模式封裝的是對象的行為變化。通過封裝變化,可以最大程度的保證程序的穩(wěn)定性和可拓展性。

---

### 1.4 原型模式和JavaScript
- Brendan Eich設計JavaScript時,之所以選擇原型的面向對象系統(tǒng),是因為從一開始就沒有打算在JavaScript中加入類的概念。
- 以類作為中心的面向對象編程語言當中,比如Java,類和對象的關系可以想象成鑄模和鑄件的關系,對象是從類中創(chuàng)建而來的。而在原型編程的思想當中,類不是必須的,對象是通過克隆另一個對象得到的。

#### 1.4.1 使用克隆的原型模式
- 原型模式是創(chuàng)建對象的一種模式。
- 相比起Java,創(chuàng)建一個對象要先指定它的類型,然后通過類來創(chuàng)建這個對象。原型模式不在關心對象的具體類型,而是找到一個對象,然后通過克隆來創(chuàng)建一個一模一樣的對象,就好比游戲中的分身。
- 說到克隆,原型模式的實現(xiàn)關鍵在于編程語言是否提供clone方法,比如ECMAScript5提供的`Object.create()`方法。

#### 1.4.2 克隆是創(chuàng)建對象的手段
- 原型模式的真正目的并不是為了復制一個一模一樣的對象,而是提供一種便捷的方式去創(chuàng)建某個類型的對象,而克隆只是創(chuàng)建對象的手段。
- 依賴倒置原則提醒開發(fā)者,編寫像Java等靜態(tài)型語言的程序時,創(chuàng)建對象要避免依賴具體的類型,比如`new XXX`創(chuàng)建對象的方式會使得類型之間的耦合度很高,代碼很僵硬。需要通過工廠方法模式和抽象工廠模式解決此類問題,但這無可避免的,會增加很多額外的代碼。
- 原型模式則提供了另外一種方式,通過克隆對象,不需要再關心對象的具體類型名稱,所以也就不存在類型耦合的問題。
- JavaScript本身是一門基于原型的面型對象語言,它的面向對象系統(tǒng)通過原型模式來搭建,所以與其稱為原型模式,不如稱之為原型編程范例更為合適。

#### 1.4.3 原型模式的Io語言
- 事實上,使用原型模式來構建面向對象系統(tǒng)的編程語言,并非僅有JavaScript一家。還有比如Self語言、Smalltalk語言,以及另一個輕巧的Io語言。
- Io中同樣沒有類的概念每個對象都是基于另外一個對象的克隆。既然每個對象都是由其他對象克隆而來,那么Io語言本身應該至少要提供一個根對象,其他對象都發(fā)源于這個根對象才對,就好像美劇吸血鬼的始祖一樣。對的,Io語言根對象是Object。
- 繼續(xù)拿動物世界的例子講解Io語言

//通過克隆Object根對象得到Animal對象,所以Obejct稱為Animal的原型
Animal := Object clone;
//給Animal對象添加makeSound方法
Animal makeSound := method("animal makeSound" print);
//接下來以Animal作為原型,繼續(xù)創(chuàng)建Dog對象
Dog := Animal clone;
//然后給Dog對象添加eat方法
Dog eat := method("dog eat" print);
//最后測試Animal對象和Dog對象的功能
Animal makeSound; //輸出"animal makeSound"
Dog eat; //輸出"dog eat"


#### 1.4.4 原型編程的特點
- 從Io語言的使用當中可看出,跟使用“類”的語言不同的是,原型編程語言最初只有一個根對象(Object),其他對象都是克隆自另一個對象。
- 在上一個例子當中,Object是Animal的原型,Animal的Dog的原型,它們串聯(lián)起來形成了一條原型鏈。
- 原型鏈是很有用處的,當嘗試調用Dog對象的某個方法,而它本身又沒有時,那么Dog對象會把調用的請求委托給它的原型Animal對象。如果Animal對象也沒有的話,請求會繼續(xù)順著原型鏈,被委托給Object對象。這樣一來,便能得到繼承的效果,看起了就像是Animal是Dog的父類,Object是Animal的父類。這個機制并不復雜卻非常強大,JavaScript和Io語言一樣,原型繼承的本質就是基于原型鏈的委托機制。
- 最后我們觀察發(fā)現(xiàn),原型編程泛型包括以下的特點:
  * 所有的數(shù)據(jù)都是對象;
  * 不通過實例化創(chuàng)建對象,而是找到一個對象作為原型并克隆它;
  * 對象會記住個各自的原型;
  * 如果對象無法響應某個請求,會把這個請求委托給自己的原型;

#### 1.4.5 原型模式的JavaScript語言
- 接下來講解JavaScript如何基于原型編程的規(guī)則來構建面向對象系統(tǒng)。
- __所有的數(shù)據(jù)都是對象__:
    * JavaScript在設計的時候模仿了Java,數(shù)據(jù)類型分為基本類型和對象類型。

    * 基本數(shù)據(jù)類型有boolean、number、string、null、undefined。
    * 按照JavaScript設計者的本意,除了undefined之外,其他都是對象。而為了實現(xiàn)這一目標,基本數(shù)據(jù)類型也可以通過“包裝類”的方式變成對象類型來處理。

- __不通過實例化創(chuàng)建對象,而是找到一個對象作為原型并克隆它__:
    * 相比起Io語言,JavaScript中不需要關心克隆的細節(jié),JavaScript引擎內部會處理。我們只需要顯式的調用`var obj1 = new Object();`或者`var obj2 = {};`,JavaScript引擎就會從Object.prototype上克隆一個對象出來。
    * 演示用new運算符從構造器中得到一個對象
    ```
function Person(name){
        this.name = name;
};
Person.prototype.getName = function(){
        return this.name;
};
var person1 = new Person('William');
console.log(person1.name);   //輸出”William“
console.log(person1.getName());   //輸出”William“
console.log(Object.getPrototypeOf(person1) === Person.prototype);   //輸出"true“
    ```  

    * 這里的Person不是類,而是構造函數(shù)。JavaScript的函數(shù)既可以作為普通函數(shù)被調用,也可以作為構造函數(shù)被調用。當使用new關鍵字調用函數(shù)時,此函數(shù)就是一個構造器。
    * 當你使用new操作符調用構造函數(shù)時,會經歷以下步驟:
      1. 創(chuàng)建一個空對象,作為將要返回的實例對象;
      2. 將空對象的原型指向構造函數(shù)的prototype屬性,也就是Keith構造函數(shù)的prototype屬性;
      3. 將空對象賦值給構造函數(shù)內部的this關鍵字,也就是this關鍵字會指向實例對象;
      4. 開始執(zhí)行構造函數(shù)內部的代碼;
- __對象會記住個各自的原型__:
    * 要實現(xiàn)Io語言或者JavaScript語言中的原型鏈查找機制,每個對象至少應該先記住自己的原型對象。
    * 但就JavaScript真正的實現(xiàn)來說,其實說對象有原型并我準確,應該說對象的構造器有原型。對于“對象把請求委托給自己的原型”這句話,更好的說法應該是“對象把請求委托給它的構造器的原型”。
    ```
person1.constructor指向Person,然后Person.prototype指向原型對象;
或者
person1.[[Prototype]]指向Person.Person.prototype原型對象([[Prototype]]屬性和書中所寫的__proto__屬性一致)
    ```
- __如果對象無法響應某個請求,會把這個請求委托給自己的原型__:
    * Io語言中每個對象都可以作為原型被克隆,Animal對象克隆自Object對象,Dog對象又克隆自Animal對象,形成了一條天然的原型鏈。但這樣就只是單一的繼承連,這樣的面向對象系統(tǒng)顯得非常受限。
    * 實際上JavaScript的對象最初都是由Object.prototype對象克隆而來,但不受限于Obejct.prototype,而是可以動態(tài)的指向其他對象。
    * 在原型鏈查找機制中,原型鏈并不是無限長的。當嘗試訪問對象的某個屬性,請求會被委托給各自的原型對象,如果最終傳遞到Object.prototype對象也沒有查找到。這次請求會就此打住,返回undefined。

#### 1.4.6 原型繼承的未來
- 設計模式很多時候其實是在彌補語言的不足之處,就像Peter Norvig曾說,設計模式是對語言不足的補充,如果要使用設計模式,不如去找一門更好的語言。
- JavaScript中用`Object.create()`來完成原型繼承,看起來更能體現(xiàn)原型模式的精髓。但效率卻不高,比通過構造函數(shù)來創(chuàng)建對象要慢。而ECMAScript6帶來了新的Class語法。

class Animal{
constructor(name){
this.name = name;
}
getName(){
return this.name;
}
}
class Dog extends Animal{
constructor(name){
super(name);
}
speak(){
return "woof";
}
}
var dog = new Dog("Scamp");
console.log(dog.getName() + ' says' + dog.speak());

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容