# 剑指前端(前端入门笔记系列)——设计模式

一、设计模式

1.1 什么是设计模式

  一套经过反复使用、多人知晓的、经过分类的、代码设计经验的总结

1.2 为什么使用设计模式:

  为了代码的可重用性、让代码更容易被他人理解、保证代码的可靠性。设计模式使代码的编写真正的工程化;设计模式是软件工程的基石脉络,如同大厦的结构

1.3 有哪些设计模式(来自W3Cschool,23种):

  构造器模式,模块化模式,暴露模块模式,单例模式,中介者模式,原型模式,命令模式,外观模式,工厂模式,Mixin模式,装饰模式,亨元(Flyweight)模式,MVC模式,MVP模式,MVVM模式,组合模式,适配器模式,外观模式,观察者模式,迭代器模式,惰性初始模式,代理模式,建造者模式

二、单例模式

  单个实例,只有一个对象

//多次创建,返回同一个对象
function fn(){
    if(!fn.obj) { //给函数添加一个属性。 因为函数是全局的,所以该属性一旦添加一直存在;
         fn.obj = {
             name : “liyang"
         };
    }
    return fn.obj;
}
var obj1 = new fn();
var obj2 = new fn();
console.log(obj1 == obj2);

//例如我们创建一个信息提示框,每一次执行toast方法,如果都创建一个新的元素,这样做太浪费了。
//因此,我们采取单例模式,确保无论调用多少次toast方法,都只创建一个DOM元素。
//我们只控制它的显示和隐藏,而不是每次创建每次销毁。

function Toast(){
    var div = document.createElement("div");
    div.className = "box";
    document.body.appendChild(div);
    setTimeout(function(){
        div.remove();
    },1000)
}

obtn.onclick = function(){
    var a = new Toast();

    var b = new Toast();

    console.log(a == b)
}

function Toast(){
    if(!Toast.div){
        Toast.div = document.createElement("div");
        Toast.div.className = "box";
        document.body.appendChild(Toast.div);
            clearTimeout(Toast.div.timer);
            Toast.div.timer = setTimeout(function(){
            Toast.div.style.display = "none";
        },1000)
    }else{
        Toast.div.style.display = "block";
        clearTimeout(Toast.div.timer);
            Toast.div.timer = setTimeout(function(){
            Toast.div.style.display = "none";
        },1000)
    }
    return Toast;
}
obtn.onclick = function(){
    var a = new Toast();
    var b = new Toast();
    console.log(a == b);
}

三、组合模式

  把多个对象组成树状结构来表示局部与整体,使得用户可以同时操作单个对象和对象的组合。

  • 可以以相同的方法处理对象的集合与其中的特定子对象。组合对象与组成该对象的对象可实现同一批的操作,对组合对象执行的操作会向下传递到所有的组成对象,使得所有组成对象都会执行同样的操作。
  • 可以将对象组织成树状结构,并且使整棵树可被遍历,所有组合对象都实现一个用来获取其子对象的方法,借助该方法可以隐藏实现的细节,组织子对象,使子对象内部的实现不形成依赖

  对于创建动态用户界面来说,组合模式可以算是为其量身定做的,因为HTML结构正好符合组合模式适用场景的结构。

  • 存在一批组织成某种层次体系的对象
  • 希望对这批对象或者其中某一部分对象实施一个操作
    组合模式擅长对大批量对象进行操作,转为组织这类对象把操作从一个层次向下一个层次传递设计,借此可以弱化对象间的耦合关系并且可以互换使用一些类或者实例,使代码模块化程度更高,维护更容易。
function ImagesStore( id ){
    this.children = [];
    this.element = document.createElement("div");
    this.element.id = id;
    this.element.className = "imgs-store";
    document.body.appendChild(this.element)
}
ImagesStore.prototype = {
    constructor : ImagesStore,
    add:function( child ){
        this.children.push( child );
        this.element.appendChild( child.getElement() );
    },
    remove:function( child ){
        for( var node, i=0; node = this.getChild(i); i++ ){
            if( node === child ){
                this.children.splice( i, 1 );
                break;
            }
        }
        this.element.removeChild( child.getElement() );
    },
    getChild:function( i ){
        return this.children[i];
    },
    show:function(){
        this.element.style.display = '';
        for( var node, i=0; node = this.getChild(i); i++ ){
            node.show();
        }
    },
    hide:function(){
        for( var node, i=0; node = this.getChild(i); i++ ){
            node.hide();
        }
        this.element.style.display = 'none';
    },
    getElement:function(){
        return this.element;
    }
}
    //上面的组合对象中我们可以看出,原型上的hide和show方法不单单是对于当前element进行处理,还延伸到其包含的每一个叶对象上执行。这边就体现了组合模式的运行机制,一条命令在多个对象上激发复杂的或者递归的行为。


function ImageItem( src ){
    this.element = document.createElement("img");
    this.element.src = src;
    this.element.className = "img-item";
}
ImageItem.prototype = {
    constructor:ImageItem,
    add:function( child ){
        console.log("this is image object, no add function");
    },
    remove:function( child ){
        console.log("this is image object, no remove function");
    },
    getChild:function( i ){
        console.log("this is image object, no getChild function");
    },
    show:function(){
        this.element.style.display = '';
    },
    hide:function(){
        this.element.style.display = 'none';
    },
    getElement:function(){
        return this.element;
    }
}

  使用组合模式组织起来的对象具有出色的层次结构,每当对顶层组合对象执行一个操作的时候,实际上是在对整个结构进行深度优先的节点搜索。但是这些优点都是用操作的代价换取的,比如每次顶级执行一次show方法,实际的操作就是整个树形结构的节点都会被遍历一次。但是组合对象的每个对象之间的耦合非常松散,可以简单的操作处理复杂的结果。
  简单的说,组合模式是讲一批子对象组织为树形结构,一条顶层的命令会在操作树中所有的对象。提高了代码的模块化程度,对于动态的HTML界面具有很强的适用性

四、观察者模式

  观察者模式又叫发布订阅模式(Publish/Subscribe),它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,这个主题对象的状态发生变化时就会通知所有的观察者对象,使得它们能够自动更新自己。

使用观察者模式的好处:

  • 支持简单的广播通信,自动通知所有已经订阅过的对象。
  • 页面载入后目标对象很容易与观察者存在一种动态关联,增加了灵活性。
  • 目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

代表案例:看孩子还是打麻将

五、代理模式

  代理模式分成两个部分,一个部分是本体; 即为你想要实现的功能;另一部分为代理;代理可以代替本体实例化;
  代理一般使用在非常耗时的数据上,也会用在体积十分庞大的本体上。
  一句话总结代理模式:为其他对象提供代理,以控制这个对象的访问;
  举个简单的例子:
  小伙子想要送花给小姑娘,但是不好意思送,于是找到了快递小哥,小哥帮忙送花;在这里小哥就是代理!

//小姑娘(姑娘的名字);

var girl = function(name){
    this.name = name;
}

//小伙子(想要送给谁);

var boy = function(girl){
    this.girl = girl;
    this.sendGift = function(gift){
        alert("你好,漂亮的"+this.girl.name+",这是我送你的:"+gift);
    }
}
//快递小哥(知道送给谁);

var porxyLitterBrother = function(girl){
    this.girl = girl;
    this.send = function(gift){
        gift = "一个吻";
        (new boy(girl)).sendGift(gift);
    }
}

  现在的送花就变得简单了;

var porxy = new porxyLitterBrother(new girl("花花"));
porxy.send("钻戒");

  一个人替你去做一些事情。 这个人保不齐还能捞点好处, 这就是代理模式;

六、适配器模式

//我们要对所有产品都进行一个标准化的测试,测试流程其中包括了
电话、短信、游戏、音乐等等功能
 
//但是对于一个平板来说,电话功能是无法使用的,因此测试会出问题。
  所以将平板进行了包装(类似于代理)
 
//这样就简单的解决了兼容问题
function test(product) {
    try {
         product.phonecall();
    } catch(e) {
         console.log("电话功能测试失败!")
    }
    try {
         product.playgame();
    } catch(e) {
         console.log("游戏功能测试失败!")
    }
}
 
function Phone(){
    this.phonecall = function(){}
    this.playgame = function(){}
    this.toString = function(){
         return "电话";
    }
}
function Pad(){
    this.playgame = function(){}
    this.toString = function(){
         return "平板";
    }
 
}
//适配器的意义,多数应用在系统接口使用,也就是别人提供了一个功能,但要求传入一个A类型的参数
//而我们手里的数据是B类型的,如果我们想使用这个功能。那么有两种解决办法:
//第一,把自己的原代码进行修改,让B类型改为A类型,这是非常蠢的做法。
//第二,我们把B类型的数据进行一个包装,让它看起来符合类型A,这个包装函数,就是适配器。
 
function Adapter(product){

    this.phonecall = function(){
         if(product.phonecall) {
             product.phonecall();
         } else {
             console.log("this "+ product.toString() + " is not support function phonecall!")
         }
    }
    this.playgame = function(){
         if(product.playgame) {
             product.playgame();
         }
    }
}
test(new Phone());
test(new Adapter(new Pad()));

七、抽象工厂模式

7.1 什么是工厂模式

  产出对象,创建类的一种设计模式。

7.2 为什么要用工厂模式

  当有需求要大量出产相似对象的时候需要用到工厂模式。

7.3 工厂模式怎么用

  创建对象使用的设计模式, 主要分成原料,加工和出厂三个部分。

// 想要创建一个对象,对象名为car;
var car = {};
// 想要对car进行组装, 有轮子,和发动机。
car.wheel = "15";
car.engine = "V8";
// 一个车对象产生了。 
// 我们能看到的对象大概是这样的。 
car { 
    wheel : 15,
    engine : V8
}

  这就是一个实用的对象,而现在我们需求升级, 我们需要制造出各种各样不同的车,12寸轮廓的,V6发动机的,各种各样的组合,那么怎么出产这样的抽象汽车对象
  我们需要有一个模型, 也就是这个模具构建了这个车大概的样子, 类似于一张设计图。 详细的信息我们根据需求在后续事件为其添加内容 。
  这种模式,就是所谓的抽象工厂模式。当然工厂模式是有固定的模式的,这个模式大概是这个样子的。

var factory = (function(){
    var car = function (wheel,engine){ //内部配置函数,可以提供配置功能。
        this.wheel = wheel;
        this.engine = engine;
    }
    return function(wheel , engine){ // 构造器, 负责创建对象。  // 这是对外提供的接口, 负责和外部需求连接。 
        return new car(wheel,engine);
    }
})()
发布了24 篇原创文章 · 获赞 43 · 访问量 9797

猜你喜欢

转载自blog.csdn.net/weixin_37844113/article/details/100824211
今日推荐