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

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】

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

你可能感兴趣的:(Javascript设计模式)