Нарушает ли Factory Pattern в js принцип Open-Close?

поскольку JS не поддерживает абстрактные классы или наследование, каждый раз, когда мы хотим добавить новый тип, который будет создан при использовании фабричного шаблона, нам придется модифицировать код, что означает, что мы нарушаем принцип открытия-закрытия. например, на снимке ниже — если мы хотим добавить новый тип сотрудника, такой как маркетинг, нам придется обновить оператор switch, что нарушает принцип открытия-закрытия. Есть ли обходной путь для использования фабричного шаблона без нарушения принципа открытия-закрытия?

function Accountant(){
    console.log('I am accountant');
}

function Developer(){
    console.log('I am developer');
}

function Sales(){
    console.log('I am sales');
}

function CreateEmployee(employee){
    switch(employee){
        case('accountant'): return new Accountant();
        case('developer'): return new Developer()
        case('sales'): return new Sales();
    }
}

person Alex    schedule 07.06.2021    source источник
comment
Литерал объекта — это новый отдельный экземпляр.   -  person StackSlave    schedule 08.06.2021
comment
Абстрактные классы в Javascript   -  person charlietfl    schedule 08.06.2021
comment
JS не поддерживает абстрактные классы или наследование — неправильно и неправильно. Но ни один из них не имеет ничего общего с OCP. Открытый для расширения не относится к подклассам.   -  person Bergi    schedule 08.06.2021


Ответы (4)


если мы хотим добавить новый тип сотрудника, нам придется обновить оператор switch, что нарушает принцип открытия-закрытия.

Нет, это не так. OCP не запрещает обновлять код. Если мы хотим реализовать новую функцию, нам, конечно, нужно коснуться кода программы. OCP предназначен для проектирования ваших интерфейсов таким образом, чтобы ваша программа могла быть легко расширена без изменения кода повсеместно — в идеале вам нужно только предоставить новый код и изменить конфигурацию программы, чтобы использовать из него - или, если это не настраивается, измените только строительные блоки высокого уровня.

Я бы сказал, что фабричный шаблон даже облегчает применение OCP — не думайте об изменениях в фабричной функции, думайте о модулях, которые ее используют. Вместо того, чтобы изменять весь код во всех модулях, которые создают экземпляры объектов сотрудников, все, что вам нужно сделать, это предоставить им другую фабрику.

person Bergi    schedule 07.06.2021
comment
Я нахожу этот ответ несколько противоречивым. В частности, ...для реализации новой функции нам, конечно же, нужно коснуться кода... следует описание решений, не затрагивающих код. - person jaco0646; 08.06.2021
comment
@jaco0646 jaco0646 Я имел в виду всю программу (включая конфигурацию), всегда нужно что-то трогать, чтобы что-то изменить. Кроме того, если я пишу новую программу, перепрофилируя многие части старой (без изменения содержимого их файлов), все та же (но измененная) программа? Что вообще значит обновить код? :-) - person Bergi; 08.06.2021
comment
Помимо философии, в контексте OCP существует четкое разграничение между созданием нового кода и редактированием старого кода. Этот принцип конкретно защищает первое, а не второе. Хотя я думаю, что этот ответ в основном правильный, я думаю, что он может вызвать у ОП большую путаницу в отношении OCP. Похоже, что ОП знает, что ... все, что вам нужно сделать, это предоставить другую фабрику. Вопрос в том, как это сделать в JavaScript. - person jaco0646; 08.06.2021
comment
@ jaco0646 Я не уверен, что они знали об этом. И они не показали код, который использует (использует) фабрику. - person Bergi; 08.06.2021

Просто создайте объект employeeType, содержащий конструкторы:

const employeeType = {
  Accountant,
  Developer,
  Sales
}

console.log(new (employeeType["Accountant"])());

function Accountant(){
    console.log('I am accountant');
}

function Developer(){
    console.log('I am developer');
}

function Sales(){
    console.log('I am sales');
}
person Dexygen    schedule 07.06.2021

Я бы сказал, что шаблон не совсем то, что я хотел бы расширить, но это возможно.

Допустим, у вас есть доступ только к функции CreateEmployee, и вы хотели бы расширить ее, чтобы вы также могли добавить Engineer.

import CreateEmployee from "./employee.js";

function Engineer(){
   console.log("I'm an Engineer");
}

function CreateEmployeeAndEngineer(employeeType){
    if(employeeType === 'Engineer') return new Engineer();
    else {
        return CreateEmployee(employeeType);
    }
}

Простая (эээ... не совсем) композиция функций.

Однако в Javascript для него очень мало значения, поскольку он нетипизирован. Затем, конечно, функции и, следовательно, конструкторы являются гражданами первого класса и могут быть легко переданы оператору new.

поскольку JS не поддерживает абстрактные классы или наследование

Javascript поддерживает наследование через концепцию цепочки прототипов.

Вы можете реализовать шаблон Factory method, если хотите.

person MinusFour    schedule 07.06.2021

Если вы хотите, чтобы экземпляры new создавались на лету, вы должны использовать литералы Object. Просмотрите следующий дизайн, чтобы понять, как вы можете или не хотите это делать:

function ucFirst(string){
  const s = string.split('');
  return s.shift().toUpperCase()+s.join('');
}
function InstanceController(){
  this.instances = [];
  this.add = (name, obj)=>{
    this.instances.push({name:name, obj:obj});
    return this;
  }
  this.get = name=>{
    for(let o of this.instances){
      if(o.name === name){
        return o.obj;
      }
    }
    return false;
  }
  this.remove = name=>{
    for(let i=0,a=this.instances,l=a.length; i<l; i++){
      if(a[i].name === name){
         a.splice(i, 1);
        break;
      }
    }
    return this;
  }
}
const ic = new InstanceController;
const data1 = {
  data:'could be from database', 
  more:'sure there can be more data',
  numberTest: 2
}
const data2 = {test:'just a test'};
ic.add('developer', data1).add('accountant', {testing:'see'});
let dev = ic.get('developer'), aco = ic.get('accountant');
if(dev)console.log(dev);
if(aco)console.log(aco);
console.log(ic.get('nope'));
ic.remove('accountant'); aco = ic.get('accountant');
console.log(aco);

person StackSlave    schedule 07.06.2021