我有抽象类AbstractEmployee
和两个具体子类FixedSalaryEmployee
和PerHourSalaryEmployee
,它们继承AbstractEmployee
并覆盖其抽象getSalary
方法,并正确实现给定的雇员类型。
首次实现FixedSalaryEmployee
-固定工资员工。其中平均月薪等于员工在JSON数据中的工资值。
第二个实现PerHourSalaryEmployee
-员工按小时工资。当小时率等于JSON数据中的工资值时,工作日为8小时,月平均为20.88个工作日。
并创建能够处理不同类型员工的Collection类。
主要问题是如何创建代表雇员集合的EmployeeCollection
类:
- 构造函数应该接受JSON文件中的数据,并根据
type
字段创建相应类的实例。- id应以
id<number>
格式生成,例如(id0
,id1
等,用于收集中的每个项目)
- id应以
- 收集项应按以下规则排序:
- 按月平均工资降序排序。
- 如果员工月平均工资相等,则使用员工名称。
需要使用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
employees-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
属性的内部/初始计算中有所不同(但人们永远不知道未来可能会带来什么)…
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
类代码库看起来像下面提供的代码。与上面提供的工厂相比,上面的代码库具有额外的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;