Skip to content

Latest commit

 

History

History

3.2.2

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

Задача 2. Задача от бухгалтеров

Описание

Следующая задача пришла от наших бухгалтеров. Бухгалтерская программа должна уметь проводить операции c различными агентами, как c физическими/юридическими лицами, так и с иностранными компаниями: чп, ип, ооо, зао, иклмн, ёпрст. С некоторых операций налог платить не нужно, некоторые облагаются подоходным налогом, с некоторых необходимо уплатить НДС. Необходимо расширить функциональность класса Bill возможностью работы с различными системами налогообложения.

Дополнительная информация

Практически в любом языке программирования, если вы напишете нечто подобное, вы получите не то, что вы могли ожидать:

System.out.println(0.1 + 0.2); // => 0.30000000000000004

Связанно это с тем, что числа в компьютере хранятся в двоичном виде, и конечные дроби в десятичной системе счисления 0.1 и 0.2 превращаются в бесконечные периодические дроби в двоичной системе счисления 0.00011001100110011010 и 0.00110011001100110011 соответственно. Как следствие, часть числа теряется, а значит, и точность при операциях с ними. Подробнее про представление вещественных чисел в компьютере на сайте ИТМО.

Для того чтобы производить расчёты с десятичными дробными числами, существует специальный класс BigDecimal (большое десятичное). Большое, потому что у него нет стандартных ограничений как у double (-1.7E+308 до 1.7E+308) или int (-2147483648 до 2147483647). Этот класс может хранить число, состоящее из 2,147,483,647 цифр, Карл! А десятичное, потому что каждая цифра числа хранится по отдельности, из-за чего не возникает проблем с потерями при переводе между системами счисления. В задаче предлагается принять некоторые неточности и использовать уже знакомый нам тип double. Плюсиком будет решение задачи № 2* (со звёздочкой).

Функционал программы

→ Создание нескольких счетов и расчет налогов для них.

Процесс реализации

  1. Класс Bill

В системе уже есть класс Bill, в который мы добавили поле TaxType taxType; и метод payTaxes():

class Bill {
    private double amount;
    private TaxType taxType;
    private TaxService taxService;
    
    public Bill(double amount, TaxType taxType, TaxService taxService) {
        this.amount = amount;
        this.taxType = taxType;
        this.taxService = taxService;
    }
    
    public void payTaxes() {
        // TODO вместо 0.0 посчитать размер налога исходя из TaxType
        double taxAmount = 0.0;
        
        taxService.payOut(taxAmount);
    }
}

А также класс налоговой службы:

class TaxService {
    public void payOut(double taxAmount) {
        System.out.format("Уплачен налог в размере %.2f%n", taxAmount);
    }
}
  1. Создадим классы для различных типов налогообложения.
  • Базовый класс
class TaxType {
    public double calculateTaxFor(double amount) {
        // TODO override me!
        return 0.0;
    }
}
  • Классы, расширяющие TaxType:
    • Подоходный налог, = 13% (IncomeTaxType)
    • НДС, = 18% (VATaxType)
    • Прогрессивный налог, до 100 тысяч = 10%, больше 100 тысяч = 15% (ProgressiveTaxType)
  1. В методе main создадим несколько счетов и оплатим с них налоги в налоговую службу.
public static void main(String[] args) {
    TaxService taxService = new TaxService();
    Bill[] payments = new Bill[] {
        // TODO создать платежи с различным типами налогообложения
    };
    for (int i = 0; i < payments.length; ++i) {
        Bill bill = payments[i];
        bill.payTaxes();
    }
}

Задача 2*

Здесь необходимо реализовать тот же функционал, но используя вместо double –> BigDecimal.

Работа с ним может показаться необычной и странной. Например, их нельзя сложить, используя оператор + (в Java запрещено перегружать операторы), или сравнить с помощью == (так как это объект, произойдёт сравнение ссылок, а не значений объектов). Вместо этого мы должны использовать методы .add(…) и .compareTo(…) соответственно.

Экземпляр этого класса можно создать с помощью new BigDecimal("0.1") или BigDecimal.valueOf(0.2). Как и String, экземпляры этого класса неизменяемые (иммутабельные), а методы .add(…), .multiply(…) возвращают новый объект, содержащий результат операции.

Например, чтобы сложить 0.1 рубля и 0.2 рубля и получить ожидаемые 30 копеек, мы могли бы написать код:

BigDecimal first = new BigDecimal("0.10");
BigDecimal second = BigDecimal.valueOf(0.2);

BigDecimal sum = first.add(second);

System.out.println(sum.toString()); // => 0.30

При делении BigDecimal нужно обязательно указывать способ округления результата. Про способы округления чисел в BigDecimal можно почитать например, тут.