0

我正在开发一个类似于elFinder的文件管理器框架。我当前的代码工作正常,但现在我想让它看起来更好并添加链接(我不确定它是链接模式还是装饰模式)。

这是我想做的一个示例:

function UI() {}

UI.prototype.folders = function(){
    return [];
}

UI.prototype.folders.prototype.getSelectedFolder = function(){
   return {};
}

调用UI.folders()应该返回一个文件夹对象数组。所以如果你打电话UI.folders(),你会得到类似的东西:

[
    Object { name="folder1", selected=false }, 
    Object { name="folder2", selected=false }, 
    Object { name="folder3", selected=true }
]

调用UI.folders().getSelectedFolder()将过滤结果UI.folders()并返回:

Object { name="folder3", selected=true }

这可能吗?在这种情况下说“链接”还是“装饰图案”是否正确?
如果不是 - 还有另一种更合适的方法吗?

任何帮助将不胜感激!

4

3 回答 3

2

您问题中的代码不能反映正确的实现,但是要回答您的直接问题,是的,这...

UI.folders().getSelectedFolder()

...将是方法链接的一个示例。


装饰器模式是不同的。如果您有一组方法,并且每个方法都应始终首先调用某个公共函数,则可以创建一个装饰器,该装饰器将返回一个函数,该函数首先调用公共函数,然后是实际的函数......

function foo() {
    console.log('I\'m foo, and I\'m first, and I was given these args:', arguments);
}

function decorateWithFoo(decorated) {
    return function () {
        foo.apply(this, arguments);
        decorated.apply(this, arguments);
    };
}

所以你可以decorateWithFoo用来创建一个总是foo首先调用的函数......

  // create and decorate bar()
var bar = function(a,b) {
    console.log('I\'m bar, and I was called after "foo", and was given args:', a, b);
};
bar = decorateWithFoo(bar);

bar(123, 456); // this will first call `foo()`, then (the original) `bar()`.

  // create and decorate baz()
var baz = function(a,b) {
    console.log('I\'m baz, and I was called after "foo", and was given args:', a, b);
};
baz = decorateWithFoo(baz);

baz(123, 456); // this will first call `foo()`, then (the original) `baz()`.

一些语言内置了用于创建装饰器的语法。JavaScript 目前没有。


如果您发现自己以不同的方式使用装饰器,您可以创建另一个函数来设置初始装饰器功能......

function generateDecorator(decorator) {
    return function (decorated) {
        return function () {
            decorator.apply(this, arguments);
            decorated.apply(this, arguments);
        };
    };
}

所以我们的原版decoreateWithFoo可以这样设置......

function foo() {
    console.log('I\'m foo, and I\'m first, and I was given these args:', arguments);
}

var decorateWithFoo = generateDecorator(foo);
于 2012-04-15T17:35:41.130 回答
1

为了使其正常工作,您需要使您的文件夹方法成为一个函数,该函数返回一个从数组继承的对象。:

UI.prototype.folders = function(){
    // must return an object that inherits from an array
    // that has the additional methods on it you want like getSelectedFolder()
}
于 2012-04-15T17:30:34.110 回答
0

有几种不同的方法可以解决这个问题。主要目标是,当您调用一个函数时,您会得到一个对象/函数,它是具有不同属性的相同类型的对象。我不是原型使用的粉丝,所以我会这样做(这是解决它的一种方法):

var FolderList = function ()
{
    var _folders = [];
    folders.pop({ name: "folder1", selected: false });
    folders.pop({ name: "folder2", selected: true });
    folders.pop({ name: "folder3", selected: false });

    // prevent other programers from changing _folders
    // which would break this, so just use a function
    this.folders = function ()
    {
        return _folders;
    }

    this.selectedFolders = function ()
    {
        var tmpFolders = [];
        for (var folderIndex = 0; 
             folderIndex < this._folders.length; 
             folderIndex++)
        {
            if (this._folders[folderIndex].selected)
            {
                tmpFolders.pop(_folders[folderIndex]);
            }
        }
        _folders = tmpFolders;
        return this;
    }

    this.addFolder = function (folder)
    {
        _folders.pop(folder);
        return this;
    }
};

var folderList = new FolderList();
folderList.selectedFolders()
          .addFolder({ name: "folder1", selected: false })
          .addFolder({ name: "folder3", selected: true })
          .selectedFolders();

// array of 2 objects, folder2 and folder3
var arrayOfSelectedFolder = folderList.folders();  
于 2012-04-15T18:17:23.430 回答