讀書筆記-面向?qū)ο蟮牧笤瓌t(一)

單一職責(zé)原則

  • 讀《Android源碼設(shè)計模式》
  • 單一職責(zé)的定義為:就一個類而言鲁冯,應(yīng)該僅有一個引起它變化的原因鹦筹,簡單來說介衔,一個類中應(yīng)該是一組相關(guān)性很高的函數(shù),數(shù)據(jù)的封裝
  • 我們從最入門的方式入手

入手

  • 假設(shè)現(xiàn)在要實現(xiàn)圖片加載的功能脚翘,并且能將圖片緩存灼卢,我們可能寫出的代碼是這樣的

public class ImageLoader {

    //圖片緩存
    LruCache<String,Bitmap> mImageCache;
    //線程池,線程數(shù)量為CPU的數(shù)量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    //UI Handler
    Handler mUIHandler = new Handler(Looper.getMainLooper());

    public ImageLoader() {
        initImageCache();
    }

    private void initImageCache(){
        //計算可使用的最大內(nèi)存
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024);

        //取四分之一的可用內(nèi)存作為緩存
        final int cacheSize = maxMemory / 4;

        mImageCache = new LruCache<String,Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };

    }


    public void displayImage(final String url, final ImageView imageView){
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if(bitmap == null){
                    return;
                }
                if(imageView.getTag().equals(url)){
                    updataImageView(imageView,bitmap);
                }
                mImageCache.put(url,bitmap);
            }
        });
    }


    private void updataImageView(final ImageView imageView,final Bitmap bmp){
        mUIHandler.post(new Runnable() {
            @Override
            public void run() {
                imageView.setImageBitmap(bmp);
            }
        });
    }

    public Bitmap downloadImage(String imageUrl){
        Bitmap bitmap = null;
        try{
            URL url = new URL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();

        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bitmap;
    }
}
  • 代碼很簡單来农,可是大概分析一下不難看出鞋真,我們的所有功能都聚合在一個類里面,當(dāng)我們的需求增多的時候沃于,所有的代碼都擠在一個類里面涩咖,這將給我們的維護帶來了很大的麻煩
  • 那么怎么解決呢?

改進

  • 我們提出的方法是:將ImageLoader類拆分一下繁莹,把各個功能獨立出來
  • 各個功能獨立檩互?我們原本的這個ImageLoader類有什么功能?圖片加載和圖片緩存咨演?那好吧闸昨,就把圖片緩存提出來吧?我們單獨寫一個圖片緩存的類
public class ImageCache {
    //圖片緩存
    LruCache<String,Bitmap> mImageCache;

    public ImageCache() {
        initImageCache();
    }

    private void initImageCache(){
        //計算可使用的最大內(nèi)存
        final int maxMemory = (int) (Runtime.getRuntime().maxMemory()/1024);

        //取四分之一的可用內(nèi)存作為緩存
        final int cacheSize = maxMemory / 4;

        mImageCache = new LruCache<String,Bitmap>(cacheSize){
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
            }
        };
    }

    public void put(String url , Bitmap bitmap){
        mImageCache.put(url,bitmap);
    }

    public Bitmap get(String url){
        return mImageCache.get(url);
    }
}
  • 可以看到,我們只是將緩存類的put和get方法抽出去而已饵较,
  • 然后看一下我們的圖片加載類怎么改的
public class ImageLoader {

    //圖片緩存
    ImageCache mImageCache = new ImageCache();
    //線程池拍嵌,線程數(shù)量為CPU的數(shù)量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    //UI Handler
    Handler mUIHandler = new Handler(Looper.getMainLooper());

    public void displayImage(final String url, final ImageView imageView){
        Bitmap bitmap = mImageCache.get(url);
        if(bitmap == null){
            imageView.setImageBitmap(bitmap);
            return;
        }
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if(bitmap == null){
                    return;
                }
                if(imageView.getTag().equals(url)){
                    updataImageView(imageView,bitmap);
                }
                mImageCache.put(url,bitmap);
            }
        });
    }


    private void updataImageView(final ImageView imageView,final Bitmap bmp){
        mUIHandler.post(new Runnable() {
            @Override
            public void run() {
                imageView.setImageBitmap(bmp);
            }
        });
    }

    public Bitmap downloadImage(String imageUrl){
        Bitmap bitmap = null;
        try{
            URL url = new URL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }
}

  • 具體也沒什么大的改動,就是用到了緩存類的對象去調(diào)用相關(guān)方法
  • 這樣拆分之后循诉,每個類的功能很明確横辆,且代碼量也得到了減少,雖然可擴展性還是沒那么好茄猫,但是最起碼思路龄糊,代碼結(jié)構(gòu)變得清晰許多

總結(jié)

  • 其實上面的改進思想就是單一職責(zé)的思想:根據(jù)不同的功能,合理的劃分一個類募疮,或者一個函數(shù)的職責(zé)炫惩,關(guān)于這個劃分倒是沒有一個特別強制的概念,每個人都對功能的劃分有自己的理解阿浓,具體項目中的代碼就需要根據(jù)個人經(jīng)驗與具體邏輯而定他嚷,

開閉原則

  • 開閉原則的定義:軟件中的對象(類,模塊芭毙,函數(shù)等)應(yīng)該對于擴展是開放的筋蓖,但是對于修改是封閉的,在軟件的生命周期內(nèi)退敦,因為變化粘咖,升級和維護等原因需要對軟件原有代碼進行修改時,可能會將錯誤引入原本經(jīng)過測試的舊代碼中侈百,破壞原有系統(tǒng)瓮下,因此,當(dāng)軟件需要變化時钝域,我們應(yīng)該盡量通過擴展的方式來實現(xiàn)變化讽坏,而不是通過破壞已有的代碼來實現(xiàn)
  • 當(dāng)然,一定的不改變原有代碼是不現(xiàn)實的例证,不過路呜,我們在開發(fā)過程中,應(yīng)盡量遵循這個開閉原則

入門

  • 還是之前的那個例子织咧,通過使用不難發(fā)現(xiàn)胀葱,我們雖然寫的這個類具有緩存圖片的功能,但是當(dāng)程序重啟的時候我們之前的緩存都會丟掉笙蒙,因為我們的緩存全都是簡單的緩存在運行內(nèi)存中抵屿,這樣不就會影響Android系統(tǒng)的性能,(因為Android手機的運行內(nèi)存始終有限手趣,我們無法讓一個App占用手機太多運行內(nèi)存)晌该,具有易失性肥荔,重啟程序的時候又會重新下載,浪費用戶流量朝群,基于此燕耿,我們打算將緩存做成緩存在SD卡當(dāng)中
  • 先寫緩存到SD卡中的類
public class DiskCache {
    private static final String TAG = "DiskCache";

    static String cacheDir = null;

    public DiskCache() {
        cacheDir = getSDPath() + "/sadsaf";
    }

    public String getSDPath(){
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState()
                .equals(android.os.Environment.MEDIA_MOUNTED);//判斷sd卡是否存在
        if(sdCardExist) {
            //這里得到的是手機內(nèi)置存儲空間的根目錄
            sdDir = Environment.getExternalStorageDirectory();
            Log.d(TAG, "getSDPath: " + sdDir.toString());
        }else {
            //而這個得到的是手機外部SD卡的根目錄,但是一般Android 是不允許我們對此目錄下文件進行讀寫操作
            sdDir = Environment.getDataDirectory();
            Log.d(TAG, "getSDPath: " + sdDir.toString());
        }
        return sdDir.toString();
    }

    public Bitmap get(String url){
        Log.d(TAG, "get: 在這里" + url);
        String fileName = creatFileName(url);
        return BitmapFactory.decodeFile(cacheDir + fileName);
    }

    public void put(String url, Bitmap bmp){
        FileOutputStream fileOutputStream = null;
        try{

            File file = new File(cacheDir);
            if(!file.exists()){
                Log.d(TAG, "put: 文件夾不存在姜胖,先創(chuàng)建出文件夾");
                if(!file.mkdirs()){
                    Log.d(TAG, "put: 文件夾創(chuàng)建失敗");
                }
                if (file.exists()){
                    Log.d(TAG, "put: 文件夾已經(jīng)存在");
                }
            }
            String s = cacheDir + creatFileName(url);
            Log.d(TAG, "put: 準備打開文件流 " + s);
            fileOutputStream = new FileOutputStream(s);
            bmp.compress(Bitmap.CompressFormat.PNG,100,fileOutputStream);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            if (fileOutputStream != null){
                try{
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //因為我們直接獲取網(wǎng)絡(luò)圖片的話誉帅,圖片的地址會含有斜杠,而這個斜杠在寫文件的時候會被當(dāng)成文件夾目錄右莱,故此會出錯蚜锨,所以這里我將
    //文件的url處理,讓他的名字取網(wǎng)絡(luò)圖片url的最后一個斜杠之后的東西
    private String creatFileName(String url){
        StringBuilder builder = new StringBuilder(url);
        String s;
        if(url.contains("/")){
            int i = builder.lastIndexOf("/");
            s = builder.substring(i, builder.length());
        }else {
            s = builder.toString();
        }
        return s;
    }
  • 那么接下來改一下我們ImageLoader慢蜓,讓他具有設(shè)置SD卡緩存的能力
  • :這里的SD卡寫入問題亚再,以及權(quán)限問題,就不在這里細說了晨抡,如果在這里有問題的話氛悬,自行百度
  • 看ImageLoader改動的內(nèi)容
//圖片 內(nèi)存 緩存
    ImageCache mImageCache = new ImageCache();
    //圖片SD卡或手機內(nèi)存緩存
    DiskCache mDiskCache = new DiskCache();

    //是否使用SD卡緩存
    boolean isUseDiskCache = false;


public void displayImage(final String url, final ImageView imageView){
        //判斷使用的是哪種緩存,并將緩存中的東西取出來(如果有的話)
        Bitmap bitmap = isUseDiskCache ? mDiskCache.get(url) : mImageCache.get(url);
        if(bitmap != null){
            Log.d(TAG, "displayImage: 獲取到緩存");
            imageView.setImageBitmap(bitmap);
            return;
        }
        //如果沒有緩存耘柱,就去線程池中請求下載
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if(bitmap == null){
                    return;
                }
                if(imageView.getTag().equals(url)){
                    updataImageView(imageView,bitmap);
                }
                if(isUseDiskCache){
                    mDiskCache.put(url,bitmap);
                }else {
                    mImageCache.put(url,bitmap);
                }
            }
        });
    }


//是否使用SD卡緩存
    public void useDiskCache(boolean useDiskCache){
        isUseDiskCache = useDiskCache;
    }
  • 這里我們在Activity里面設(shè)置使用SD卡緩存就ok啦
        String url = "http://img2.imgtn.bdimg.com/it/u=4060216298,1329589408&fm=27&gp=0.jpg";
        mImageView = findViewById(R.id.main_IV);
        ImageLoader loader = new ImageLoader();
        loader.useDiskCache(true);//設(shè)置用SD卡緩存
        loader.displayImage(url,mImageView);
  • 寫成這樣如捅,我們就可以很方便的選擇緩存方式,非常方便
  • 但是不知道大家思考過沒调煎?如果我想兩種緩存都使用呢镜遣?
  • 如果這樣的話,用目前的代碼去達到這種要求是不是太過復(fù)雜士袄?那怎么辦悲关?
  • 我們可以提供這樣一個思路,當(dāng)要獲取圖片的時候窖剑,我們先看看內(nèi)存緩存里面有沒有坚洽,如果沒有戈稿,再看看SD卡緩存里面有沒有西土,如果都沒有,再去網(wǎng)絡(luò)上獲取是不是更加人性化一些呢?

繼續(xù)探索

  • 這里有兩種方案鞍盗,一種是我們直接在原來代碼上面改需了,一種是創(chuàng)建一個新的可以實現(xiàn)同時兩種緩存都支持的類
  • 那么想想看?我們剛才說的開閉原則般甲?好吧肋乍,直接選擇第二種方案
  • 來看看我們這個雙緩存類(DoubleCache)的實現(xiàn)

public class DoubleCache {

    ImageCache mMemoryCache = new ImageCache();
    DiskCache mDiskCache = new DiskCache();

    //先從內(nèi)存緩存中獲取,如果沒有敷存,再從SD中獲取
    public Bitmap get(String url){
        Bitmap bitmap = mMemoryCache.get(url);
        if(bitmap == null){
            bitmap = mDiskCache.get(url);
        }
        return bitmap;
    }

    //把圖片緩存到內(nèi)存和SD中
    public void put(String url,Bitmap bitmap){
        mMemoryCache.put(url,bitmap);
        mDiskCache.put(url,bitmap);
    }

}
  • 代碼沒有任何難度墓造,當(dāng)提供了雙緩存機制之后堪伍,我們就可以去修改下我們的加載類了(ImageLoader)
//雙緩存
    DoubleCache mDoubleCache = new DoubleCache();
    //是否使用雙緩存
    boolean isUseDoubleCache = false;

public void displayImage(final String url, final ImageView imageView){
        //判斷使用的是哪種緩存,并將緩存中的東西取出來(如果有的話)
        Bitmap bitmap;
        if(isUseDoubleCache){
            bitmap = mDoubleCache.get(url);
        }else if(isUseDiskCache){
            bitmap = mDiskCache.get(url);
        }else {
            bitmap = mImageCache.get(url);
        }


        if(bitmap != null){
            Log.d(TAG, "displayImage: 獲取到緩存");
            imageView.setImageBitmap(bitmap);
            return;
        }
        //如果沒有緩存觅闽,就去線程池中請求下載
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if(bitmap == null){
                    return;
                }
                if(imageView.getTag().equals(url)){
                    updataImageView(imageView,bitmap);
                }
                if(isUseDiskCache){
                    mDiskCache.put(url,bitmap);
                }else {
                    mImageCache.put(url,bitmap);
                }
            }
        });
    }


//是否使用雙緩存
    public void UseDoubleCache(boolean useDoubleCache) {
        isUseDoubleCache = useDoubleCache;
    }

  • 貌似?蠻好的帝雇?好像是符合開閉原則來著?
  • 來蛉拙,回過頭想一下尸闸,我們剛才為了添加雙緩存機制,修改了幾個類的代碼孕锄?好像基本上都修改了吧
  • 問題:每次加入新的緩存方法都要修改原來的代碼吮廉,這樣可能引來新的bug,而且畸肆,照這樣的實現(xiàn)方法宦芦,用戶是不能自己實現(xiàn)自定義緩存實現(xiàn)的
  • 這里基于這個問題,我們再來看一下開閉原則的定義:軟件中的對象(類轴脐,模塊踪旷,函數(shù)等)應(yīng)該對于擴展是開放的,但是對于修改是封閉的豁辉,也就是說令野,當(dāng)軟件需要變化時,我們應(yīng)該盡量通過擴展的方式來實現(xiàn)變化徽级,而不是通修改已有的代碼來實現(xiàn)
  • 如果要實現(xiàn)用戶自定義緩存機制實現(xiàn)的話气破,我們是不是應(yīng)該抽出一個緩存接口?
public interface IImageCache {
    public Bitmap get(String url);
    public void put(String url,Bitmap bitmap);
}
  • 然后讓我們之前寫的三個緩存類實現(xiàn)這個接口餐抢,這里就不貼代碼现使,接下來我們?nèi)タ纯磮D片加載類怎么做的(ImageLoader)
public class ImageLoader {

    private final static String TAG = "ImageLoader";
    
    //默認為內(nèi)存緩存
    IImageCache mImageCache =  new MemeryCache();
    
    //線程池,線程數(shù)量為CPU的數(shù)量
    ExecutorService mExecutorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    //UI Handler
    Handler mUIHandler = new Handler(Looper.getMainLooper());
    
    //外部注入緩存
    public void setImageCache(IImageCache mImageCache){
        this.mImageCache = mImageCache;
    }
    
    

    public void displayImage(final String url, final ImageView imageView){
        //直接來獲取緩存
        Bitmap bitmap = mImageCache .get(url);
        
        if(bitmap != null){
            Log.d(TAG, "displayImage: 獲取到緩存");
            imageView.setImageBitmap(bitmap);
            return;
        }
        //如果沒有緩存旷痕,就去線程池中請求下載網(wǎng)絡(luò)圖片
        submitLoadRequest(url,imageView);
    }

    private void submitLoadRequest(final String url, final ImageView imageView) {
        imageView.setTag(url);
        mExecutorService.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = downloadImage(url);
                if(bitmap == null){
                    Log.d(TAG, "run: 網(wǎng)絡(luò)圖片下載失敗");
                    return;
                }
                if (imageView.getTag().equals(url)){
                    updataImageView(imageView,bitmap);
                }
                //設(shè)置緩存
                mImageCache.put(url,bitmap);
            }
        });
        
    }


    //更新UI
    private void updataImageView(final ImageView imageView,final Bitmap bmp){
        mUIHandler.post(new Runnable() {
            @Override
            public void run() {
                imageView.setImageBitmap(bmp);
            }
        });
    }

    //下載網(wǎng)絡(luò)圖片
    public Bitmap downloadImage(String imageUrl){
        Bitmap bitmap = null;
        try{
            URL url = new URL(imageUrl);
            final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            bitmap = BitmapFactory.decodeStream(conn.getInputStream());
            conn.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bitmap;
    }
}

  • 從這個ImageLoader里面我們可以看出來碳锈,這個類已經(jīng)相當(dāng)成熟了,里面的東西我們基本不需要再去改變欺抗,想用哪種緩存售碳,哪怕是我們自己的緩存方式,只要我們實現(xiàn)了那個接口绞呈,然后調(diào)用set方法將我們的緩存注入進去即可贸人,
  • 現(xiàn)在想想看?如果我們現(xiàn)在需要使用一種新的緩存方式該怎么做呢佃声?只需實現(xiàn)我們自己的緩存邏輯艺智,然后在調(diào)用一下set方法,即可完美使用圾亏,如下:
String url = "http://img2.imgtn.bdimg.com/it/u=4060216298,1329589408&fm=27&gp=0.jpg";
        mImageView = findViewById(R.id.main_IV);
        ImageLoader loader = new ImageLoader();
        DoubleCache doubleCache = new DoubleCache();
        loader.setImageCache(doubleCache);
        loader.displayImage(url,mImageView);
  • 這就是開閉原則十拣,我們的圖片加載機制對于擴展式開放的封拧,我們可以任意去擴展我們的緩存機制,而不用去管一點點圖片加載的細節(jié)夭问,就可以實現(xiàn)代碼的開閉原則
  • 這就是六大原則的前兩種哮缺,預(yù)知后面如何,且聽下回分解
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末甲喝,一起剝皮案震驚了整個濱河市尝苇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌埠胖,老刑警劉巖糠溜,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異直撤,居然都是意外死亡非竿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門谋竖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來红柱,“玉大人,你說我怎么就攤上這事蓖乘〈盖模” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵嘉抒,是天一觀的道長零聚。 經(jīng)常有香客問我,道長些侍,這世上最難降的妖魔是什么隶症? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮岗宣,結(jié)果婚禮上蚂会,老公的妹妹穿的比我還像新娘。我一直安慰自己耗式,他們只是感情好胁住,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般牺丙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天鉴嗤,我揣著相機與錄音,去河邊找鬼周拐。 笑死,一個胖子當(dāng)著我的面吹牛浪规,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播探孝,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼笋婿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了顿颅?” 一聲冷哼從身側(cè)響起缸濒,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粱腻,沒想到半個月后庇配,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡绍些,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年捞慌,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柬批。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡啸澡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出氮帐,到底是詐尸還是另有隱情嗅虏,我是刑警寧澤,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布上沐,位于F島的核電站旋恼,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏奄容。R本人自食惡果不足惜冰更,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望昂勒。 院中可真熱鬧蜀细,春花似錦、人聲如沸戈盈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽塘娶。三九已至归斤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間刁岸,已是汗流浹背脏里。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留虹曙,地道東北人迫横。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓番舆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矾踱。 傳聞我的和親對象是個殘疾皇子恨狈,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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