创建代表 Employees 集合的 class
Create class which represents collection of Employees
我有抽象的 Class AbstractEmployee
和两个具体的子 classes FixedSalaryEmployee
和 PerHourSalaryEmployee
继承自 AbstractEmployee
并覆盖它的抽象 getSalary
方法对给定的雇员类型具有正确的实现。
第一次实施 FixedSalaryEmployee
- 固定工资的员工。 JSON 数据中的平均月薪等于雇员的薪水值。
第二次实施PerHourSalaryEmployee
- 雇员按小时计薪。其中小时率等于JSON数据中的薪水值,工作日为8小时,月平均为20.88个工作日。
并创建能够与不同类型的员工一起工作的集合class。
主要问题是如何创建代表 Employees 集合的 EmployeeCollection
class:
- 构造函数应该接受来自 JSON 文件的数据,并根据
type
字段创建相应 classes 的实例。
- id 应以
id<number>
格式生成,例如(id0
、id1
等集合中的每个项目)
- 集合中的项目应按以下规则排序:
- 按平均月薪降序对所有员工进行排序。
- 如果员工的平均月薪相等,请改用员工姓名。
需要使用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;
我有抽象的 Class AbstractEmployee
和两个具体的子 classes FixedSalaryEmployee
和 PerHourSalaryEmployee
继承自 AbstractEmployee
并覆盖它的抽象 getSalary
方法对给定的雇员类型具有正确的实现。
第一次实施 FixedSalaryEmployee
- 固定工资的员工。 JSON 数据中的平均月薪等于雇员的薪水值。
第二次实施PerHourSalaryEmployee
- 雇员按小时计薪。其中小时率等于JSON数据中的薪水值,工作日为8小时,月平均为20.88个工作日。
并创建能够与不同类型的员工一起工作的集合class。
主要问题是如何创建代表 Employees 集合的 EmployeeCollection
class:
- 构造函数应该接受来自 JSON 文件的数据,并根据
type
字段创建相应 classes 的实例。- 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
员工-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;