创建代表 Employees 集合的 class

Create class which represents collection of Employees

我有抽象的 Class AbstractEmployee 和两个具体的子 classes FixedSalaryEmployeePerHourSalaryEmployee 继承自 AbstractEmployee 并覆盖它的抽象 getSalary 方法对给定的雇员类型具有正确的实现。

第一次实施 FixedSalaryEmployee - 固定工资的员工。 JSON 数据中的平均月薪等于雇员的薪水值。

第二次实施PerHourSalaryEmployee- 雇员按小时计薪。其中小时率等于JSON数据中的薪水值,工作日为8小时,月平均为20.88个工作日。

并创建能够与不同类型的员工一起工作的集合class。

主要问题是如何创建代表 Employees 集合的 EmployeeCollection class:

需要使用ES5!

//AbstractEmployee.js
var AbstractEmployee = function(id, name, salary) {
    if (this.constructor === AbstractEmployee) {
      throw new Error("Can't instantiate abstract class!");
    }

    this.id = id;
    this.name = name;
    this.salary = salary; 

    if(typeof(object.id) !== 'string' || typeof(object.name) !== 'string' || typeof(object.salary) !== 'number'){
        throw new Error("Wrong param passed!");
    }
};

AbstractEmployee.prototype.getSalary = function() {
    throw new Error('Method getSalary() must be implemented');
}

//PerHourSalaryEmployee.js
var AbstractEmployee = require('./AbstractEmployee.js')

var PerHourSalaryEmployee = function(id, name, salary) { 
    AbstractEmployee.apply(this, arguments)
    this.id = 'id' + id;
    this.name = name;
    this.salary = salary * 20.88 * 8; 
 };
 PerHourSalaryEmployee.prototype.getSalary = function() {
    return this.salary;
}

module.exports = PerHourSalaryEmployee

//FixedSalaryEmployee.js
var AbstractEmployee = require('./AbstractEmployee.js')

var FixedSalaryEmployee = function(id, name, salary) {
    AbstractEmployee.apply(this, arguments);
    this.id = 'id' + id;
    this.name = name;
    this.salary = salary; 
};

FixedSalaryEmployee.prototype.getSalary = function() {
    return this.salary;
}

module.exports = FixedSalaryEmployee

员工-collection.json

[{
  "type": "per-hour",
  "salary": 10,
  "name": "Anna"
},
{
  "type": "per-hour",
  "salary": 8,
  "name": "Bob"
},
{
  "type": "fixed",
  "salary": 8000,
  "name": "Dany"
},
{
  "type": "fixed",
  "salary": 8000,
  "name": "Clara"
},
{
  "type": "fixed",
  "salary": 1000,
  "name": "Egor"
}]

如前所述,半生不熟的 AbstractEmployee 函数仅用作基于函数的 mixin 没有实际意义。

一个纯粹的老派(它被要求/仅限于 ES5 语法)继承方法更合适。

实际上甚至不需要 BaseEmployee 构造函数,因为 FixedSalaryEmployee 类型的特征与 BaseEmployee 类型的特征完全相同,而 PerHourSalaryEmployee 类型仅在其 salary 属性 的 internal/initial 计算上有所不同(但人们永远不知道未来还会带来什么)...

function orderBySalaryDescendingAndNameAscending(a, b) {
  return (b.salary - a.salary) || a.name.localeCompare(b.name);
}

// employee factory.
function createTypeDependedEmployeeVariant(rawData, idx) {
  const { type, name, salary } = rawData;

  const employee = (type === 'per-hour')
    ? new PerHourSalaryEmployee(String(idx), name, salary)
    : new FixedSalaryEmployee(String(idx), name, salary)

  // employee.type = type;
  return employee;
}

// employee list factory.
function createOrderedListOfVariousEmployeeInstances(arr) {
  return arr
    .map(createTypeDependedEmployeeVariant)
    .sort(orderBySalaryDescendingAndNameAscending);
}

const jsonDataList = [{
  "type": "per-hour",
  "salary": 10,
  "name": "Anna"
}, {
  "type": "per-hour",
  "salary": 8,
  "name": "Bob"
}, {
  "type": "fixed",
  "salary": 8000,
  "name": "Dany"
}, {
  "type": "fixed",
  "salary": 8000,
  "name": "Clara"
}, {
  "type": "fixed",
  "salary": 1000,
  "name": "Egor"
}];

console.log(
  createOrderedListOfVariousEmployeeInstances(jsonDataList)
    .map(({ id, name, salary }) => ({ id, name, salary }))
);
console.log(
  createOrderedListOfVariousEmployeeInstances(jsonDataList)
    .map(item => item.getSalary())
);
console.log(
  createOrderedListOfVariousEmployeeInstances(jsonDataList)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
  function BaseEmployee(id, name, salary) {
    if (
      (typeof id !== 'string') ||
      (typeof name !== 'string') ||
      (typeof salary !== 'number') ||
      !Number.isFinite(salary)
    ) {
      throw new TypeError('Wrong parameter(s) passed!');
    }
    this.id = 'id' + id;
    this.name = name;
    this.salary = salary;
  }
  BaseEmployee.prototype.getSalary = function() {
    return this.salary;
  }
</script>

<script>
  function PerHourSalaryEmployee (id, name, salary) {
    // super call.
    BaseEmployee.apply(this, arguments);

    this.salary = (salary * 20.88 * 8);
  };
  // extend superclass.
  PerHourSalaryEmployee.prototype = Object.create(BaseEmployee.prototype);

  // prevent super constructor from being the sub-classed constructor.
  PerHourSalaryEmployee.prototype.constructor = PerHourSalaryEmployee;
</script>

<script>
  function FixedSalaryEmployee(id, name, salary) {
    // super call.
    BaseEmployee.apply(this, arguments);
  };
  // extend superclass.
  FixedSalaryEmployee.prototype = Object.create(BaseEmployee.prototype);

  // prevent super constructor from being the sub-classed constructor.
  FixedSalaryEmployee.prototype.constructor = FixedSalaryEmployee;
</script>

最优化的 Employee-class 代码库 would/could 看起来像下面提供的代码。与上面的代码库相比,上面提供的工厂的用法没有区别,上面的代码库具有额外的 BaseEmployee ...

function checkEmployeeArguments(id, name, salary) {
  if (
    (typeof id !== 'string') ||
    (typeof name !== 'string') ||
    (typeof salary !== 'number') ||
    !Number.isFinite(salary)
  ) {
    throw new TypeError('Wrong parameter(s) passed!');
  }
}

function FixedSalaryEmployee(id, name, salary) {
  checkEmployeeArguments(id, name, salary);

  this.id = 'id' + id;
  this.name = name;
  this.salary = salary;
}
FixedSalaryEmployee.prototype.getSalary = function() {
  return this.salary;
}
function PerHourSalaryEmployee (id, name, salary) {
  // super call.
  FixedSalaryEmployee.apply(this, arguments);

  this.salary = (salary * 20.88 * 8);
};
// extend superclass.
PerHourSalaryEmployee.prototype = Object.create(FixedSalaryEmployee.prototype);

// prevent super constructor from being the sub-classed prototype constructor.
PerHourSalaryEmployee.prototype.constructor = PerHourSalaryEmployee;