JavaScript - 设计模式 - 命名空间


本小节主要讲解三种常用的设计模式和命名空间,第一种是工厂模式,第二种是单利模式,第三种是观察者模式


设计模式概述

是为了解决在开发中可能遇到的需求(相似),而提出的一套解决方法.

设计模式要求:

  • 在开发中整个系统需要一套设计模式(架构师)
  • 来源:建筑(建房子)领域
  • 设计模式的四人帮: Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides
  • 设计模式:总共有23种.
  • **设计模式类型:单利(例)模式 |观察者模式 | 代理模式 |工厂模式 |适配器模式 |桥接模式 | .... **
  • 设计模式的书:<设计模式><大话设计模式|大话数据结构><23种常见的设计模式>

工厂模式

批量创建大量的同类型的对象

优点 :

  • 可以通过统一的借口来创建对象,根据传入的参数不同来创建不同的对象,易于扩展和维护,稳定性更好

核心过程 :

  • 提供一个父构造函数
  • 设置这个父构造函数的原型对象(属性|方法)
  • 在父构造函数身上添加静态工厂方法

1.需要接收传入的参数(要生产的产品的类型)
2.判断 是否支持生产
3.设置子构造函数的原型对象
4.把新创建的对象返回

  • 定制合作伙伴

  • 直接使用父构造函数的静态工厂方法来创建指定的产品对象

  • 示例代码 :

<script>
    //1. 提供一个父构造函数
    function PhoneMake(){};
    //2. 设置这个父构造函数的原型对象(属性|方法)
    PhoneMake.prototype.logDes = function(){
        console.log("我们的口号是:" + this.des);
    }

    //3. 在父构造函数身上添加静态工厂方法
    PhoneMake.factory = function(typeStr){
        // 3.1 需要接收传入的参数(要生产的产品的类型)
        var productType =  typeStr;

        //var Dog = PhoneMake[productType];
        //3.2 判断 是否支持生产
        if (typeof PhoneMake[productType]  != "function")
        {
            //抛出一个异常
            throw "对不起,我们工厂和这个品牌没有商务合作,不能生产!"
        }

        //3.3 设置子构造函数的原型对象
         //为了获得构造函数原型对象的方法
        PhoneMake[productType].prototype = new PhoneMake(); 

        //3.4 设置子构造函数的原型对象
       var newProduct = new PhoneMake[productType]();

        //3.5 把新创建的对象返回
        return newProduct;
    }

    //4. 定制合作伙伴
    PhoneMake.iphone = function(){
        this.des = "最安全最稳定的系统,最垃圾的体验"
    }
    PhoneMake.oppo = function(){
        this.des = "充电两小时,通话五分钟"
    }
    PhoneMake.vivo = function(){
        this.des = "照亮你的美,你本来就很美"
    }
    PhoneMake.meizu = function(){
        this.des = "我就是我,不一样的魅族"
    }

    //5. 直接使用父构造函数的静态工厂方法来创建指定的产品对象
    var iphone = PhoneMake.factory("iphone");
    var vivo = PhoneMake.factory("vivo");
    var oppo = PhoneMake.factory("oppo");
    var meizu = PhoneMake.factory("meizu");
    var xiaomi = PhoneMake.factory("xiaomi");

    iphone.logDes();
    vivo.logDes();
    oppo.logDes();
    meizu.logDes();

</script>

单利模式

在整个程序的运行过程中,一个类只有一个实例对象

js中的单利模式

  • js没有类(ES6才有的) ,js实现单利模式(限定讨论的范围)

1.字面量
2.内置构造函数(Array Date Function Object)
3.工厂函数
4.自定义构造函数(单利模式)

  • js是什么样的语言

1.弱类型,脚本,轻量级,面向对象,基于原型(对象),解释行语言.函数式.
2.js到底是不是一门面向对象(类)的语言?
3.js是一门支持面向对象的语言.(封装|继承|多态)

单利模式实现之后的表现

var p1 = new 构造函数()
var p2 = new 构造函数()
p1 == p2

  • 示例代码 :
<script>
    function Person(){
        //首先创建一个空的对象
        //默认把新的对象赋值给this
        //把新对象返回
    }
    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);
</script>

单利模式的实现方式01 ----> 全局变量

全局变量来保存对象实现单利模式

  • 提供一个全局的变量
  • 提供一个构造函数Person
  • 在构造函数内部先判断全局变量是否有值,如果有那么就直接返回
  • 如果没有,那么就把this赋值给全局变量
  • 通过this设置属性和方法

存在的问题

  • 使用一个全局变量来保存单利对象,该全局变量在整个作用域中都可以被访问或者是修改,可能会轻易的被覆盖或者是修改.

  • 修改之后,创建出来的实例对象就不再是之前的那个单利对象了.

  • 示例代码 :

<script>
    var instance;
    function Person(){
        if(instance)
        {
            console.log("对象已经被创建,直接把之前创建好的对象返回");
            return instance;
        }
        instance = this;
        this.name = "奥特曼";
        this.age = 1000;
        console.log("第一次创建对象,创建对象之后并返回");
    }

    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);
    var p3 = new Person();

    instance = "demo";
    var p4 = new Person();
    console.log(p4);
    console.log(p4 == p1);
</script>

单利模式的实现方式02 ----> 静态属性

静态成员:直接添加到构造函数身上的属性或者是方法

存在的问题

  • 构造函数的静态属性其实也可能被修改,因此这种方法也不安全

  • 示例代码 :

<script>
    function Person(){
        //判断对象是否已经被创建
        if (Person.instance)
        {
            console.log("之前已经创建过对象,直接返回");
            return Person.instance;
        }

        this.name = "大黄蜂"
        Person.instance  = this;
        console.log("第一次创建");
    }

    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);


    instance = "demo";
    var p3 = new Person();
    console.log(p1 == p3);

    Person.instance = "123";
    var p4 = new Person();
    console.log(p4 == p1);
</script>

单利模式的实现方式03 ----> 惰性函数

核心过程

  • 提供一个构造函数

  • 在构造函数内部声明一个私有的变量

  • 使用惰性函数定义更新构造函数的实现(直接把instance返回)

  • 设置原型对象[新构造函数的原型对象 = 旧构造函数的原型对象]
    构造函数,prototype == 对象.proto

  • 使用新的构造函数创建实例对象,并且赋值给instance

  • 修正对象的构造函数指向

  • 通过instance设置实例属性和方法

  • 示例代码 :

<script>
    // 01 提供一个构造函数
    function Person(){
        //this01
        //02 在构造函数内部声明一个私有的变量
        var instance;
        //03 使用惰性函数定义更新构造函数的实现(直接把instance返回)
        Person = function(){
            //内部默认会创建一个空的对象 this02
            return instance;
        }
        //04 设置原型对象[新构造函数的原型对象 = 旧构造函数的原型对象]
        //原型链继承:Man.prototype = new Person();
        //原型式继承:Man.prototype = Person.prototype;
        //Person.prototype = this.__proto__;  //非标准(代码中不要出现)
        Person.prototype = this;

        //05 使用新的构造函数创建实例对象,并且赋值给instance
        instance = new Person();
        //instance = this;
        //06 修正对象的构造函数指向
        instance.constructor = Person;
        // 07 通过instance设置实例属性和方法
        instance.name = "我很好听";
        // 08 把instance返回
        return instance;
    }

    Person.prototype.des = "描述信息";
    var p1 = new Person();
    Person.prototype.hi = "hi";

    var p2 = new Person();
    console.log(p1 == p2);

    console.log(p1.constructor == Person);  //true
    console.log(p1.des);
    console.log(p1.hi);
</script>

单利模式的实现方式04 ----> 全局变量 + 即时函数

  • 示例代码 :
<script>
    var Person;
    (function(){
        var instance;

        Person = function (){
            if(instance)
            {
                return instance;
            }
            this.name = "momo";
            instance = this;
        }
    })();

    var p1 = new Person();
    var p2 = new Person();
    console.log(p1 == p2);
</script>

观察者模式

观察者模式举例说明

  • 男生A和男生B同时都喜欢女生C,他们想时时监视女生C的动向,动态,所以他们找了女生C的闺蜜作为观察者帮他们监视实时动态.这样不管女生C有什么最新的动态都会被男生A和男生B监听到,开发中就是男生多了点,动态多了点,核心内容就是这样

  • 要求:

女神:rose(发布者)
男生:jack(订阅者)
男生:tom(订阅者)

  • 过程:

创建或者是设置一个发布者
创建订阅者对象
注册订阅者
测试(发状态)

  • 示例代码1 : 一个发布者,两个订阅者,关注的是一个状态
<script>
    //01 创建或者是设置一个发布者
    var rose = {
        user:[],
        addUser:function(fn){
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user.push(fn);
        },
        removeUser:function(fn){
            for (var i = 0; i < this.user.length; i++) {
                if(this.user[i] == fn)
                {
                    console.log(fn + "取消了订阅");
                    this.user.splice(i,1);
                }
            }
        },
        eat:function(){
            for (var i = 0; i < this.user.length; i++) {
               this.user[i]();
            }
        }
    }


    // 02 创建订阅者对象
    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        }
    }
    var tom = {
        eat_tom:function(){
            console.log("我陪你去吃寿司吧  ---tom");
        }
    }

    // 03 注册订阅者
    rose.addUser(jack.eat_jack);
    rose.addUser(tom.eat_tom);

    //04 发布者状态改变
    rose.eat();
    rose.removeUser(jack.eat_jack);
    rose.eat();
</script>
  • 示例代码2 : 多个状态
<script>
    //01 创建或者是设置一个发布者
    var publisher = {
        addUser:function(fn,type){
            var type = type || "eat";
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user[type].push(fn);
        },
        removeUser:function(fn,type){
            var type = type || "eat";
            for (var i = 0; i < this.user[type].length; i++) {
                if(this.user[type][i] == fn)
                {
                    console.log(fn + "取消了订阅");
                    this.user[type].splice(i,1);
                }
            }
        },
        eat:function(){
            for (var i = 0; i < this.user["eat"].length; i++) {
               this.user["eat"][i]();
            }
        },
        sleep:function(){
            for (var i = 0; i < this.user["sleep"].length; i++) {
                //console.log(this.user,"++++");
                this.user["sleep"][i]();
            }
        }
    }

    var rose = {};
    //封装一个函数用来快速的让某个指定对象成为发布者
    function makePublisher(o){
        for(var i in publisher)
        {
            if (publisher.hasOwnProperty(i) && typeof publisher[i] == "function" ){
                o[i] = publisher[i];
            }
        }
        o.user = {
            eat:[],
            sleep:[]
        };
    }
    makePublisher(rose);

    // 02 创建订阅者对象
    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        },
        sleep_jack:function(){
            console.log("晚安 rose  ---jack");
        }
    }

    // 03 注册订阅者
    rose.addUser(jack.eat_jack,"eat");        //关注rose肚子饿不饿
    rose.addUser(jack.sleep_jack,"sleep");     //关注rose困不困

    rose.eat();
    rose.sleep();
  • 示例代码3 : 通用性处理
<script>
    //01 创建或者是设置一个发布者
    var publisher = {
        addUser:function(fn,type){
            var type = type || "eat";
            if (this.user[type] == undefined)
            {
                this.user[type] = [];
            }
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user[type].push(fn);
        },
        removeUser:function(fn,type){
            this.publish(type,fn);
        },
        publish:function(type,fn){
            var type = type || "eat";
            for (var i = 0; i < this.user[type].length; i++) {
                //判断当前是要取消订阅还是要发布状态
                if (typeof fn == "function")
                {
                    if(this.user[type][i] == fn)
                    {
                        console.log(fn + "取消了订阅");
                        this.user[type].splice(i,1);
                    }
                }else
                {
                    this.user[type][i]();
                }

            }
        }
    }
    var rose = {
        eat:function(){
            this.publish("eat");
        },
        sleep:function(){
            this.publish("sleep");
        },
        read:function(){
            this.publish("read");
        }
    };
    function makePublisher(o){
        for(var i in publisher)
        {
            if (publisher.hasOwnProperty(i) && typeof publisher[i] == "function" ){
                o[i] = publisher[i];
            }
        }
        o.user = {
            eat:[],
            sleep:[]
        };
    }
    makePublisher(rose);

    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        },
        sleep_jack:function(){
            console.log("晚安 rose  ---jack");
        }
    }
    var tom = {
        eat_tom:function(){
            console.log("我买给你吧  ---tom");
        },
        sleep_tom:function(){
            console.log("今晚的太阳很好看 ---tom");
        },
        read_tom:function(){
            console.log("你也在学习js吗?");
        }
    }

    rose.addUser(jack.eat_jack,"eat");
    rose.addUser(tom.sleep_tom,"sleep");
    rose.addUser(tom.read_tom,"read");
    rose.eat();
    rose.sleep();
    rose.read();

</script>
  • 示例代码4 : 订阅者成为发布者
<script>
    //01 创建或者是设置一个发布者
    var publisher = {
        addUser:function(fn,type){
            var type = type || "eat";
            if (this.user[type] == undefined)
            {
                this.user[type] = [];
            }
            if (typeof fn != "function")
            {
                throw "不支持该操作!";
            }
            this.user[type].push(fn);
        },
        removeUser:function(fn,type){
            this.publish(type,fn);
        },
        publish:function(type,fn){
            var type = type || "eat";
            for (var i = 0; i < this.user[type].length; i++) {
                //判断当前是要取消订阅还是要发布状态
                if (typeof fn == "function")
                {
                    if(this.user[type][i] == fn)
                    {
                        console.log(fn + "取消了订阅");
                        this.user[type].splice(i,1);
                    }
                }else
                {
                    this.user[type][i]();
                }

            }
        }
    }
    var rose = {
        eat:function(){
            this.publish("eat");
        },
        sleep:function(){
            this.publish("sleep");
        },
        read:function(){
            this.publish("read");
        },
        lol_rose:function(){
            console.log("你怎么又在打游戏?还是游戏比较重要一些?")
        }
    };
    function makePublisher(o){
        for(var i in publisher)
        {
            if (publisher.hasOwnProperty(i) && typeof publisher[i] == "function" ){
                o[i] = publisher[i];
            }
        }
        o.user = {
            eat:[],
            sleep:[]
        };
    }
    makePublisher(rose);

    var jack = {
        eat_jack:function(){
            console.log("我陪你去吃拉面吧  ---jack");
        },
        sleep_jack:function(){
            console.log("晚安 rose  ---jack");
        },
        statusLol:function(){
            this.publish("lol");
        }
    }
    var tom = {
        eat_tom:function(){
            console.log("我买给你吧  ---tom");
        },
        sleep_tom:function(){
            console.log("今晚的太阳很好看 ---tom");
        },
        read_tom:function(){
            console.log("你也在学习js吗?");
        },
        lol_rose:function(){
            console.log("好兄弟,终于来啦");
        }
    }

    rose.addUser(jack.eat_jack,"eat");

    rose.addUser(tom.sleep_tom,"sleep");
    rose.addUser(tom.read_tom,"read");
    rose.eat();
    rose.sleep();
    rose.read();

    //设置jack成为发布者,状态(lol)
    makePublisher(jack);
    jack.addUser(rose.lol_rose,"lol");
    jack.addUser(tom.lol_rose,"lol");
    jack.statusLol();

</script>

备忘模式(函数结构缓存)

特定场合:

  • 计算的函数f()
  • 某些参数需要进行大规模反复的计算,可以考虑吧计算的结果保存起来
    f(n) ..... =>1000m
    代码中某些参数可能会反复计算
    f(10) ===>ssddd
    f(10) ===>ssddd

使用一个缓存对象cacheObj{key-value}

  • 思路:

1.提供一个全局的对象(缓存对象),key-value
2.当我们传递参数需要进行计算(逻辑)的时候,先检查缓存对象中是否有对应的结果
3.如果有缓存数据,那么就直接使用(可以节省时间,提高效率)
4.如果没有缓存数据,那么这个时候再执行计算操作,处理得到结果之后,把这个数据保存起来
5.函数的参数作为缓存对象的key,把函数计算的结果作为这个key对应的值

  • 示例代码 :
<script>
    var cache = {};
    function f1(str){
        //.....
        if (cache[str] != undefined)
        {
            console.log("已经存在缓存数据,直接返回");
            return cache[str];
        }
        //....如果缓存中有数据,那么函数体后面的代码就不再执行(节省时间)

        //执行耗时操作...
        var result = str + " hello world!";
        cache[str] = result;
        console.log("第一次调用函数传入参数,返回结果");
        return result;
    }

    console.log(f1("demo"));   //
    console.log(f1("demo"));   //
    console.log(f1("demo"));
</script>
<script>
    function f1(str){
        //.....
        if (f1.cache[str] != undefined)
        {
            console.log("已经存在缓存数据,直接返回");
            return f1.cache[str];
        }
        //....如果缓存中有数据,那么函数体后面的代码就不再执行(节省时间)

        //执行耗时操作...
        var result = str + " hello world!";
        f1.cache[str] = result;
        console.log("第一次调用函数传入参数,返回结果");
        return result;
    }

    f1.cache = {};
    console.log(f1("test"));  //
    console.log(f1("test"));   //
    console.log(f1("test"));
</script>

命名空间模式:

写法:就是把所有的东西都写在一个对象里面.

命名:命名空间的名称一般是项目的名称或者是简写,要求所有的字符都大写

  • 示例代码 :
<script>
    //01 普通的变量
    var a = "a";
    var b = "b";

    //02 对象
    var obj = {
        name:"xxx"
    }

    function func (){
        console.log("func");
    }

    function Person(){
        this.name = "默认的名称";
    }
    function func (){
        console.log("func");
    }
</script>
<script>
    var MOMO = {};
    //01 普通的变量
    MOMO.a = "a";
    MOMO.b = "b";

    //02 对象
    MOMO.obj = {
        name:"zahngsan"
    }

    MOMO.func = function(){
        console.log("func");
    }

    MOMO.Person = function(){
        this.name = "默认的名称";
    }

    console.log(new  MOMO.Person());
</script>
<script>
//    var MOMO ={};
//    MOMO.obj = {
//        name:"张三"
//    };
//
//    MOMO.obj = "demodede";

    //在使用或者是对属性进行赋值之前,会先做一个检查(检查改属性或者是方法是否存在)
    //var MOMO = {};  不推荐

    //02 更安全的处理方式:麻烦
//    if (MOMO == undefined)
//    {
//        var MOMO = {};
//    }

    var MOMO = MOMO || {};      //逻辑或 如果MOMO为真那么返回MOMO,否则就返回{}
    //if (MOMO.name == undefined)
    if ( typeof MOMO.name == 'undefined')
{
    MOMO.name = "测试的名称";
}

    if ( typeof MOMO.age == 'undefined')
    {
        MOMO.age = 20;
    }

    //100属性

</script>

通用的命名空间函数

在命名空间上面提供一个方法(nameSpace)

  • 得到调用函数传入的字符串
  • 把字符串转换为字符串数组
  • 把MOMO最外层去掉(删除)
  • 遍历
  • 示例代码 :
<script>
    var MOMO = MOMO || {};
    MOMO.namespace = function(stringParam){
        var str = stringParam;
        var parts = str.split(".");   //根据字符串切割字符串变成一个数组
        var parent = MOMO;

        console.log(parts);

        if(parts[0] == "MOMO")
        {
            parts = parts.slice(1)    //作用:删除第一个元素返回一个新的数组
        }

        for (var i = 0; i < parts.length; i++) {
            //MOMO.name
            //name.des
            //des.abc
            if (parent[parts[i]] == undefined)
            {
                parent[parts[i]] = {};
            }
            //更新父节点
            parent = parent[parts[i]];
        }
    }

    MOMO.namespace("MOMO.name.des.abc");
    console.log(MOMO);

    MOMO.namespace("MOMO.a.b.c.d.e.f.d.g.h.j.k.s.d.g.h.j.a.s.d.f.we.r");
    console.log(MOMO);
    MOMO.namespace("abc.des.abc");
    console.log(MOMO);
</script>

截至今日,面向对象和JavaScript进阶内容已经全部更新完毕! 内容是比较详细的,只要跟着每一篇的博文仔细学习,比你看网上的垃圾视频强多了 ! 理论和实践相结合 更多的是得动手去敲,以后还请大家多多关注更新,日后定会上一些新颖的东西和大家见面 !


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • 老刘最近把朋友圈关了。 我打电话给他约他出来吃饭,问他:“你这么一个不安分的人,怎么突然一下子把朋友圈关了?” 老...
    大猫卡门阅读 454评论 0 0
  • 参加于斯的文化培训课听了韩冰老师的599,方百里老师的指法练习教材,还有宋涵老师的小汤等教材,受益很多,每位老师都...
    胡美美阅读 811评论 0 3
  • 不知从何时开始,“宫寒”一词闯入女人们的生活。 不管是小到月经不调、痛经,还是大到不孕不育,除了癌症,几乎所有妇科...
    沐晨雨rara阅读 1,238评论 0 0
  • 今天上班第一天,我就长了个记性,妈呀我的小电驴居然追尾人家,伤心π_π,我还重重摔了一跤,摔在地上的时候我还起不来...
    言如心阅读 207评论 0 0