代码的设计模式

① 定义:是一套经过反复使用、多人知晓的、经过分类的、代码设计经验的总结
② 为什么使用设计模式?
    1.为了代码的可重用性、更容易被他人理解、保证代码的可靠性
    2.设计模式使代码的编写真正的工程化,是软件工程的基石脉络,如同大厦的结构
③ 有哪些?
     构造器模式,模块化模式,暴露模块模式,单例模式,中介者模式,原型模式,命令模式,外观模式,工厂模式,Mixin模式,装饰模式,亨元(Flyweight)模式,MVC模式,MVP模式,MVVM模式,组合模式,适配器模式,外观模式,观察者模式,迭代器模式,惰性初始模式,代理模式,建造者模式

一、单例模式 

特点:单个实例 每次new处理都是一个实例

利用new的原理,主动返回对象(不能用this和原型)
    function Fn() {
        if (!Fn.obj) {
            Fn.obj = {};
            Fn.obj.__proto__ = Fn.prototype;  // 需要使用原型的时候,手动创建原型链
        }
        Fn.obj.abc = "ggg";
        return Fn.obj;   // 主动返回对象(上的obj属性 格式好点) 可以const Fn.obj为变量that
    }
    Fn.prototype.show = function() {
        console.log(12345678);
    }
    var f1 = new Fn();
    var f2 = new Fn();
    console.log(f1 === f2); //true才是单例模式
    f1.show();   // 手动创建原型链后才能获得show

(new原理)

1. 创建了一个新对象

2. 修改了函数的this, 指向第一步创建的新对象

3. 修改了新对象的原型链(__proto__), 指向了函数的prototype

4. 检测函数是否主动返回对象, 如果没有, 主动返回新对象

栗子:弹出框(始终都是一个提示框 节约内存)

   <!-- <dialog>提示框 默认隐藏 </dialog> -->
    <input type="button" value="信息" id="btn1">
    <input type="button" value="成功" id="btn2">
    <input type="button" value="失败" id="btn3">
    <input type="button" value="警告" id="btn4">
    const obtn1 = document.getElementById("btn1");
    const obtn2 = document.getElementById("btn2");
    const obtn3 = document.getElementById("btn3");
    const obtn4 = document.getElementById("btn4");

    obtn1.onclick = function() {
        new Toast({
            message: "信息",
            type: "info"
        })
    }
    obtn2.onclick = function() {
        new Toast({
            message: "成功",
            type: "success"
        })
    }
    obtn3.onclick = function() {
        new Toast({
            message: "失败",
            type: "error"
        })
    }
    obtn4.onclick = function() {
        new Toast({
            message: "警告",
            type: "warning"
        })
    }

    function Toast(ops) {
        if (!Toast.obj) {
            Toast.obj = {};
            Toast.obj.ele = document.createElement("dialog");
            document.body.appendChild(Toast.obj.ele);
        }
        const that = Toast.obj;
        that.ele.innerHTML = ops.message;

        let color = "";
        if (ops.type === "info") {
            color = "#55f";
        } else if (ops.type === "success") {
            color = "#5f5";
        } else if (ops.type === "error") {
            color = "#f55";
        } else if (ops.type === "warning") {
            color = "yellowgreen";
        }
        // 统一设置css格式
        that.ele.style.cssText = `border-color:${color};color:${color};display:block`;

        clearTimeout(that.t);
        that.t = setTimeout(() => {
            that.ele.style.display = "none";
        }, 2000);
        return that;
    }

二、观察者模式(发布订阅者模式)

1.发布:被观察者,主题对象
2.订阅:观察者
3.一个主题对象发布或更新信息,多个订阅者接收信息,并根据信息作出不同的功能处理
4.可以实现广播通信,一对多关系,耦合低

    // 发布者
    // 定义的时候接受参数
    function stu(name) {
        this.name = name;
        this.send = function(type) {
            this.type = type;
        }
    }
    // 观察者
    function 讲师() {
        this.listen = function(t) {
            switch (t) {
                case "睡觉":
                    console.log("叫醒 揍一顿");
                    break;
                case "学习":
                    console.log("好棒");
                    break;
                case "玩游戏":
                    console.log("制止 揍俩顿");
                    break;
            }
        }
    }

    function 班主任() {
        this.listen = function(t) {
            switch (t) {
                case "睡觉":
                    console.log("叫醒 去喝茶");
                    break;
                case "学习":
                    console.log("好棒棒");
                    break;
                case "玩游戏":
                    console.log("走 一起玩");
                    break;
            }
        }
    }

    function 校长() {
        this.listen = function(t) {
            switch (t) {
                case "睡觉":
                    console.log("叫班主任");
                    break;
                case "学习":
                    console.log("好棒!");
                    break;
                case "玩游戏":
                    console.log("制止 叫班主任");
                    break;
            }
        }
    }

    function 行政(s) {
        this.listen = function(t) {
            console.log(s.name + t + "拍照");
        }
    }
    // new的时候传入参数
    const s = new stu("张三");
    s.send("睡觉");

    const ly = new 讲师();
    ly.listen(s.type);

    const clb = new 班主任();
    clb.listen(s.type);

    const xz = new 校长();
    xz.listen(s.type);

    const jz = new 行政(s);
    jz.listen(s.type);

三、适配器模式

1.假如现有数据A 和功能B,功能B只能接受B类型的数据,可是现有数据类型是A
2.此时需要一个适配器,将数据A进行一层包装,让数据A看起来像 B类型的数据

  // 手机:打电话 玩游戏
    function Phone(n) {
        this.name = n;
        this.call = function() {
            console.log("打电话");
        }
        this.game = function() {
            console.log("玩游戏");
        }
    }
    // 平板:玩游戏
    function Pad(n) {
        this.name = n;
        this.game = function() {
            console.log("玩游戏");
        }
    }

    // 测试模块:打游戏 玩游戏
    function test(o) {
        o.call();
        o.game();
    }

    const p1 = new Phone("大米");
    const p2 = new Pad("橘子");

    // 适配器包装
    function fn(o) {
        o.call = function() {
            console.log("这是一个平板,不能打电话");
        }
        return o;
    }
    // phone可以直接测试
    test(p1);
    // pad需要经过适配器的包装之后才能测试
    test(fn(p2));

 四、代理模式

1.系统功能A在调用系统功能B的过程中,为了传输数据,我们需要记录数据、改写数据、拦截数据
2.先断开执行,获取系统功能B的执行权限,编写代理程序执行功能B,让功能A调用代理程序,将原有的数据,发给代理程序,代理程序将数据发给功能B(A-代理-B)

    // B
    function Girl(n) {
        this.name = n;
    }
    // A
    function Boy(girl) {
        this.name = "张三";
        this.girl = girl;
        this.send = function(msg) {
            console.log(`你好,${this.girl.name},这是我送你的${msg}`);
        }
    }
    // 代理
    function porxyLitterBrother(girl) {
        // 小本本记录
        this.messages = [];
        this.girl = girl;
        this.send = function(msg) {
            // console.log(msg); 查看
            // msg = "一束花"; 修改

            const b = new Boy(this.girl);
            // 拦截并记录
            this.messages.push({
                收件人: this.girl.name,
                寄件人: b.name,
                time: Date.now(),
                msg: msg
            })
            b.send(msg);
        }
    }

    const g = new Girl("翠花");
    const p = new porxyLitterBrother(g);
    p.send("一封信");

五、 策略模式

1.根据程序执行过程中产生的不同的状态或信息,决定后续的功能执行
2.利用不同的功能接口(方法)决定不同的功能(降低if-else)

 const Obj = {
        getBanner: function() {
            return "获取到了轮播图数据";
        },
        getGoods: function() {
            return "获取到了商品数据";
        },
        getMenu: function() {
            return "获取到了菜单数据";
        }
    }

    function getData(type) {
        // if (type === "getBanner") {
        //     Obj.getBanner();
        // }
        // 减少使用if-else
        return Obj[type]();
    }
    console.log((getData("getBanner")));

六、组合模式

1.按照一定的组织关系,将多个对象进行组合
      - 树状关系(html结构)
2.组合模式就是为动态的html而生的
3.组合模式为了能实现批量操作,节省操作过程,使用了递归的思想,所以消耗比较大的性能
4.利用组合器将对象组合起来
   - 枝对象:只要具有子对象,无论层级在哪 都是枝对象 (操作枝 里面所有都被操作)
   - 叶对象:只要不具有子对象,无论层级在哪 都是叶对象

    // 枝和叶 功能要一一对应

    // 枝对象的类:div
    class Team {
        constructor(id) { //接收传入的id名 imgbox1,2
            this.ele = document.createElement("div"); //ele指创建的div
            this.ele.id = id;
            this.children = []; //保存叶
        }
        add(child) { //接收叶传入 child就是Item
            this.children.push(child);
            // 叶从属于某个枝 让枝保存叶   叶的img插入到枝的div
            this.ele.appendChild(child.ele);
        }
        remove(child) {
            // 找到重复的叶
            let i = 0;
            this.children.some((val, idx) => {
                i = idx;
                return val === child;
            })

            // 数组中 从第i个删1位
            this.children.splice(i, 1);
            // 动态的html标签也删除
            child.ele.remove();
        }
        border() {
            this.ele.style.border = "solid 2px black";
            // 拿到所有的叶 批量设置边框
            this.children.forEach(val => {
                val.border();
            })
        }
        none() {
            this.ele.style.border = "none";
            this.children.forEach(val => {
                // 拿到所有的叶 批量删除边框
                val.none();
            })
        }
    }


    // 叶对象的类:img
    class Item {
        constructor(src) {
            this.ele = document.createElement("img");
            this.ele.src = src; //图片地址
        }
        add() {
            console.log("这是一个叶对象,无法添加子对象");
        }
        remove() {
            console.log("这是一个叶对象,无法删除子对象");
        }
        border() {
            this.ele.style.border = "solid 2px black";
        }
        none() {
            this.ele.style.border = "none";
        }
    }


    // 创建叶对象img1和2和3
    const img1 = new Item("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png");
    const img2 = new Item("https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_e835568.png");
    const img3 = new Item("https://inews.gtimg.com/newsapp_bt/0/0923142908664_4470/0");

    // 创建枝对象imgbox1和2
    const imgbox1 = new Team("imgbox1");
    const imgbox2 = new Team("imgbox2");

    // 将叶对象img1和2组合到枝对象imgbox1和2
    imgbox1.add(img1);
    imgbox2.add(img2);

    // 又创建枝对象box
    const box = new Team("box");

    // 将枝对象imgbox1和2和叶对象img3都组合到枝对象box
    box.add(imgbox1);
    box.add(imgbox2);
    box.add(img3);

    // 将最大的枝对象box直接插入到页面 box实例上的属性ele(div元素)
    document.body.appendChild(box.ele);

    // 开始批量操作
    imgbox1.border();
    box.border();
    imgbox2.none();

七、抽象工厂模式

在工厂模式的基础之上,再次对同一个实例的相同属性进行抽象,抽象成一个公共对象,再做具体的工厂模式的创建

function CreatePhone(id) {
        this.id = id;
    }
    CreatePhone.prototype.call = function() {
        console.log(this.color + this.id + "打电话");
    }

    // 抽象工厂1
    function AbstractColorWhite(id) {
        const p = new CreatePhone(id);
        p.color = "白色";
        return p;
    }
    // 抽象工厂2
    function AbstractColorPink(id) {
        const p = new CreatePhone(id);
        p.color = "粉色";
        return p;
    }
    const p1 = AbstractColorWhite("001");
    const p2 = AbstractColorWhite("002");
    const p3 = AbstractColorPink("003");
    const p4 = AbstractColorPink("004");
    console.log(p1);
    console.log(p2);
    console.log(p3);
    console.log(p4);
    p1.call();
    p2.call();
    p3.call();
    p4.call();

八、MVC模式

M:model 模型层 只负责数据的管理
V:view 视图层  只负责将来数据展示的视图的管理
C:control 控制层  负责接收用户的指令,根据指令,选中不同的模型,将模型中的数据,寄给不同的视图渲染
 -工作流程
     - 控制器接收到指令后,根据指令读取的制定模型,拿到数据
     - 控制器再根据指定获取指定的视图
     - 将第一步读取到的数据,传给获取的视图
     - 由视图负责将接收数据 渲染

 // 模型层
    class Model {
        // constructor没有可以不写
        m1() {
            return "hello";
        }
        m2() {
            return "world";
        }
    }
    // 视图层
    class View {
        v1(d) {
            console.log(d);
        }
        v2(d) {
            document.write(d);
        }
        v3(d) {
            alert(d);
        }
    }
    // 控制层
    class Control {
        constructor() {
            this.m = new Model();
            this.v = new View();
        }
        c1() {
            const d = this.m.m1();
            this.v.v2(d);
        }
        c2() {
            const d = this.m.m2();
            this.v.v1(d);
        }
    }
    const c = new Control();
    c.c1();

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值