02-JS设计模式

6/28/2001

# 一. 观察者设计模式

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div id="box"></div>
    <script src='js/jquery-3.2.1.min.js'></script>
    <script>
        // 观察者设计模式   基于发布订阅  
        //   观察者      Foreign
        //   被观察者    RMB    需要保存观察者
        // 人民币类
        function RMB() {
            // 创建人民币输入框的dom
            this.$dom = $("<div><span>人民币:</span><input type='text'/></div>");
            // 追加节点
            $("#box").append(this.$dom)
            // 保存了观察者(订阅者)
            // 在被观察者中保存了所有观察者
            this.subscribes = [];
            // 初始化监听
            this.bindEvent();
        }
        RMB.prototype.subscribe = function(obj) {
            this.subscribes.push(obj)
        }
        RMB.prototype.bindEvent = function() {
            let that = this;
            this.$dom.find("input").bind("input", function() {
                // 通知所有的观察者重新计算
                for (let i = 0; i < that.subscribes.length; i++) {
                    that.subscribes[i].update($(this).val());
                }
            })
        }
        var rmb = new RMB()

        // 外币类
        function Foreign(title, rate) {
            this.title = title;
            this.rate = rate;
            // 外币的dom
            this.$dom = $("<div><span>" + this.title +
                ":</span><input disabled type='text'/></div>");
            $("#box").append(this.$dom);

            rmb.subscribe(this)
        }
        Foreign.prototype.update = function(val) {
            let res = val / this.rate;
            this.$dom.find("input").val(res)
        }
        new Foreign("美元", '6.5');
        new Foreign("英镑", '8.7');
        new Foreign("日元", '0.063');
        new Foreign("韩元", '0.0058');
    </script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

# 二. 单例设计模式

<!-- 
    JS实现单例设计模式:
        一个类限制必须只能有一个实例,如果第二次创建的时候,
        我们可以抛出错误或者返回第一次的实例。
 -->
1
2
3
4
5
<script>
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    let malu = new Person("码路", 17); // 码路
    let manman = new Person("漫漫", 15); // 漫漫
    console.log(malu);
    console.log(manman);
</script>
1
2
3
4
5
6
7
8
9
10
<script>
    let Person = (function() {
        let instance = null;
        return function(name, age) {
            this.name = name;
            this.age = age;
            if (instance) {
                return instance;
            }
            return instance = this;
        }
    })();
    Person.prototype.sayHello = function() {
        console.log(this.name);
    }
    let malu = new Person("码路", 17); // 码路
    let manman = new Person("漫漫", 15); // 漫漫
    console.log(malu);
    console.log(manman);
    console.log(malu === manman);
    malu.sayHello();
    manman.sayHello();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
    // new Person并不是单例的
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype.sayHello = function() {
        console.log(this.name);
    }

    // 创建一个代理类,实现单例设计模式
    let PersonProxy = (function() {
        let instance = null;
        return function(name, age) {
            if (instance) {
                return instance;
            }
            return instance = new Person(name, age)
        }
    })()

    let malu = new PersonProxy("码路", 17); // 码路
    let manman = new PersonProxy("漫漫", 15); // 漫漫
    console.log(malu);
    console.log(manman);
    console.log(malu === manman);
    malu.sayHello();
    manman.sayHello();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 三. 组合设计模式

<script>
    // 组合模式:
    //  组合模式就是一组任务的顺序组合,也就是命令(任务)清单。
    //  组合模式的设计哲学就是将单独的命令(任务)通过组合串联起来,形成顺序的程序列表。

    // 任务清单
    let coding = {
        execute: function() {
            console.log("coding");
        }
    }
    let playgame = {
        execute: function() {
            console.log("playgame");
        }
    }
    let eat = {
        execute: function() {
            console.log("eat");
        }
    }
    let basketball = {
        execute: function() {
            console.log("basketball");
        }
    }
    let meeting = {
        execute: function() {
            console.log("meeting");
        }
    };
    // 工作相关的  把上面的部分任务组合成一个列表
    let work = {
        commands: [meeting, coding, eat],
        execute() {
            for (let i = 0; i < this.commands.length; i++) {
                this.commands[i].execute();
            }
        }
    }
    // 娱乐相关的
    let yule = {
        commands: [eat, playgame, basketball],
        execute() {
            for (let i = 0; i < this.commands.length; i++) {
                this.commands[i].execute();
            }
        }
    }
    // 把把两个组合后的任务,继续组合成一个大任务
    let allDay = {
        commands: [work, yule],
        execute() {
            for (let i = 0; i < this.commands.length; i++) {
                this.commands[i].execute();
            }
        }
    }
    // work.execute();
    // yule.execute();
    allDay.execute();
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 四. 工厂设计模式

<script>
    // 简单工厂
    //    有一个工厂函数创建对象,而不是new出来的,是创建对象的方式之一

    // 下面的代码就是简单的工厂的创建
    // 工厂函数
    function createPerson(name, age, sex) {
        return {
            name: name,
            age: age,
            sex: sex,
            sayHello: function() {
                console.log("你好我是" + this.name + "今年" + this.age + "岁了,我是一个" + this.sex)
            }
        }
    };
    // malu  和  manman 都是Object的实例
    // 它们没有自己的对应的构造器
    var malu = createPerson("码路", 12, '男生');
    var manman = createPerson("漫漫", 13, "女生")
    console.log(malu);
    malu.sayHello();
    console.log(manman);
    manman.sayHello();
    console.log(malu instanceof Object);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script>
    // 构造器函数
    function Car(color, doors) {
        this.color = color;
        this.doors = doors;
    }
    Car.prototype.sayHello = function() {
        console.log("你好,我是小汽车,我的颜色是" + this.color + "色,一共有" + this.doors + "个门");
    }

    // 工厂函数
    function createCar(color, doors) {
        return new Car(color, doors)
    }
    let car1 = createCar("红", 2);
    let car2 = createCar("黑", 4);
    console.log(car1);
    console.log(car2);
    console.log(car1 instanceof Car);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
    // 普通工厂
    // 小汽车
    function Car(color, doors) {
        this.color = color;
        this.doors = doors;
        return this
    }
    // 大卡车
    function Trank(weight) {
        this.weight = weight;
        return this;
    }
    // 增强工厂函数
    // 可以创建各种各样的对象
    function createVihicle(type) {
        // 根据type进行判断,到底要创建什么样的对象
        if (type === "Car") {
            return Car.apply(new Car(), [].slice.call(arguments, 1))
        } else if (type === "Trank") {
            return Trank.apply(new Trank(), [].slice.call(arguments, 1))
        }
    }

    var xiaoqiche = new createVihicle("Car", "red", 4);
    var dakache = new createVihicle("Trank", 500)
    console.log(xiaoqiche)
    console.log(dakache)
    console.log(xiaoqiche instanceof Car)
    console.log(dakache instanceof Trank);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script>
    // 抽象工厂就是提供一个注册方法,然后实例这个类。
    //  工厂维护一个类的清单,我们用一个对象来维持当前的所有的类内容,注册的时候可以提供预审查功能。
    //  比如我们要求所有的注册类都必须要有update和render方法,否则不允许注册

    // 构造函数
    function Duck(color, age) {
        this.color = color;
        this.age = age;
        return this;
    }
    Duck.prototype.update = function() {}
    Duck.prototype.render = function() {}

    // 构造函数
    function Chicken(color) {
        this.color = color;
        return this;
    }
    Chicken.prototype.update = function() {}
    Chicken.prototype.render = function() {}

    // 定义一个工厂函数
    var Factory = (function() {
        let types = {}; // 存储不同的构造函数,不同角色
        return {
            // 进行注册
            // 在注册时,可以进行预审查
            registFactory(type, typeFunction) {
                if (!typeFunction.prototype.update || !typeFunction.prototype.render) {
                    throw new Error(type + "类型没有注册成功,请设置update和render方法后,再进行注册")
                    return
                }
                // 给types对象注册方法
                types[type] = typeFunction
            },
            // 创建对象  生成对象
            careateActor(type) {
                return types[type].apply(new types[type](), [].slice.call(arguments, 1))
            }
        }
    })();
    // 注册
    Factory.registFactory("Duck", Duck);
    Factory.registFactory("Chicken", Chicken);

    // 实例,必须要先注册才能进行实例
    var yazi = Factory.careateActor("Duck", "黄", 1)
    var xiaoji = Factory.careateActor("Chicken", "红")
    console.log(yazi)
    console.log(xiaoji)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

# 五. 装饰者模式

<script>
    // 装饰者模式
    //  不改变原来的类,并且不使用继承,把一个类的进行增强

    // 案例:
    //     比如现在有一个学生类,他有一个方法学习,
    //     学习内容是html,css,js
    //     码路就是这个学生的实例

    function Student() {}
    Student.prototype.study = function() {
        console.log("html")
        console.log("css")
        console.log("js")
    };

    // 定义一个装饰类,对Student类进行增强
    function ZhuangShi(sombody) {
        this.sombody = sombody
        this.sombody.xixi = "xixi~"
        return this.sombody;
    }
    var malu = new Student();
    malu = new ZhuangShi(malu);
    console.log(malu.xixi);
    console.log(malu instanceof Student);
    console.log(malu instanceof ZhuangShi);
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 六. 代理设计模式

<script>
    // 代理设计模式
    //    有通告需要找到明星, 先找到经纪人,不能直接和明星直接接触,经纪人进行筛选后,然后在和明星进行沟通。
    //    经纪人的所作就是代理类的作用

    // 案例:
    //     码路同学要送花给小㺯

    // 没有使用代理
    function Flower(name) {
        this.name = name
    }
    var malu = (function() {
        var flower = new Flower('玫瑰花');
        return {
            name: '码路',
            sendFlower: function(target) {
                // 送的目标
                target.getFlower(flower, this)
            }
        }
    })()
    var xiaomei = {
        getFlower: function(flower, person) {
            console.log("小美收到了" + person.name + '的' + flower.name)
        }
    }
    malu.sendFlower(xiaomei)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<script>
    // 突然有一天,小美和码路同学生气了,码路为了哄小红开心,想送小美礼物,
    // 但是此时小美由于还在生码路的气,所以不会搭理码路。
    // 此时码路想到了小美的闺蜜,让她做代理,然后把礼物送给小美的闺蜜,让闺蜜适时送给小美

    function Flower(name) {
        this.name = name
    }
    var malu = (function() {
        var flower = new Flower('玫瑰花');
        return {
            name: '码路',
            sendFlower: function(target) {
                target.getFlower(flower, this)
            }
        }
    })();

    // guimi就是一个代理
    var guimi = (function() {
        return {
            name: "闺蜜",
            flower: null,
            sendPeron: null,
            getFlower(flower, person) {
                this.flower = flower.name;
                this.sendPeron = person.name;
                console.log("闺蜜收到了" + person.name + "的" + flower.name);
            },
            getState(state) {
                if (state === "心情很好" && this.flower) {
                    xiaomei.getFlower(this.flower, this.sendPeron);
                }
            }
        }
    })()

    var xiaomei = (function() {
        var state;
        var timer = setInterval(function() {
            if (Math.random() > 0.5) {
                state = '心情很好'
            } else {
                state = '心情不好'
            }
            guimi.getState(state)
        }, 1000)
        // guimi.getState(state)
        return {
            getFlower: function(flower, person) {
                // 接收自闺蜜转接的礼物
                console.log("小美收到了来自闺蜜转接自" + person + "的" + flower)
            }
        }
    })();
    malu.sendFlower(guimi)
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0px;
            padding: 0px;
        }

        body {
            background-color: skyblue;
        }

        img {
            width: 100px;
            height: 100px;
        }
    </style>
</head>

<body>
    <script>
        // 代理类实现图片loading
        function MyImage(src) {
            // 创建节点
            this.oImg = document.createElement("img");
            // 节点上树
            document.body.appendChild(this.oImg);
        }
        MyImage.prototype.setSrc = function(src) {
            this.oImg.src = src;
        };
        // 代理类
        function MyImageProxy(src) {
            this.myImage = new MyImage();
            this.myImage.setSrc("./images/loading.gif");

            // image相当于一个钩子
            var image = new Image();
            image.src = src;
            var that = this;
            image.onload = function() {
                that.myImage.setSrc(src)
            }
        }
        new MyImageProxy("./images/0.jpg")
        new MyImageProxy("./images/1.jpg")
        new MyImageProxy("./images/2.jpg");
    </script>
</body>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

# 七. 装饰者模式


1

# 六. 装饰者模式


1

# 六. 装饰者模式


1
Last Updated: 12/25/2022, 10:02:14 PM