js-day4 结构型设计模式

结构型设计模式

结构型设计模式关注于如何将类或对象组合成更大,更复杂的结构,以简化设计

Facade

外观模式,为一组复杂的子系统接口提供一个更高级的统一接口,通过这个接口使得对子系统接口的访问更加容易

document.onclick=function (ev) {
    ev.preventDefault();
    if (ev.target!==document.getElementById('myinpuy')){
        hidePageAlert();
    } 
};
function hidePageAlert() {}

外观模式实现

function addEvent(dom, type, fn) {
    if (dom.addEventListener){
        dom.addEventListener(type,fn,false);
    } else if (dom.attachEvent){
        dom.attachEvent('on'+type,fn);
    } else {
        dom['on'+type]=fn;
    }
}
let myInput=document.getElementById('myinput');
addEvent(myInput,'click',function () {
    console.log('first event');
});
addEvent(myInput,'click',function () {
    console.log('second');
});
addEvent(myInput,'click',function () {
    console.log('third');
});

解决兼容性,preventDefault和target

let getEvent=function (event) {
    return event||window.event;
};
let getTarget=function (event) {
    let ev=getEvent(event);
    return ev.target||ev.srcElement;
};
let preventDefault=function (event) {
    let ev=getEvent(event);
    if (event.preventDefault){
        ev.preventDefault();
    } else {
        ev.returnValue=false;
    }
};
function hideInputSug() {}
document.onclick=function (ev) {
    preventDefault(ev);
    if (getTarget(ev) !==document.getElementById('myinput')){
        hideInputSug();
    } 
};

小型代码库

let A={
    g:function (id) {
        return document.getElementById(id);
    },
    css:function (id, key, value) {
        document.getElementById(id).style[key]=value;
    },
    attr:function (id, key, value) {
        document.getElementById(id)[key]=value;
    },
    html:function (id, html) {
        document.getElementById(id).innerHTML=html;
    },
    on:function (id, type, fn) {
        document.getElementById(id)['on'+type]=fn;
    }
};
A.css('box','background','red');
A.attr('box','className','box');
A.html('box','new container');
A.on('box','click',function () {
    A.css('box','width','500px');
});

Adapter

适配器模式.将一个类(对象)的接口(方法或属性)转化成另一个接口,满足用户的需求,使类(对象)之间接口的不兼容问题通过适配器得以解决

let A=A||{};
A.g=function (id) {
    return document.getElementById(id);
};
A.on=function (id, type, fn) {
    let dom=typeof id==='string'?this.g(id):id;
    if (dom.addEventListener){
        dom.addEventListener(type,fn,false);
    } else if (dom.attachEvent){
        dom.attachEvent('on'+type,fn);
    } else{
        dom['on'+type]=fn;
    }
};
A.on(window,'load',function () {
    A.on('mybutton','click',function () {});
});
A.g=function (id) {
    return $(id).get(0);
};
A.on=function (id, type, fn) {
    let dom=typeof id==='string'?$('#'+id):$(id);
    dom.on(type,fn);
};

参数适配器

方法需要传递多个参数时,可传递多个参数

function dosomething(name,title,age,color,size,price) {}
let obj={
    name:'name',
    title:'title',
    age:'age',
    color:'color',
    size:'size',
    prize:'prize'
};
function dosomething(obj) {
    let _adapter={
        name:'name',
        title:'title',
        age:'age',
        color:'color',
        size:'size',
        prize:'prize'
    };
    for (let i in _adapter){
        _adapter[i]=obj[i]||_adapter[i];
    }
}

数据适配

将数组适配成对象

let arr=['javascript','book','html','8.1'];
let obj={
    name:'',
    title:'',
    type:'',
    time:''
};
function arrToObj(arr) {
    return {
        name: arr[0],
        type: arr[1],
        title: arr[2],
        data: arr[3]
    };
}
let data=arrToObj(arr);
console.log(data)

服务器端数据适配

适配服务器端数据的变化

function ajaxAdapter(data) {
    return [data['key1'],data['key2'],data['key3']];
}
$.ajax({
    url:'someAdress.php',
    success:function (data, status) {
        if (data){
            dosometing(ajaxAdapter(data));
        } 
    }
});

proxy

代理模式,由于一个对象不能直接引用另一个对象,所以需要通过代理对象在两个对象之间起到中介作用

let Count=(function () {
    let _img=new Image();
    return function (param) {
        let str='http://www.count.com/a.gif?';
        for (let i in param){
            str +=i+'='+param[i];
        }
        _img.src=str;
    }
})();
Count({num:10});

小明给女神送花,无代理模式

let Flower=function () {};
let xiaoming={
    sendFlower:function (target) {
        let flower=new Flower();
        target.receiveFlower(flower);
    }
};
let A={
    receiveFlower:function (flower) {
        console.log('receive'+flower);
    }
};
xiaoming.sendFlower(A);

引入B代理

let Flower=function () {};
let xiaoming={
    sendFlower:function (target) {
        let flower=new Flower();
        target.receiveFlower(flower);
    }
};
let B={
    receiveFlower:function (flower) {
        A.receiveFlower(flower);
    }
};
let A={
    receiveFlower:function (flower) {
        console.log('receive'+flower);
    }
};
xiaoming.sendFlower(B);

加入B的优势

let Flower=function () {};
let xiaoming={
    sendFlower:function (target) {
        let flower=new Flower();
        target.receiveFlower(flower);
    }
};
let B={
    receiveFlower:function (flower) {
        A.listenGoodMood(function () {
            A.receiveFlower(flower);
        });
    }
};
let A={
    receiveFlower:function (flower) {
        console.log('receive'+flower);
    },
    listenGoodMood:function (fn) {
        setTimeout(function () {
            fn();
        },3000);
    }
};
xiaoming.sendFlower(B);

将开销大的对象延迟到真正需要时才创建

let B={
    receiveFlower:function (flower) {
        A.listenGoodMood(function () {
            let flower=new Flower();
            A.receiveFlower(flower);
        });
    }
};

虚拟代理实现图片预加载

let myImage=(function () {
    let imgNode=document.createElement('img');
    document.body.appendChild(imgNode);
    return {
        setSrc:function (src) {
            imgNode.src=src;
        }
    };
})();
myImage.setSrc('http://');

添加代理对象

let myImage=(function () {
    let imgNode=document.createElement('img');
    document.body.appendChild(imgNode);
    return {
        setSrc:function (src) {
            imgNode.src=src;
        }
    };
})();
myImage.setSrc('http://');
let proxyImage=(function () {
    let img=new Image();
    img.onload=function () {
        myImage.setSrc(this.src);
    };
    return {
        setSrc:function (src) {
            myImage.setSrc('file://');
        }
    };
})();
proxyImage.setSrc('http://');

不使用代理

let myImage=(function () {
    let imgNode=document.createElement('img');
    document.body.appendChild(imgNode);
    let img=new Image();
    img.onload=function () {
        imgNode.src=img.src;
    };
    return {
        setSrc:function (src) {
            imgNode.src='file://';
            img.src=src;
        }
    };
})();
myImage.setSrc('http://');

虚拟代理合并HTTP请求

let synchronousFile=function (id) {
    console.log('start id:'+ id);
};
let proxySynchronousFile=(function () {
    let cache=[],
        timer;
    return function (id) {
        cache.push(id);
        if (timer){
            return null;
        }
        timer=setTimeout(function () {
            synchronousFile(cache.join(','));
            clearTimeout(timer);
            timer=null;
            cache.length=0;
        },2000);
    };
})();
let checkbox=document.getElementsByTagName('input');
for (let i=0,c;c=checkbox[i++];){
    c.onclick=function () {
        if (this.checked===true){
            proxySynchronousFile(this.id);
        } 
    };
}

虚拟代理在惰性加载中的应用

let miniConsole=(function () {
    let cache=[];
    let handler=function (ev) {
        if (ev.keyCode===113){
            let script=document.createElement('script');
            script.onload=function () {
                for (let i=0,fn;fn=cache[i++];){
                    fn();
                }
            };
            script.src='miniConsole.js';
            document.getElementsByTagName('head')[0].appendChild(script);
            document.body.removeEventListener('keydown',handler);
        }
    };
    document.body.addEventListener('keydown',handler,false);
    return {
        log:function () {
            let args=arguments;
            cache.push(function () {
                return miniConsole.log.apply(miniConsole,args);
            });
        }
    }
})();
miniConsole.log(11);
miniConsole={
    log:function () {
        console.log(Array.prototype.join.call(arguments));
    }
};

缓存代理

let mult=function () {
    console.log('start cal');
    let a=1;
    for (let i=0,l=arguments.length;i<l;i++){
        a=a*arguments[i];
    }
    return a;
};
console.log(mult(2,3),mult(2,3,4));
let proxyMult=(function () {
    let cache={};
    return function () {
        let args=Array.prototype.join.call(arguments,',');
        if (args in cache){
            return cache[args];
        }
        return cache[args]=mult.apply(this,arguments);
    }
})();
console.log(proxyMult(1,2,3,4),proxyMult(1,2,3,4));

用高阶函数动态创建代理

let mult=function () {
    console.log('start cal');
    let a=1;
    for (let i=0,l=arguments.length;i<l;i++){
        a=a*arguments[i];
    }
    return a;
};
let plus=function(){
    let a=0;
    for (let i=0,l=arguments.length;i<l;i++){
        a=a+arguments[i];
    }
    return a;
};
let createProxyFactory=function(fn){
    let cache={};
    return function () {
        let args=Array.prototype.join.call(arguments,',');
        if (args in cache){
            return cache[args];
        }
        return cache[args]=fn.apply(this,arguments);
    }
};
let proxyMult=createProxyFactory(mult),
    proxyPlus=createProxyFactory(plus);
console.log(proxyMult(1,2,3,4),proxyMult(1,2,3,4));
console.log(proxyPlus(1,2,3,4),proxyPlus(1,2,3,4));

Decorator

装饰者模式,在不改变原有对象的基础上,通过对其进行包装拓展(添加属性或方法)使原有对象可以满足用户的更复杂的需求

let decorator=function (input, fn) {
    let inp=document.getElementById(input);
    if (typeof inp.onclick==='function'){
        let oldClickFn=inp.onclick;
        inp.onclick=function () {
            oldClickFn();
            fn();
        }
    } else {
        inp.onclick=fn;
    }
};

Bridge

桥接模式,在系统沿着多个维度发生变化时,又不增加其复杂度并达到解耦

let spans=document.getElementsByTagName('span');
spans[0].onmouseover=function () {
    this.style.color='red';
    this.style.background='#ddd';
};
spans[0].onmouseout=function () {
    this.style.color='#333';
    this.style.background='#f5f5f5';
};
spans[1].onmouseover=function () {
    this.getElementsByTagName('string')[0].style.color='red';
    this.getElementsByTagName('string')[0].style.background='#ddd';
};
spans[1].onmouseout=function () {
    this.getElementsByTagName('string')[0].style.color='#333';
    this.getElementsByTagName('string')[0].style.background='#f5f5f5';
};

桥接模式

function changeColor(dom, color, bg) {
    dom.style.color=color;
    dom.style.background=bg;
}
let spans=document.getElementsByTagName('span');
spans[0].onmouseover=function () {
    changeColor(this,'red','#ddd');
};
spans[0].onmouseout=function () {
    changeColor(this,'#333','#f5f5f5');
};
spans[1].onmouseover=function () {
    changeColor(this.getElementsByTagName('string')[0],'red','#ddd');
};
spans[1].onmouseout=function () {
    changeColor(this.getElementsByTagName('string')[0],'#333','#f5f5f5');
};

多元化对象

function Speed(x, y) {
    this.x=x;
    this.y=y;
}
Speed.prototype.run=function () {
    console.log('run run');
};
function Color(cl) {
    this.color=cl;
}
Color.prototype.draw=function () {
    console.log('draw color');
};
function Shape(sp) {
    this.shape=sp;
}
Shape.prototype.change=function () {
    console.log('change shape');
};
function Speek(wd) {
    this.word=wd;
}
Speek.prototype.say=function () {
    console.log('speek word');
};
function Ball(x, y, c) {
    this.speed=new Speek(x,y);
    this.color=new Color(c);
}
Ball.prototype.init=function () {
    this.speed.run();
    this.color.draw();
};
function People(x, y, f) {
    this.speed=new Speed(x,y);
    this.font=new Speek(f);
}
People.prototype.init=function () {
    this.speed.run();
    this.font.say();
};
function Spirite(x, y, c, s) {
    this.speed=new Speed(x,y);
    this.color=new Color(c);
    this.shape=new Shape(s);
}
Spirite.prototype.init=function () {
    this.speed.run();
    this.color.draw();
    this.shape.change();
};
let p=new People(10,12,16);
p.init();

Composite

组合模式,又称部分-整体模式,将对象组合成树形结构以表示"部分整体"的层次结构,组合模式使得用户对单个对象和组合对象使用具有一致性

let News=function () {
    this.children=[];
    this.element=null;
};
News.prototype={
    init:function () {
        throw new Error('rewrite your method');
    },
    add:function () {
        throw new Error('rewrite your method');
    },
    getElement:function () {
        throw new Error('rewrite your method');
    },
};
let Container=function (id, parent) {
    News.call(this);
    this.id=id;
    this.parent=parent;
    this.init();
};
inheritPrototype(Container,News);
Container.prototype.init=function () {
    this.element=document.createElement('ul');
    this.element.id=this.id;
    this.element.className='new-container';
};
Container.prototype.add=function (child) {
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
};
Container.prototype.getElement=function () {
    return this.element;
};
Container.prototype.show=function () {
    this.parent.appendChild(this.element);
};
let Item=function (classname) {
    News.call(this);
    this.classname=classname||'';
    this.init();
};
inheritPrototype(Item,News);
Item.prototype.init=function(){
    this.element=document.createElement('li');
    this.element.className=this.classname;
};
Item.prototype.add=function (child) {
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
};
Item.prototype.getElement=function () {
    return this.element;
};
let NewsGroup=function (classname) {
    News.call(this);
    this.classname=classname||'';
    this.init();
};
inheritPrototype(NewsGroup,News);
NewsGroup.prototype.init=function(){
    this.element=document.createElement('div');
    this.element.className=this.classname;
};
NewsGroup.prototype.add=function (child) {
    this.children.push(child);
    this.element.appendChild(child.getElement());
    return this;
};
NewsGroup.prototype.getElement=function () {
    return this.element;
};
let ImageNews=function (url, href, classname) {
    News.call(this);
    this.url=url||'';
    this.href=href||'#';
    this.classname=classname||'normal';
    this.init();
};
inheritPrototype(ImageNews,News);
ImageNews.prototype.init=function () {
    this.element=document.createElement('a');
    let img=new Image();
    img.src=this.url;
    this.element.appendChild(img);
    this.element.className='image-news'+this.classname;
    this.element.href=this.href;
};
ImageNews.prototype.add=function () {};
ImageNews.prototype.getElement=function () {
    return this.element;
};
let IconNews=function (text, href, type) {
    News.call(this);
    this.text=text||'';
    this.href=href||'#';
    this.type=type||'video';
    this.init();
};
inheritPrototype(IconNews,News);
IconNews.prototype.init=function () {
    this.element=document.createElement('a');
    this.element.innerHTML=this.text;
    this.element.href=this.href;
    this.element.className='icon '+this.type;
};
IconNews.prototype.add=function () {};
IconNews.prototype.getElement=function () {
    return this.element;
};
let EasyNews=function (text, href) {
    News.call(this);
    this.text=text||'';
    this.href=href||'#';
    this.init();
};
inheritPrototype(EasyNews,News);
EasyNews.prototype.init=function () {
    this.element=document.createElement('a');
    this.element.innerHTML=this.text;
    this.element.href=this.href;
    this.element.className='text';
};
EasyNews.prototype.add=function () {};
EasyNews.prototype.getElement=function () {
    return this.element;
};
let TypeNews=function (text, href, type, pos) {
    News.call(this);
    this.text=text||'';
    this.href=href||'#';
    this.type=type||'';
    this.pos=pos||'left';
    this.init();
};
inheritPrototype(TypeNews,News);
TypeNews.prototype.init=function () {
    this.element=document.createElement('a');
    if (this.pos==='left'){
        this.element.innerHTML='['+this.type+']';
    } else {
        this.element.innerHTML=this.text+'['+this.type+']';
    }
    this.element.href=this.href;
    this.element.className=this.classname;
};
TypeNews.prototype.add=function () {};
TypeNews.prototype.getElement=function () {
    return this.getElement();
};
let new1=new Container('news',document.body);
new1.add(
    new Item('normal').add(
        new IconNews('succsssss','#','video')
    )
).add(
    new IconNews('project','#','live')
).add(
    new Item('normal').add(
        new NewsGroup('has-img').add(
            new ImageNews('img/1.jpg','#','small')
        ).add(
            new EasyNews('from 240 to 120','#')
        ).add(
            new EasyNews('five man','#')
        )
    )
).add(
    new Item('normal').add(
        new TypeNews('ak47','#','NBA','left')
    ).add(
        new Item('normal').add(
            new TypeNews('three','#','CBA','right')
        )
    )
).show();

Flyweight

享元模式,运用共享技术有效支持大量的细粒度的对象,避免对象间拥有相同内容造成多余的开销

原始需求

let dom=null,
    paper=0,
    num=5,
    i=0,
    len=article.length;
for (;i<len;i++){
    dom=document.createElement('div');
    dom.innerHTML=article[i];
    if (i>=num){
        dom.style.display='none';
    }
    document.getElementById('container').appendChild(dom);
}
document.getElementById('next_page').onclick=function () {
    let div=document.getElementById('container').getElementsByTagName('div');
    let k;
    let n;
    let j = k = n = 0;
    n=++paper % Math.ceil(len/num)*num;
    for (;j<len;j++){
        div[j].style.display='none';
    }
    for (;k<5;k++){
        if (div[n+k])
            div[n+k].style.display='block';
    }
};

享元模式

let Flyweight=function () {
    let created=[];
    function create() {
        let dom=document.createElement('div');
        document.getElementById('container').appendChild(dom);
        created.push(dom);
        return dom;
    }
    return {
        getDiv:function () {
            if (created.length<5){
                return create();
            } else {
                let div=created.shift();
                created.push(div);
                return div;
            }
        }
    }
}();
let paper=0,
    num=5,
    len=article.length;
for (let i=0;i<5;i++){
    if (article[i])
        Flyweight.getDiv().innerHTML=article[i];
}
document.getElementById('next_page').onclick=function () {
    if (article.length<5)
        return null;
    let n=++paper*num%len,
        j=0;
    for (;j<5;j++){
        if (article[n+j]){
            Flyweight.getDiv().innerHTML=article[n+j];
        } else if (article[n+j-len]) {
            Flyweight.getDiv().innerHTML=article[n+j-len];
        }else {
            Flyweight.getDiv().innerHTML="";
        }
    }
};

享元动作

let Flyweight={
    moveX:function (x) {
        this.x=x;
    },
    moveY:function (y) {
        this.y=y;
    }
};
let Player=function (x, y, c) {
    this.x=x;
    this.y=y;
    this.color=c;
};
Player.prototype=Flyweight;
Player.prototype.changeC=function (c) {
    this.color=c;
};
let Spirit=function (x,y,r) {
    this.x=x;
    this.y=y;
    this.r=r;
};
Spirit.prototype=Flyweight;
Spirit.prototype.changeR=function (r) {
    this.r=r;
};
let player1=new Player(5,6,'red');
console.log(player1);
player1.moveX(6);
player1.moveY(7);
player1.changeC('pink');
console.log(player1);
let spirit1=new Spirit(2,3,4);
console.log(spirit1);
spirit1.moveX(3);
spirit1.moveY(4);
spirit1.changeR(5);
console.log(spirit1);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值