Домашнее задание по Java проблема с абстрактным классом и внешним компаратором. Написал код почти работающий
Что нужно сделать Выполните задание в репозитории java_basics в проекте AbstractClasses/practice_1. Директория пустая, вам необходимо в ней создать новый проект и выполнить задание.
- Создайте класс компании Company, содержащей сотрудников и реализующей методы:
найм одного сотрудника — hire(Employee employee), найм списка сотрудников – hireAll(Collection employes), увольнение сотрудника – fire(Employee employee), получение значения дохода компании – getIncome(). Каждый метод НЕ должен иметь модификатор static, это позволит каждому объекту класса Company иметь свой набора сотрудников, свой расчет дохода, увольнение и найм. Аргументы и возвращаемое значение методов выберите на основании логики работы вашего приложения.
- Создайте два метода, возвращающие список указанной длины (count). Они должны содержать сотрудников, отсортированных по убыванию и возрастанию заработной платы:
List getTopSalaryStaff(int count), List getLowestSalaryStaff(int count).
- Создайте классы сотрудников с информацией о зарплатах и условиями начисления зарплаты:
Manager — зарплата складывается из фиксированной части и бонуса в виде 5% от заработанных для компании денег. Количество заработанных денег для компании генерируйте случайным образом от 115 000 до 140 000 рублей. TopManager — зарплата складывается из фиксированной части и бонуса в виде 150% от заработной платы, если доход компании более 10 млн рублей. Operator — зарплата складывается только из фиксированной части. Каждый класс сотрудника должен имплементировать интерфейс Employee. В интерфейсе Employee должен быть объявлен метод, возвращающий зарплату сотрудника, — getMonthSalary().
Аргументы и возвращаемое значение метода выберите в соответствии с логикой начисления зарплат. В интерфейсе объявите необходимые методы. Для демонстрации и тестирования работы ваших классов:
Создайте и наймите в компанию: 180 операторов Operator, 80 менеджеров по продажам Manager, 10 топ-менеджеров TopManager. Распечатайте список из 10–15 самых высоких зарплат в компании. Распечатайте список из 30 самых низких зарплат в компании. Увольте 50% сотрудников. Распечатайте список из 10–15 самых высоких зарплат в компании. Распечатайте список из 30 самых низких зарплат в компании.
Еще не сказано что нужно написать работающий компаратор. я по честному перелопатил варианты с кодом, но так и не нашел как составить компаратор так чтобы премия начислялась в соответствии с условием в классе TopManager if ( company.getCompanyRevenue() > 10_000_000.0) , а не так как сейчас премия начисляется при Доходе компании : 800000.0 невзирая на условие в 10_000_000.0. Дайте зацепочку.
- прошу подсказать как правильно задавать здесь вопросы, это мой первый опыт.
- подскажите с решением.
import java.util.*;
public class Company {
private double inCome = 0;
List <Employee> employees = new ArrayList<>();
public void hire (Employee employee) {
employees.add(employee);
}
public void hireAll (List <Employee> employees) {
for ( Employee e : employees) {
hire(e);
}
}
public void fire (Employee employee) {
employees.remove(employee);
}
public double getInCome () {
return inCome;
}
public List <Employee> getTopSalaryStaff (int count) {
employees.sort(new SortByTopSalaryStaff());
if (count < 0 && count > employees.size()) {
List <Employee> EmptyList = new ArrayList<>();
System.out.println("неверное количество");
return EmptyList;
}
return employees.subList(0, count);
}
public List <Employee> getLowestSalaryStaff (int count) {
employees.sort(new SortByLowestSalaryStaff());
if (count < 0 && count > employees.size()) {
List <Employee> EmptyList = new ArrayList<>();
System.out.println("неверное количество");
return EmptyList;
}
return employees.subList(0, count);
}
public double getCompanyRevenue () {
for (Employee e : employees) {
inCome = inCome + e.getRevenue();
}
return inCome;
}
}
public interface Employee {
double getMonthSalary ();
double getRevenue();
}
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Company company = new Company();
List <Employee> workers = new ArrayList<>();
Operator operator = new Operator();
//Manager manager = new Manager();
//TopManager topManager = new TopManager(company);
company.hire(operator);
for (int i = 0; i < 180; i++){
workers.add(new Operator());
}
for (int i = 0; i < 80; i++) {
workers.add(new Manager());
if ( i%8 == 0 ) {
workers.add(new TopManager(company));
}
}
company.hireAll(workers);
System.out.println();
System.out.println("Количество работников : " + company.employees.size());
System.out.println();
System.out.println("Доход компании : " + company.getCompanyRevenue());
System.out.println();
System.out.println("topSalaryStaff");
System.out.println();
List <Employee> topSalaryStaff = company.getTopSalaryStaff(12);
for (Employee e: topSalaryStaff) {
System.out.println(e.getMonthSalary());
}
System.out.println("--------------------------------------");
/*
System.out.println();
System.out.println("lowSalaryStaff");
System.out.println();
List <Employee> lowSalaryStaff = company.getLowestSalaryStaff(12);
for (Employee e: lowSalaryStaff) {
System.out.println(e.getMonthSalary());
}
System.out.println("--------------------------------------");
*/
}
}
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
Company company = new Company();
List <Employee> workers = new ArrayList<>();
Operator operator = new Operator();
//Manager manager = new Manager();
//TopManager topManager = new TopManager(company);
company.hire(operator);
for (int i = 0; i < 180; i++){
workers.add(new Operator());
}
for (int i = 0; i < 80; i++) {
workers.add(new Manager());
if ( i%8 == 0 ) {
workers.add(new TopManager(company));
}
}
company.hireAll(workers);
System.out.println();
System.out.println("Количество работников : " + company.employees.size());
System.out.println();
System.out.println("Доход компании : " + company.getCompanyRevenue());
System.out.println();
System.out.println("topSalaryStaff");
System.out.println();
List <Employee> topSalaryStaff = company.getTopSalaryStaff(12);
for (Employee e: topSalaryStaff) {
System.out.println(e.getMonthSalary());
}
System.out.println("--------------------------------------");
/*
System.out.println();
System.out.println("lowSalaryStaff");
System.out.println();
List <Employee> lowSalaryStaff = company.getLowestSalaryStaff(12);
for (Employee e: lowSalaryStaff) {
System.out.println(e.getMonthSalary());
}
System.out.println("--------------------------------------");
*/
}
}
public class Operator implements Employee {
private double salary = 30_000;
final double income = 0;
@Override
public double getMonthSalary() {
return salary;
}
@Override
public double getRevenue() {
return income;
}
}
import java.util.Comparator;
public class SortByLowestSalaryStaff implements Comparator<Employee> {
@Override
public int compare(Employee employee1, Employee employee2) {
if (employee1.getMonthSalary() > employee2.getMonthSalary()) {
return 1;
}
if (employee1.getMonthSalary() == employee2.getMonthSalary()) {
return 0;
}
return -1;
}
}
import java.util.Comparator;
public class SortByTopSalaryStaff implements Comparator <Employee> {
@Override
public int compare(Employee employee1, Employee employee2) {
return Double.compare(employee2.getMonthSalary(), employee1.getMonthSalary());
}
/*
@Override
public int compare(Employee employee1, Employee employee2) {
if (employee1.getMonthSalary() < employee2.getMonthSalary()) {
return 1;
}
if (employee1.getMonthSalary() == employee2.getMonthSalary()) {
return 0;
}
return -1;
}
*/
}
import java.util.Random;
public class TopManager implements Employee{
private final Company company;
private final double salary;
private final double bonus = 1.5;
private final double earnedLimit = 10_000_000.0;
final double income = 0;
public TopManager (Company company) {
this.company = company;
this.salary = 900000; // + new Random().nextInt(40000);
}
@Override
public double getRevenue() {
return income;
}
@Override
public double getMonthSalary() {
//double companyIncome = company.getCompanyRevenue();
if ( company.getCompanyRevenue() > earnedLimit) {
return salary + salary * bonus;
}
return salary;
}
}
Ответы (1 шт):
Основная ошибка в представленном коде -- некорректное вычисление выручки (revenue) компании в методе getCompanyRevenue()
, где значение переменной inCome
(данное название следует перевести как приБыль) НЕ обнуляется и соответственно "приБыль" будет нарастать при каждом вызове данного метода, то есть к примеру, при сортировке работников этот метод будет вызываться для каждого топ менеджера при сравнении его дохода с доходом любого другого сотрудника и "выручка" компании взлетит до небес.
Вероятно следовало закешировать вычисленное значение дохода, чтобы сократить количество ненужных вычислений:
public class Company {
private Double income = null;
// ...
public double getCompanyRevenue () {
if (null == income) {
income = calcIncome();
}
return income.doubleValue();
}
protected double calcIncome() {
double result = 0d;
for (var emp : employees) {
result += emp.getRevenue();
}
return result;
// или так (Stream API)
// return employees.stream().mapToDouble(Employee::getRevenue).sum();
}
}
Соответственно, при вызове других методов, которые изменяют штат / персонал компании, значение переменной income
следует сбрасывать в null
(исключительно в рамках данного учебного задания, предполагая, что эта программа однопоточная).
Дополнение
Может быть альтернативное решение без кеширования (дополнительной логики в геттере getCompanyRevenue
), но в любом случае потребуется реализовать отдельный метод для вычисления суммарной выручки/прибыли, который следует не забывать вызывать вместо сеттера в нужный момент, например после заполнения коллекции всех сотрудников.
public class Company {
// ...
private double income = 0d;
// простой геттер, без логики кеширования
public double getCompanyRevenue() {
return income;
}
public void calculateRevenue() {
var result = 0d;
for (var emp : employees) {
result += emp.getRevenue();
}
this.income = result;
}
// ...
}
В классе Main
следует вызвать этот метод после вызова hireAll
перед сортировкой:
// ...
company.hireAll(workers);
company.calculateRevenue();
Кроме того, в представленном коде для всех сотрудников их "выручка", которая возвращается из метода getRevenue
равна нулю, соответственно и выручка компании всегда будет нулевой.
Чтобы проверить возможность начисления бонусов для топ-менеджеров, нужно чтобы хотя бы операторы приносили 56К дохода при прочих входных данных.
Ещё одна типичная ошибка -- использование типа с плавающей точкой double
для хранения результатов финансовых вычислений, где требуется фиксированная точность (например, до копейки).
Также в представленном коде можно улучшить реализацию методов getTopSalaryStaff
, getLowestSalaryStaff
в классе Company
.
Во-первых, сортировку следует выполнять после проверки входного параметра count
.
Во-вторых, условие if (count < 0 && count > employees.size())
бессмысленно и никогда не будет выполняться из-за неверной логической операции &&
, подразумевающей, что count
является отрицательным числом, большим нуля. Следовало использовать оператор ИЛИ ||
.
Кроме того, для неправильного аргумента имеет смысл выбрасывать соответствующее исключение типа IllegalArgumentException
, а не возвращать пустой список. Если же надо вернуть пустой список, лучше использовать стандартный метод Collections.emptyList
, а не создавать каждый раз пустой модифицируемый список.
В-третьих, отдельные классы компараторов НЕ нужны со времени появления Java 8 в 2014 году, вместо них следует использовать статические методы Comparator::comparingDouble
:
В-четвёртых, из указанных методов следует возвращать немодифицируемые списки при помощи Collections.unmodifiableList
.
public List <Employee> getTopSalaryStaff (int count) {
if (count <= 0 || count > employees.size()) {
return emptyListOnError(count);
}
employees.sort(Comparator
.comparingDouble(Employee::getMonthSalary)
.reversed()
);
return Collections.unmodifiableList(employees.subList(0, count));
}
private static List<Employee> emptyListOnError(int count) {
System.out.println("неверное количество: " + count);
return Collections.emptyList();
}
Аналогично при помощи Stream API и определения двух статических компараторов:
private static final Comparator<Employee> byMonthSalary = Comparator.comparingDouble(Employee::getMonthSalary);
private static final Comparator<Employee> byMonthSalaryDesc = byMonthSalary.reversed();
public List <Employee> getTopSalaryStaff (int count) {
return getNEmployees(count, byMonthSalaryDesc);
}
public List <Employee> getLowestSalaryStaff(int count) {
return getNEmployees(count, byMonthSalary);
}
private List<Employee> getNEmployees(int count, Comparator<Employee> comparator) {
return count <= 0 || count > employees.size()
? emptyListOnError(count)
: employees.stream()
.sorted(comparator)
.limit(count)
.toList();
}