2016-01-21 4 views
0

Я создаю этот шаблон Builder, и я хотел бы объединить некоторые элементы из списка вместе. Но я хотел бы сделать это чище. Это то, к чему я пришел, пока работает, но я уверен, что есть лучший способ сделать это.Как условно объединить некоторые элементы в списке в JavaScript?

function FiltersBuilder() { 
    this.filters = []; 
}; 

FiltersBuilder.prototype.addFilter = function(options) { 
    var filter = { 
    'type': 'selector', 
    'dimension': options.dimension, 
    'value': options.value 
    } 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.addRegexFilter = function(options) { 
    var filter = { 
    'type': 'regex', 
    'dimension': options.dimension, 
    'pattern': options.value 
    } 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.not = function() { 
    var not = { 
    'type': 'not' 
    }; 
    this.filters.push(not); 
    return this; 
} 

FiltersBuilder.prototype.getFilters = function() { 
    var result = []; 
    this.filters.forEach(function each(filter, index, theFilters) { 
    if (filter.type === 'not') { 
     var filterToMerge = theFilters[index + 1]; 
     var mergedFilter = _.merge(filter, {field: filterToMerge}); 
     result.push(mergedFilter); 
    } else { 
     if(index > 0) { 
     notFilter = theFilters[index - 1]; 
     if(notFilter.type === 'not') { 
      return; 
     } 
     } 
     result.push(filter); 
    } 
    }); 

    return result; 
} 

var filterBuilder = new FiltersBuilder(); 
filterBuilder.addFilter({ 
    dimension: '_o', 
    value: 'origin' 
}); 
filterBuilder.not().addRegexFilter({ 
    dimension: 'cTy', 
    value: 'value' 
}); 

console.log(filterBuilder.getFilters()); 

Если not метод вызывается перед добавлением фильтра, я хотел бы объединить not фильтр на следующий элемент и добавить этот объект в список result. Но если not не вызывается перед добавлением фильтра, тогда ничего не делайте, просто добавьте фильтр в список result.

https://jsfiddle.net/9wyqbovu/

ответ

3

Вместо того чтобы рассматривать not как фильтр будет добавлен в список фильтров и обрабатываются, когда вы получаете фильтры, рассматривать его в качестве модификатора - флаг. Соблюдайте свойство not на объекте FiltersBuilder, инициализированном false, который вызовет FilterBuilders.not. На каждом фильтре также добавьте свойство not, которое устанавливается текущим значением флага not на FilterBuilders (который затем сбрасывается). Другими словами:

function FiltersBuilder() { 
    this.filters = []; 
    this.not = false; 
}; 

FiltersBuilder.prototype.addFilter = function(options) { 
    var filter = { 
    'type': 'selector', 
    'dimension': options.dimension, 
    'value': options.value, 
    not: this.not 
    } 
    this.not = false; 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.addRegexFilter = function(options) { 
    var filter = { 
    'type': 'regex', 
    'dimension': options.dimension, 
    'pattern': options.value, 
    not: this.not 
    } 
    this.not = false; 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.not = function() { 
    this.not = !this.not; 
} 

FiltersBuilder.prototype.getFilters = function() { 
    return this.filters; 
} 

var filterBuilder = new FiltersBuilder(); 
filterBuilder.addFilter({ 
    dimension: '_o', 
    value: 'origin' 
}); 
filterBuilder.not().addRegexFilter({ 
    dimension: 'cTy', 
    value: 'value' 
}); 

console.log(filterBuilder.getFilters()); 

Если вы предпочли бы иметь возможность сказать filterBuilder.not.addFilter (без скобок после not), а затем определить not как геттер, т.е.

Object.defineProperty(FiltersBuilder.prototype, "not", { 
    get: function() { 
    this.not = !this.not; 
    return this; 
    } 
}); 
+0

Мне нравится ваш подход лучше, чем у меня , благодаря! – toy

2

Ну, как если мы делаем итерацию его с правой стороны и использовать unshift вместо push:

getFilters = function(){ 
    return this.filters.reduceRight(function(results, filter){ 
     if(filter.type === 'not'){ 
      //get filter to 'not' 
      var notFilter = results[0]; 
      Object.assign(notFilter, filter); //Or _.merge 
     } else { 
      results.unshift(filter); 
     } 
     return results; 
    }, []); 
} 

В качестве альтернативы, вы можете использовать push вместо unshift, захватить последний элемент массив как фильтр для отрицания (вместо первого) и отменить результаты.

getFilters = function(){ 
    return this.filters.reduceRight(function(results, filter){ 
     if(filter.type === 'not'){ 
      //get filter to 'not' 
      var notFilter = results[results.length - 1]; 
      Object.assign(notFilter, filter); //Or _.merge 
     } else { 
      results.push(filter); 
     } 
     return results; 
    }, []).reverse(); 
} 
Смежные вопросы