JsDesignMode第三篇

结构型设计模式
     如何将类或对象组合成更大、更复杂的结构,简化设计
1.外观模式
        1.1为一组复杂的子系统接口提供一个更高级的统一接口
                    通过这个接口对子系统接口的访问更容易
      

  //添加一个点击事件
            document.onclick = function(e){
                e.preventDefault();
                if(e.target !== document.getElementById('myinput')){
                    hidePageAlert();
                }
            }
            function hidePageAlert(){
                //隐藏提示框
            }


                  为document绑定了一个onclick事件,onclick是DOM0级事件,也就是说为元素绑定一个事件方法
                  如果有人再次通过这种方式来绑定click,会覆盖你定义的事件方法,所以应该使用DOM2级事件addEventListener
                  但是老版本IE不支持这个方法,使用attachEvent,不支持DOM2级事件处理程序的浏览器,只能使用onclick
        1.2兼容模式
         

   //外观模式
            function addEvent(dom, type, fn){
                //支持DOM2级事件处理程序addEventListener方法的浏览器
                if(dom.addEventListener){
                    dom.addEventListener(type, fn, false);
                //不支持addEventListener,但是支持attachEvent方法的浏览器
                }else if(dom.attachEvent){
                    dom.attachEvent('on' + type, fn);
                //以上都不支持
                }else{
                    dom['on' + type] = fn;
                }
            }


2.适配器模式
        2.1将一个类的接口转换成为另外一个接口
                  公司内部开发使用A框架,想引入jQuery
                  如果A框架和jQuery很类似,使用适配器来匹配
                  window.A = A = jQuery;
                  就可以使用jQuery来使用之前的代码
        2.2适配异类框架
                  如果框架之间差别太大,适配起来繁琐
        2.3参数适配器
           

//参数太多,理清顺序很麻烦
//以一个参数对象传入
            function doSomeThing(obj){
                var _adapter = {
                    name : '雨夜清荷',
                    title : 'xgd',
                    age : 24,
                    color : 'red',
                    size : 100,
                };
                for(var i in _adapter){
                    _adapter[i] = obj[i] || _adapter[i];
                }
            }


        2.4数据适配
                    后端数据因为架构改变导致传递的数据结构发生变化
                    后端传来的数据不是我们想要的数据类型
                    我们可以写一个适配器,适配成我们想要的格式
3.代理模式
             一个对象不能直接引用另一个对象,通过一个代理在两个对象之间起到中介的作用
        3.1用户相册模块上传的照片量越来越大,导致服务端需要将图片上传模块重新部署到
             另外一个域(另一个服务器),对于前端来说,路径发生改变,导致跨域
        3.2因为JS中同源策略的限制,不同域名、端口号、协议,任何一个不同,就造成跨域
        3.3找一个代理对象来处理两个对象的通信
        3.4代理对象
            1.站长统计
                简单一点的,比如img标签通过src属性可以向其他域下的服务器发送请求
                这类请求是get请求,并且是单向的,也就是没有响应数据
                应用:
                        站长平台对你的页面统计项,当你的页面触发一些动作的时候
                        向站长平台发送类似这类img的get请求,对你的请求进行统计
                        然而你并不知道
            2.JSONP
                通过script标签,比如我们在CDN(内容分发网络,一种更接近用户的网络架构,就近获取内容)
                在src中添加相应的字段信息,然后服务端相应生成一份内容
            3.代理模板
                不同域的调用是有限制的,那么自己域中的两个页面相互之间的调用是可以的
                自己域:X域
                    被代理页面:A页面
                        1.发送请求的模块
                            form表单提交,负责向Y域发送请求
                            提供额外的两组数据:
                            执行的回调函数名、X域中代理模板所在的路径并将target目标指向内嵌框架
                        2.内嵌框架
                            如iframe,负责提供第一部分中form表单的响应目标target的指向
                            并将嵌入X域中的代理页面作为子页面
                        3.回调函数
                            处理返回来的数据
                    代理页面:B页面
                另外的域:Y域
4.装饰者模式
        在不改变原对象的基础上,对其进行包装拓展,添加属性和方法
        使原有对象可以满足用户更为复杂的需求
      

  //装饰者
            var decorator = function(input, fn){
                var input = document.getElementById(input);
                if(typeof input.onclick === 'function'){
                    var oldClickFn = input.onclick;
                    input.onclick = function(){
                        oldClickFn();
                        fn();
                    }
                }else{
                    input.onclick = fn;
                }
                //其他
            }
        //使用
        decorator('tel_input', function(){
            document.getElementById('tel_demo_text').style.display = 'none';
        });


5.桥接模式
             系统沿着多个维度变化的同时,不增加其复杂度并已达到解耦
        5.1提取共同点
             对相同的逻辑做抽象提取处理,代码简洁、重用率更大、更可读
        5.2事件与业务逻辑之间的桥梁
             先抽象提取共用部分,将实现与抽象通过桥接方法链接在一起,达到解耦
        5.3多元化对象
           

 function Speed(x, y){
                this.x = x;
                this.y = y;
            }
            Speed.prototype.run = function(){
                console.log('运动起来');
            }

            function Color(cl){
                this.color = cl;
            }
            Color.prototype.draw = function(){
                console.log('绘制色彩');
            }

            function Shape(sp){
                this.shape = sp;
            }
            Shape.prototype.change = function(){
                console.log('改变形状');
            }

            function Speek(wd){
                this.word = wd;
            }
            Speek.prototype.say = function(){
                console.log('书写字体');
            }
            //球类
            function Ball(x,y,c){
                this.speed = new Speed(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();
            }
            实现一个人物
            var p = new People(10, 12, 16);
            p.init();


6.组合模式
        部分-整体模式,将对象组合树形结构以表示"部分整体"的层次结构
        对单个对象和组合对象的使用具有一致性
        6.1套餐服务
                先拆分出个体,然后按需要寻找相应的个体合成新的整体的意思
        6.2每个成员都有祖先
                要求:接口的统一
           

//让所有的新闻继承至一个新闻虚拟父类News
                var News = function(){
                    //子组件容器
                    this.children = [];
                    //当前组件元素
                    this.element = null;
                }
                News.prototype = {
                    init : function(){
                        throw new Error("请重写你的方法");
                    },
                    add : function(){
                        throw new Error("请重写你的方法");
                    },
                    getElement : function(){
                        throw new Error("请重写你的方法");
                    }
                }


            父类是虚拟父类,为何声明一些特权变量
                   因为后面的继承子类都要声明这两个变量,简化子类提前声明在父类中
            拆分确定层次关系
                   最顶层是一个新闻模块的容器,再往下就是每一行新闻成员集合
                   每一行还可能是新闻组合体,最后一层就是新闻对象
        6.3.组合要有一个容器类
          

  //容器类构造函数
            var Container = function(id, parent){
                //构造函数继承父类
                News.call(this);
                //模块id
                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(){
                //在子元素容器中插入子元素
                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);
            }
            下一层级的行成员集合类以及后面的新闻组合体类实现的方式
            var 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(){
                this.children.push(child);
                this.element.appendChild(child.getElement());
                return this;
            }
            Item.prototype.getElement = function(){
                return this.element;
            }
            var 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;
            }


        6.4创建一个新闻类
           

 var 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');
                var 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;
            }


        6.5创建新闻模块
           

var news1 = new Container('news', document.body);
            news1.add(
                new Item('normal').add(
                    new IconNews('梅西', '#', 'video')
                )
            ).add(
                new Item('normal').add(
                    new NewsGroup('has-img'.add(
                        new ImageNews('img/1.jpg', '#', 'small')
                    ).add(
                        new EasyNews('xx', '#')
                    ).add(
                        new EasyNews('xxx', '#')
                    )
                )
            ).show();


        6.6应用在表单
7.享元模式
               共享技术有效支持大量的细粒度的对象,避免拥有相同类容造成多余的开销
        7.1新闻翻页
                所有新闻具有相同结构,当几百条新闻同时插入页面并操作造成的多余开销
                在低版本IE浏览器中或严重影响其性能
        7.2享元模式
               对其数据、方法共享分离,将数据和方法分成内部数据、内部方法、外部数据、外部方法
               内部数据和内部方法指的是相似或者共有的数据和方法,需要一出来减少开销
        7.3享元对象
                新闻个体具有共同的结构,作为内部方法,下一页绑定的事件不能再抽象了,作为外部方法
                操作方法,操作这些提取出来的内部数据
           

var Flyweight = function(){
                //已创建的元素
                var created = [];
                //创建一个新闻包装容器
                function create(){
                    var dom = document.createElement('div');
                    //将容器插入新闻列表容器中
                    document.getElementById('container').appendChild(dom);
                    //缓存新创建的元素
                    created.push(dom);
                    //返回创建的新元素
                    return dom;
                }
                return {
                    //获取创建新闻元素方法
                    getDiv : function(){
                        //已创建的元素小于当前页元素总个数,则创建
                        if(created.length < 5){
                            return create();
                        }else{
                            //获取第一个元素,并插入到最后面
                            var div = created.shift();
                            created.push(div);
                            return div;
                        }
                    }
                }
            }();


        7.4实现需求
                    创建一个享元类,由于每页只能显示5条新闻,所以我们创建5个元素
                    保存在享元类的内部,通过享元类提供的方法getDiv来获取创建的元素
        7.5享元动作
           

//横向移动和纵向移动
            var FlyWeight = {
                moveX : function(x){
                    this.x = x;
                },
                moveY : function(y){
                    this.y = y;
                }
            }
            //其他任何角色都可以继承来实现这些方法
            var 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;
            }
发布了34 篇原创文章 · 获赞 34 · 访问量 1099

猜你喜欢

转载自blog.csdn.net/qq_45517916/article/details/103500598