JavaScript 設(shè)計(jì)模式(下)——設(shè)計(jì)原則

三. 設(shè)計(jì)原則和編程技巧

3.1 單一職責(zé)原則(SRP)

SRP 原則體現(xiàn)為:一個(gè)對(duì)象(方法)只做一件事情纷纫;

單一職責(zé)原則指的是,就一個(gè)類(通常也包括對(duì)象和函數(shù)等)而言三妈,應(yīng)該僅有一個(gè)引起它變化的原因。如果一個(gè)對(duì)象承擔(dān)了多項(xiàng)職責(zé)莫绣,就意味著這個(gè)對(duì)象將變得巨大畴蒲,引起它變化的原因可能會(huì)有多個(gè)。面向?qū)ο笤O(shè)計(jì)鼓勵(lì)將行為分布到細(xì)粒度的對(duì)象之中对室,如果一個(gè)對(duì)象承擔(dān)的職責(zé)過多模燥,等于把這些職責(zé)耦合到了一起,這種耦合會(huì)導(dǎo)致脆弱和低內(nèi)聚的設(shè)計(jì)掩宜。當(dāng)變化發(fā)生時(shí)蔫骂,設(shè)計(jì)可能會(huì)遭到意外的破壞;

3.1.1 設(shè)計(jì)模式中的 SRP 原則

SRP 原則在很多設(shè)計(jì)模式中都有著廣泛的運(yùn)用牺汤,例如代理模式辽旋、迭代器模式、單例模式和裝飾者模式。

  1. 代理模式:圖片預(yù)加載示例补胚,增加虛擬代理的方式码耐,把預(yù)加載圖片的職責(zé)放到代理對(duì)象中,而本體僅僅負(fù)責(zé)往頁面中添加 img 標(biāo)簽溶其,這也是它最原始的職責(zé)骚腥;
// myImage 負(fù)責(zé)往頁面中添加 img 標(biāo)簽:
var myImage = (function(){
  var imgNode = document.createElement( 'img' );
  document.body.appendChild( imgNode );
  return {
    setSrc: function( src ){
      imgNode.src = src;
    }
  }
})();
// proxyImage 負(fù)責(zé)預(yù)加載圖片,并在預(yù)加載完成之后把請(qǐng)求交給本體 myImage:
var proxyImage = (function(){
  var img = new Image;
  img.onload = function(){
    myImage.setSrc( this.src );
  }
  return {
    setSrc: function( src ){
      myImage.setSrc( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
      img.src = src;
    }
  }
})();
proxyImage.setSrc( 'http:// imgcache.qq.com/music/photo/000GGDys0yA0Nk.jpg' );
  1. 迭代器模式瓶逃,實(shí)例:先遍歷一個(gè)集合束铭,然后往頁面中添加一些 div,這些 div 的 innerHTML 分別對(duì)應(yīng)集合里的元素厢绝;
// a. 基本實(shí)現(xiàn)
var appendDiv = function( data ){
  for ( var i = 0, l = data.length; i < l; i++ ){
    var div = document.createElement( 'div' );
    div.innerHTML = data[ i ];
    document.body.appendChild( div );
  }
};
appendDiv( [ 1, 2, 3, 4, 5, 6 ] );
// b. SRP 原則實(shí)現(xiàn)
var each = function( obj, callback ) {
  var value, i = 0, length = obj.length, isArray = isArraylike( obj ); // isArraylike 函數(shù)未實(shí)現(xiàn)契沫,可以翻閱 jQuery 源代碼
  if ( isArray ) { // 迭代類數(shù)組
    for ( ; i < length; i++ ) {
      callback.call( obj[ i ], i, obj[ i ] );
    }
    } else {
    for ( i in obj ) { // 迭代 object 對(duì)象
      value = callback.call( obj[ i ], i, obj[ i ] );
    }
  }
  return obj;
};

var appendDiv = function( data ){
  each( data, function( i, n ){
    var div = document.createElement( 'div' );
    div.innerHTML = n;
    document.body.appendChild( div );
  });
};

appendDiv( [ 1, 2, 3, 4, 5, 6 ] );
appendDiv({a:1,b:2,c:3,d:4} );
  1. 單例模式:惰性單例創(chuàng)建唯一一個(gè)登錄窗 div 的示例;
// a. 基本實(shí)現(xiàn)
var createLoginLayer = (function(){
  var div;
  return function(){
    if ( !div ){
      div = document.createElement( 'div' );
      div.innerHTML = '我是登錄浮窗';
      div.style.display = 'none';
      document.body.appendChild( div );
    }
    return div;
  }
})();
// b. SRP 原則實(shí)現(xiàn)
var getSingle = function( fn ){ // 獲取單例
  var result;
  return function(){
    return result || ( result = fn .apply(this, arguments ) );
  }
};
var createLoginLayer = function(){ // 創(chuàng)建登錄浮窗
  var div = document.createElement( 'div' );
  div.innerHTML = '我是登錄浮窗';
  document.body.appendChild( div );
  return div;
};
var createSingleLoginLayer = getSingle( createLoginLayer );
var loginLayer1 = createSingleLoginLayer();
var loginLayer2 = createSingleLoginLayer();
alert ( loginLayer1 === loginLayer2 ); // 輸出: true
  1. 裝飾者模式:裝飾函數(shù)實(shí)現(xiàn)代芜;
Function.prototype.after = function( afterfn ){
  var __self = this;
  return function(){
    var ret = __self.apply( this, arguments );
    afterfn.apply( this, arguments );
    return ret;
  }
};

3.1.2 何時(shí)應(yīng)該分離職責(zé)

要明確的是埠褪,并不是所有的職責(zé)都應(yīng)該一一分離。一方面挤庇,如果隨著需求的變化钞速,有兩個(gè)職責(zé)總是同時(shí)變化,那就不必分離他們嫡秕;另一方面渴语,職責(zé)的變化軸線僅當(dāng)它們確定會(huì)發(fā)生變化時(shí)才具有意義,即使兩個(gè)職責(zé)已經(jīng)被耦合在一起昆咽,但它們還沒有發(fā)生改變的征兆驾凶,那么也許沒有必要主動(dòng)分離它們,在代碼需要重構(gòu)的時(shí)候再進(jìn)行分離也不遲掷酗。

3.1.3 違反 SRP 原則

在常規(guī)思維中调违,總是習(xí)慣性地把一組相關(guān)的行為放到一起,如何正確地分離職責(zé)不是一件容易的事情泻轰。一方面技肩,我們受設(shè)計(jì)原則的指導(dǎo), 另一方面浮声, 我們未必要在任何時(shí)候都一成不變地遵守原則虚婿;在方便性與穩(wěn)定性之間要有一些取舍。具體是選擇方便性還是穩(wěn)定性泳挥,并沒有標(biāo)準(zhǔn)答案然痊,而是要取決于具體的應(yīng)用環(huán)境。

3.1.4 SRP 原則的優(yōu)缺點(diǎn)

SRP 原則的優(yōu)點(diǎn)是降低了單個(gè)類或者對(duì)象的復(fù)雜度屉符,按照職責(zé)把對(duì)象分解成更小的粒度剧浸,這有助于代碼的復(fù)用锹引,也有利于進(jìn)行單元測(cè)試。當(dāng)一個(gè)職責(zé)需要變更的時(shí)候辛蚊,不會(huì)影響到其他的職責(zé)粤蝎。但 SRP 原則也有一些缺點(diǎn),最明顯的是會(huì)增加編寫代碼的復(fù)雜度袋马。當(dāng)我們按照職責(zé)把對(duì)象分解成更小的粒度之后初澎,實(shí)際上也增大了這些對(duì)象之間相互聯(lián)系的難度。

3.2 最少知識(shí)原則(LKP)

最少知識(shí)原則( LKP):一個(gè)軟件實(shí)體應(yīng)當(dāng)盡可能少地與其他實(shí)體發(fā)生相互作用虑凛;

3.2.1 減少對(duì)象之間的聯(lián)系

最少知識(shí)原則要求在設(shè)計(jì)程序時(shí)碑宴,應(yīng)當(dāng)盡量減少對(duì)象之間的交互。如果兩個(gè)對(duì)象之間不必彼此直接通信桑谍,那么這兩個(gè)對(duì)象就不要發(fā)生直接的相互聯(lián)系延柠。常見的做法是引入一個(gè)第三者對(duì)象,來承擔(dān)這些對(duì)象之間的通信作用锣披。如果一些對(duì)象需要向另一些對(duì)象發(fā)起請(qǐng)求贞间,可以通過第三者對(duì)象來轉(zhuǎn)發(fā)這些請(qǐng)求。

3.2.2 設(shè)計(jì)模式中的最少知識(shí)原則

最少知識(shí)原則在設(shè)計(jì)模式中體現(xiàn)得最多的地方是中介者模式和外觀模式雹仿,如下所示:

  1. 中介者模式:

如博彩公司示例增热,博彩公司作為中介,每個(gè)人都只和博彩公司發(fā)生關(guān)聯(lián)胧辽,博彩公司會(huì)根據(jù)所有人的投注情況計(jì)算好賠率峻仇,彩民們贏了錢就從博彩公司拿,輸了錢就賠給博彩公司邑商。中介者模式很好地體現(xiàn)了最少知識(shí)原則摄咆,通過增加一個(gè)中介者對(duì)象,讓所有的相關(guān)對(duì)象都通過中介者對(duì)象來通信人断,而不是互相引用吭从。所以,當(dāng)一個(gè)對(duì)象發(fā)生改變時(shí)恶迈,只需要通知中介者對(duì)象即可涩金。

  1. 外觀模式:主要是為子系統(tǒng)中的一組接口提供一個(gè)一致的界面,外觀模式定義了一個(gè)高層接口蝉绷,這個(gè)接口使子系統(tǒng)更加容易使用鸭廷;
_外觀模式_1577154500_28791.png

外觀模式的作用是對(duì)客戶屏蔽一組子系統(tǒng)的復(fù)雜性枣抱,外觀模式對(duì)客戶提供一個(gè)簡(jiǎn)單易用的高層接口熔吗,高層接口會(huì)把客戶的請(qǐng)求轉(zhuǎn)發(fā)給子系統(tǒng)來完成具體的功能實(shí)現(xiàn)。大多數(shù)客戶都可以通過請(qǐng)求外觀接口來達(dá)到訪問子系統(tǒng)的目的佳晶,如果外觀不能滿足客戶的個(gè)性化需求桅狠,那么客戶也可以選擇越過外觀來直接訪問子系統(tǒng);

3.2.3 封裝在最少知識(shí)原則中的體現(xiàn)

封裝在很大程度上表達(dá)的是數(shù)據(jù)的隱藏。一個(gè)模塊或者對(duì)象可以將內(nèi)部的數(shù)據(jù)或者實(shí)現(xiàn)細(xì)節(jié)隱藏起來中跌,只暴露必要的接口 API 供外界訪問咨堤。對(duì)象之間難免產(chǎn)生聯(lián)系,當(dāng)一個(gè)對(duì)象必須引用另外一個(gè)對(duì)象的時(shí)候漩符,我們可以讓對(duì)象只暴露必要的接口一喘,讓對(duì)象之間的聯(lián)系限制在最小的范圍之內(nèi)。把變量的可見性限制在一個(gè)盡可能小的范圍內(nèi)嗜暴,這個(gè)變量對(duì)其他不相關(guān)模塊的影響就越小凸克,變量被改寫和發(fā)生沖突的機(jī)會(huì)也越小。這也是廣義的最少知識(shí)原的一種體現(xiàn)闷沥。

實(shí)例:具有緩存效果的計(jì)算乘積的函數(shù)萎战;

var mult = (function(){
  var cache = {};
  return function(){
    var args = Array.prototype.join.call( arguments, ',' );
    if ( cache[ args ] ){
      return cache[ args ];
    }
    var a = 1;
    for ( var i = 0, l = arguments.length; i < l; i++ ){
      a = a * arguments[i];
    }
    return cache[ args ] = a;
  }
})();
mult( 1, 2, 3 ); // 輸出: 6

3.3 開放封閉原則(OCP)

開放封閉原則( OCP):軟件實(shí)體(類、模塊舆逃、函數(shù))等應(yīng)該是可以擴(kuò)展的蚂维,但是不可修改;

開放封閉原則的思想:當(dāng)需要改變一個(gè)程序的功能或者給這個(gè)程序增加新功能的時(shí)候路狮,可以使用增加代碼的方式虫啥,但是不允許改動(dòng)程序的源代碼。

3.3.1 擴(kuò)展 window.onload 函數(shù)

通過增加代碼览祖,而不是修改原代碼的方式孝鹊,來給 window.onload 函數(shù)添加新的功能,代碼如下:

// 使用裝飾函數(shù)實(shí)現(xiàn)函數(shù)功能擴(kuò)展
Function.prototype.after = function( afterfn ){
  var __self = this;
  return function(){
    var ret = __self.apply( this, arguments );
    afterfn.apply( this, arguments );
    return ret;
  }
};
window.onload = ( window.onload || function(){} ).after(function(){
  console.log( document.getElementsByTagName( '*' ).length );
});

3.3.2 用對(duì)象的多態(tài)性消除條件分支

過多的條件分支語句是造成程序違反開放封閉原則的一個(gè)常見原因展蒂,每當(dāng)需要增加一個(gè)新的 if 語句時(shí)又活,都要被迫改動(dòng)原函數(shù)。因此當(dāng)一大片的 if-else 或者 swtich-case 語句時(shí)锰悼,第一時(shí)間考慮能否利用對(duì)象的多態(tài)性來重構(gòu)代碼柳骄,例如讓動(dòng)物發(fā)出叫聲的例子,每增加一種動(dòng)物箕般,就需要改動(dòng) makeSound 函數(shù)的內(nèi)部實(shí)現(xiàn):

// a. 使用 if-else 基本實(shí)現(xiàn)
var makeSound = function( animal ){
  if ( animal instanceof Duck ){
    console.log( '嘎嘎嘎' );
  }else if ( animal instanceof Chicken ){
    console.log( '咯咯咯' );
  }
};
var Duck = function(){};
var Chicken = function(){};
makeSound( new Duck() ); // 輸出:嘎嘎嘎
makeSound( new Chicken() ); // 輸出:咯咯咯
// b. 利用對(duì)象的多態(tài)性重構(gòu)代碼
var makeSound = function( animal ){
  animal.sound();
};
var Duck = function(){};
Duck.prototype.sound = function(){
  console.log( '嘎嘎嘎' );
};
var Chicken = function(){};
Chicken.prototype.sound = function(){
  console.log( '咯咯咯' );
};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() ); // 咯咯咯

3.3.3 找出變化的地方

開放封閉原則是一個(gè)看起來比較虛幻的原則耐薯,并沒有實(shí)際的模板教導(dǎo)怎樣地實(shí)現(xiàn)它;但開發(fā)中能找到一些讓程序盡量遵守開放封閉原則的規(guī)律丝里,最明顯的就是找出程序中將要發(fā)生變化的地方曲初,然后把變化封裝起來。通過封裝變化的方式杯聚,可以把系統(tǒng)中穩(wěn)定不變的部分和容易變化的部分隔離開來臼婆,在系統(tǒng)的演變過程中,只需要替換那些容易變化的部分幌绍,而穩(wěn)定的部分是不需要改變的颁褂;

3.3.4 設(shè)計(jì)模式中的開放封閉原則

開放封閉原則在設(shè)計(jì)模式中應(yīng)用很廣泛故响,如之前的裝飾者模式示例,還有發(fā)布訂閱模式颁独、模板方法模式彩届、策略模式、代理模式誓酒、職責(zé)鏈模式樟蠕,如下所示:

  1. 發(fā)布訂閱模式

發(fā)布訂閱模式用來降低多個(gè)對(duì)象之間的依賴關(guān)系,它可以取代對(duì)象之間硬編碼的通知機(jī)制靠柑,一個(gè)對(duì)象不用再顯式地調(diào)用另外一個(gè)對(duì)象的某個(gè)接口坯墨。當(dāng)有新的訂閱者出現(xiàn)時(shí),發(fā)布者的代碼不需要進(jìn)行任何修改病往;同樣當(dāng)發(fā)布者需要改變時(shí)捣染,也不會(huì)影響到之前的訂閱者。

  1. 模板方法模式

模板方法模式是一種典型的通過封裝變化來提高系統(tǒng)擴(kuò)展性的設(shè)計(jì)模式停巷,在一個(gè)運(yùn)用了模板方法模式的程序中耍攘,子類的方法種類和執(zhí)行順序都是不變的,所以把這部分邏輯抽出來放到父類的模板方法里面畔勤;而子類的方法具體怎么實(shí)現(xiàn)則是可變的蕾各,于是把這部分變化的邏輯封裝到子類中。通過增加新的子類庆揪,便能給系統(tǒng)增加新的功能式曲,并不需要改動(dòng)抽象父類以及其他的子類,這也是符合開放封閉原則的缸榛。

  1. 策略模式

策略模式和模板方法模式在大多數(shù)情況下可以相互替換使用吝羞,其中模板方法模式基于繼承的思想,而策略模式則偏重于組合和委托内颗。策略模式將各種算法都封裝成單獨(dú)的策略類钧排,這些策略類可以被交換使用。策略和使用策略的客戶代碼可以分別獨(dú)立進(jìn)行修改而互不影響均澳。我們?cè)黾右粋€(gè)新的策略類也非常方便恨溜,完全不用修改之前的代碼。

  1. 代理模式

代理模式的圖片預(yù)加載示例中找前,代理函數(shù)負(fù)責(zé)圖片預(yù)加載糟袁,在圖片預(yù)加載完成之后,再將請(qǐng)求轉(zhuǎn)交給原來的 myImage 函數(shù)躺盛, myImage 在這個(gè)過程中不需要任何改動(dòng)项戴,預(yù)加載圖片的功能和給圖片設(shè)置 src 的功能被隔離在兩個(gè)函數(shù)里,它們可以單獨(dú)改變而互不影響颗品。 myImage 不知曉代理的存在肯尺,它可以繼續(xù)專注于自己的職責(zé)——給圖片設(shè)置 src 屬性;

  1. 職責(zé)鏈模式

職責(zé)鏈模式的訂單示例中躯枢,當(dāng)增加一個(gè)新類型的訂單函數(shù)時(shí)则吟,不需要改動(dòng)原有的訂單函數(shù)代碼,只需要在鏈條中增加一個(gè)新的節(jié)點(diǎn)锄蹂。

3.3.5 開放封閉原則的相對(duì)性

實(shí)際開發(fā)中氓仲,讓程序保持完全封閉是不容易做到,并且有一些代碼是無論如何也不能完全封閉的得糜,總會(huì)存在一些無法對(duì)其封閉的變化敬扛。因此我們可以做到的有下面兩點(diǎn):

  • 挑選出最容易發(fā)生變化的地方,然后構(gòu)造抽象來封閉這些變化朝抖。
  • 在不可避免發(fā)生修改的時(shí)候啥箭,盡量修改那些相對(duì)容易修改的地方。如一個(gè)開源庫(kù)治宣,修改它提供的配置文件急侥,總比修改它的源代碼來得簡(jiǎn)單。

系列鏈接

  1. JavaScript 設(shè)計(jì)模式(上)——基礎(chǔ)知識(shí)
  2. JavaScript 設(shè)計(jì)模式(中)——1.單例模式
  3. JavaScript 設(shè)計(jì)模式(中)——2.策略模式
  4. JavaScript 設(shè)計(jì)模式(中)——3.代理模式
  5. JavaScript 設(shè)計(jì)模式(中)——4.迭代器模式
  6. JavaScript 設(shè)計(jì)模式(中)——5.發(fā)布訂閱模式
  7. JavaScript 設(shè)計(jì)模式(中)——6.命令模式
  8. JavaScript 設(shè)計(jì)模式(中)——7.組合模式
  9. JavaScript 設(shè)計(jì)模式(中)——8.模板方法模式
  10. JavaScript 設(shè)計(jì)模式(中)——9.享元模式
  11. JavaScript 設(shè)計(jì)模式(中)——10.職責(zé)鏈模式
  12. JavaScript 設(shè)計(jì)模式(中)——11. 中介者模式
  13. JavaScript 設(shè)計(jì)模式(中)——12. 裝飾者模式
  14. JavaScript 設(shè)計(jì)模式(中)——13.狀態(tài)模式
  15. JavaScript 設(shè)計(jì)模式(中)——14.適配器模式
  16. JavaScript 設(shè)計(jì)模式(下)——設(shè)計(jì)原則
  17. JavaScript 設(shè)計(jì)模式練習(xí)代碼

本文主要參考了《JavaScript設(shè)計(jì)模式和開發(fā)實(shí)踐》一書

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侮邀,一起剝皮案震驚了整個(gè)濱河市坏怪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绊茧,老刑警劉巖铝宵,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異华畏,居然都是意外死亡鹏秋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門亡笑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拼岳,“玉大人,你說我怎么就攤上這事况芒∠е剑” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵绝骚,是天一觀的道長(zhǎng)耐版。 經(jīng)常有香客問我,道長(zhǎng)压汪,這世上最難降的妖魔是什么粪牲? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮止剖,結(jié)果婚禮上腺阳,老公的妹妹穿的比我還像新娘落君。我一直安慰自己,他們只是感情好亭引,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布绎速。 她就那樣靜靜地躺著,像睡著了一般焙蚓。 火紅的嫁衣襯著肌膚如雪纹冤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天购公,我揣著相機(jī)與錄音萌京,去河邊找鬼。 笑死宏浩,一個(gè)胖子當(dāng)著我的面吹牛知残,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播比庄,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼橡庞,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了印蔗?” 一聲冷哼從身側(cè)響起扒最,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎华嘹,沒想到半個(gè)月后吧趣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耙厚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年强挫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薛躬。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡俯渤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出型宝,到底是詐尸還是另有隱情八匠,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布趴酣,位于F島的核電站梨树,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏岖寞。R本人自食惡果不足惜抡四,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧指巡,春花似錦淑履、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至阔涉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間捷绒,已是汗流浹背瑰排。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留暖侨,地道東北人椭住。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像字逗,于是被迫代替她去往敵國(guó)和親京郑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

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