07.Javascript设计模式之组合模式----Composite

来源:互联网 发布:sql server2012图标 编辑:程序博客网 时间:2024/06/18 14:29

07.Javascript设计模式之组合模式----Composite

组合模式是一种专为创建WEB上的动态用户界面而量身定制的模式。使用这种模式,可以用一条命令在多个对象上激发复杂的或递归的行为,这可以简化粘合性代码,使其更容易维护,而那些复杂行为则被委托给各个对象。

本文主要通过一个Windows文件目录结构的例子来阐述组合模式。

问题引入

Windows文件目录结构就像一棵树,有根节点(我的电脑),然后有子节点(如C盘、D盘等),子节点也还有子节点(盘符下的文件夹),文件夹下还可能会有文件夹,也可能会有单独的文件,于是,在树的概念中, 我们称单独的文件节点为叶子,而文件夹则为树枝。

于是,这一次有这样一个命题,我们希望能够有选择地隐藏或显示Windows目录结构中的特定部分。这可能是单独的文件,也可能是文件夹。考虑到Windows文件目录结构的复杂性,这里我们只关注文件或文件夹的显示和隐藏操作。

组合模式

类的定义

针对上面的命题,我们需要设计两个类,一个用作文件夹的组合对象类,一个用作文件本身的叶子对象类。

//文件夹接口:组合对象var IDirectory = new Interface("IDirectory",["add","delete","getFile"]);//文件接口:叶子对象var IFile = new Interface("IFile",["show","hide"]);

接下来就是非常关键的了,这里即将定义一个动态的文件系统类DynamicFileSystem,该类是IDirectory和IFile的实现类。也就是说,通过DynamicFileSystem类实例化出来的对象,既可能是一个文件,也可能是一个文件夹。

其代码如下:

//文件系统类var DynamicFileSystem = function(id,fileName){    this.files = []; //子文件列表(注意,文件夹也是一个文件)    this.createDate = new Date();//文件的创建日期    this.fileName = fileName; //文件名    //为了在WEB中很好的来描述这个问题,我们需要用到HTMLDOMElement    this.element = document.createElement("div");    this.element.id = id;};//实现两个接口implements(DynamicFileSystem,IDirectory,IFile);//实现所有的抽象方法DynamicFileSystem.prototype = {    add : function(fileSystemChild){        this.files.push(fileSystemChild);        this.element.appendChild(fileSystemChild.getElement());    },    delete : function(fileSystemChild){        for(var file,i = 0;node = this.getFile(i),i++){            if(file == fileSystemChild){                this.files.splice(i,1);                break;            }        }        this.element.removeChild(fileSystemChild.getElement());    },    getFile : function(index){        return this.files[index];    },    show : function(){        //显示文件或文件夹        this.element.style.display = "block";                   for(var file,i = 0;node = this.getFile(i),i++){            file.show(); //递归调用        }    },    hide : function(){                  for(var file,i = 0;node = this.getFile(i),i++){            file.hide(); //递归调用        }        //隐藏文件或文件夹        this.element.style.display = "none";    },    //拓展方法    getElement : function(){        return this.element;    }};

在上面的代码中,首先定义的是组合对象类和叶子对象类应该实现的接口。除了常规的组合对象方法外,这些类要定义的操作只包含hide和show。 接下来定义的是组合对象类。由于DynamicFileSystem只是对div对象的包装,所以文件系统可以再嵌套子文件系统,而我们因此也只需要用到一个组合对象类即可。

实例化演示

下面就是大家迫不及待想要看到的,如何实例化并操作整个Windows的目录树结构呢?

其实到这里还没有完,我们必须要有一个真正的文件实体类,比如Word文档、PDF文档、Text文档等等,它们都是File,因此我们可以随便的定义一个文件类,并让它继承DynamicFileSystem类即可(因为它同样具备文件系统的功能), 下面以Text文档为例,创建TextFile类:

var TextFile = function(id,fileName){    //文件名    this.fileName = fileName;    this.element = document.createElement("div");    this.element.id = id;};//实施继承inherits(TextFile,DynamicFileSystem);

如此一来,TextFile类就已经具备了DynamicFileSystem类的所有方法,而且还有一个自己独特的构造器,接收一个参数----文件名。

接下来就是真正的开始应用了,我们首先创建一个文件系统(文件夹)的实例,再创建三个文本文件TextFile类的实例,最后将这三个文本文件添加到文件系统中去:

//创建文件夹var fileSystem = new DynamicFileSystem("dirRoot","C盘");//创建文本文件var txtFile1 = new TextFile("txtFile1","文本文件1");var txtFile2 = new TextFile("txtFile2","文本文件2");var txtFile3 = new TextFile("txtFile3","文本文件3");//将三个文本文件添加到文件夹中fileSystem.add(txtFile1);fileSystem.add(txtFile2);fileSystem.add(txtFile3);

在这个时候你可能想说了,我想在C盘下建立两个文件夹,分别是“Windows”和“Program Files”,该怎么办呢?很简单,继续之前的代码:

var windowsDir = new DynamicFileSystem("dirWindows","Windows"); //Windows文件夹var programDir = new DynamicFileSystem("dirProgram","Program Files"); //Program Files文件夹//添加到C盘fileSystem.add(windowsDir);fileSystem.add(programDir);

OK,到了这一步,一切都顺利的完成了。

如果你是一个爱问的同学,你想知道,如果我突然需要安装一个软件,该软件的安装目录必须为C:Program FilesMicrosoft,安装完成后还会在Microsoft目录下产生一个microsoft.exe的文件,又该怎么模拟呢?

照猫画虎:

第一步,创建ExeFile类第二步,创建Microsoft目录第三步,将其添加到C:/Program Files下第四步,创建ExeFile类的实例microsoft.exe文件第五步,将microsoft.exe添加到C:/Program Files/Microsoft目录下,完成

总结

如果应用得当,组合模式将是一种非常管用的设计模式。它把一批子对象组织为树形结构,只要一条命令就可以操作树上的所有对象,提高了代码的模块化程度,而且便于代码重构和对象的更换。这种模式特别适合于动态的HTML用户界面,在它的帮助下,你可以在不知道用户界面的最终格局的情况下进行开发。对于我们每一个前端Javascript程序员来说,能掌握好组合模式,一定会大受益处滴。

本文参考《Javascript设计模式》【Ross Harmes,Dustin Diaz】

小生愚昧,文中如有阐述之不当,还请不要介怀