****************************************************************
Задание 4
1. Выберем операцию, с которой мы сможем начать.
Подумаем. В банкомате еще денег нет, поэтому INFO и WITHDRAW протестить не получится.
Начнем с операции DEPOSIT - поместить деньги.
Считаем с консоли код валюты, потом считаем номинал и количество банкнот, а потом добавим их в манипулятор.

2. Чтобы считать код валюты, добавим статический метод String askCurrencyCode() в ConsoleHelper.
Этот метод должен предлагать пользователю ввести код валюты, проверять, что код содержит 3 символа.
Если данные некорректны, то сообщить об этом пользователю и повторить.
Если данные валидны, то перевести код в верхний регистр и вернуть.

3. Чтобы считать номинал и количество банкнот, добавим статический метод String[] getValidTwoDigits(String currencyCode) в ConsoleHelper.
Этот метод должен предлагать пользователю ввести два целых положительных числа.
Первое число - номинал, второе - количество банкнот.
Никаких валидаторов на номинал нет. Т.е. 1200 - это нормальный номинал.
Если данные некорректны, то сообщить об этом пользователю и повторить.
Пример вводимых данных:
200 5

4. В классе CurrencyManipulator создайте метод void addAmount(int denomination, int count),
который добавит введенные номинал и количество банкнот

5. Пора уже увидеть приложение в действии.
В методе main захардкодь логику пункта 1.
Кстати, чтобы не было проблем с тестами на стороне сервера, добавь в метод main первой строчкой Locale.setDefault(Locale.ENGLISH);
Запускаем, дебажим, смотрим.


****************************************************************
Задание 3
1. Создадим класс CurrencyManipulator, который будет хранить всю информацию про выбранную валюту.
String currencyCode - код валюты, например, USD. Состоит из трех букв
Map<Integer, Integer> denominations - это Map<номинал, количество>
Чтобы можно было посмотреть, к какой валюте относится манипулятор, добавим геттер для currencyCode
Очевидно, что манипулятор никак не может функционировать без названия валюты,
поэтому добавим конструктор с этим параметром и проинициализируем currencyCode

2. Валют может быть несколько, поэтому нам понадобится фабрика, которая будет создавать и хранить манипуляторы.
Создадим класс CurrencyManipulatorFactory со статическим методом getManipulatorByCurrencyCode(String currencyCode).
В этом методе будем создавать нужный манипулятор, если он еще не существует, либо возвращать ранее созданный.
Подумайте, где лучше хранить все манипуляторы.
Сделайте так, чтобы невозможно было создавать объекты CurrencyManipulatorFactory класса


****************************************************************
Задание 2
1. Создадим в ConsoleHelper два статических метода:
1.1 writeMessage(String message), который будет писать в консоль наше сообщение
1.2 String readString(), который будет считывать с консоли строку и возвращать ее.
Если возникнет какое-то исключение при работе с консолью, то перехватим его и не будем обрабатывать.
Кстати, создадим только один экземпляр BufferedReader-а

2. Создадим пакет exception, в который поместим два checked исключения:
2.1 InterruptOperationException будем кидать, когда нужно прервать текущую операцию и выйти из приложения
2.2 NotEnoughMoneyException будем кидать, когда не сможем выдать запрашиваемую сумму


****************************************************************
Задание 1

Давай напишем эмулятор работы банкомата.
Операции, которые будем поддерживать, следующие:
поместить деньги, снять деньги, показать состояние банкомата.
Также будем поддерживать мультивалютность.
Купюрами будем оперировать теми, которые поместим в банкомат.
Если для снятия требуемой суммы будет недостаточно банкнот, то сообщим юзеру об этом.
Понятно, что всё должно быть user friendly, поэтому придется наводить рюшечки.

Итак..
1. Создайте класс CashMachine с методом main.
2. Наши операции зададим в энуме Operation: INFO, DEPOSIT, WITHDRAW
Т.к. всё должно быть user friendly, то на выход из приложения надо попрощаться с юзером.
Поэтому добавим еще операцию EXIT
3. Т.к мы будем активно общаться с юзером, то будет много выводимого текста.
Чтобы работу с консолью сосредоточить в одном месте, создадим класс ConsoleHelper

 

package com.javarush.test.level26.lesson15.big01;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by promoscow on 20.02.17.
 */
public class CurrencyManipulator {
    private String currencyCode;
    public static Map<Integer, Integer> denominations = new HashMap<>();

    public String getCurrencyCode() {
        return currencyCode;
    }

    public CurrencyManipulator(String currencyCode) {
        this.currencyCode = currencyCode;
    }

    public void addAmount(int denomination, int count) {
        for (Map.Entry<Integer, Integer> entry : denominations.entrySet()) {
            if (entry.getKey() == denomination) {
                int cash = entry.getValue() + count;
                entry.setValue(cash);
                return;
            }
        }
        denominations.put(denomination, count);
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import java.util.ArrayList;

/**
 * Created by promoscow on 20.02.17.
 */
public final class CurrencyManipulatorFactory {
    private static ArrayList <CurrencyManipulator> manipulators = new ArrayList<>();

    public static CurrencyManipulator getManipulatorByCurrencyCode(String currencyCode) {
        for (CurrencyManipulator manipulator : manipulators) {
            if (manipulator.getCurrencyCode().equals(currencyCode)) return manipulator;
        }
        CurrencyManipulator newManipulator = new CurrencyManipulator(currencyCode);
        manipulators.add(newManipulator);
        return newManipulator;
    }

    private CurrencyManipulatorFactory() {
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by promoscow on 20.02.17.
 */
public class ConsoleHelper {

    private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static void writeMessage(String message) {
        System.out.println(message);
    }

    public static String readString() throws InterruptOperationException, NotEnoughMoneyException {

        String s = "";
        try {
            s = reader.readLine();
        } catch (IOException e) {

        }
        return s;
    }

    public static String askCurrencyCode() throws NotEnoughMoneyException, InterruptOperationException {
        System.out.println("ВВЕДИТЕ КОД ВАЛЮТЫ:");
        String currencyCode;
        while (true) {
            currencyCode = readString();
            if (isCorrectCurrency(currencyCode)) break;
            System.out.println("КОД ВАЛЮТЫ МОЖЕТ СОДЕРЖАТЬ 3 СИМВОЛА АНГЛИЙСКОГО АЛФАВИТА. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
        }
        return currencyCode.toUpperCase();
    }

    private static boolean isCorrectCurrency(String newNickname) {
        Pattern p = Pattern.compile("^[a-zA-Z]{3}$");
        Matcher m = p.matcher(newNickname);
        return m.matches();
    }

    public static String[] getValidTwoDigits(String currencyCode) throws NotEnoughMoneyException, InterruptOperationException {
        System.out.println("ВВЕДИТЕ НОМИНАЛ И КОЛИЧЕСТВО БАНКНОТ (ЧЕРЕЗ ПРОБЕЛ):");
        int denomination = 0;
        int amount = 0;
        while (true) {
            String enter = readString();
            StringTokenizer st = new StringTokenizer(enter, " ");
            if (st.countTokens() == 2) {
                try {
                    denomination = Integer.parseInt(st.nextToken());
                    amount = Integer.parseInt(st.nextToken());
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
                return new String[]{String.valueOf(denomination), String.valueOf(amount)};
            }
            System.out.println("НЕКОРРЕКТНЫЙ ВВОД. ВВЕДИТЕ НОМИНАЛ И КОЛ-ВО ВАЛЮТ.");
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01;

/**
 * Created by promoscow on 20.02.17.
 */
public enum Operation {
    INFO,
    DEPOSIT,
    WITHDRAW,
    EXIT
}

 

package com.javarush.test.level26.lesson15.big01.exception;

/**
 * Created by promoscow on 20.02.17.
 */
public class InterruptOperationException extends Exception {
    public InterruptOperationException() {

    }
}

 

package com.javarush.test.level26.lesson15.big01.exception;

/**
 * Created by promoscow on 20.02.17.
 */
public class NotEnoughMoneyException extends Exception {
    public NotEnoughMoneyException() {

    }
}

 

package com.javarush.test.level26.lesson15.big01;

/**
 * Created by promoscow on 20.02.17.
 */
public class CashMachine {
    public static void main(String[] args) {
    }
}
****************************************************************
Задание 5
1.В предыдущем таске мы реализовали основную логику операции DEPOSIT.
Но посмотреть результат так и не удалось.
Поэтому создадим в манипуляторе метод int getTotalAmount(), который посчитает общую сумму денег для выбранной валюты.

2. Добавим вызов метода getTotalAmount() в метод main.
Всё работает верно? Тогда движемся дальше.
Видно, что метод getTotalAmount() считает то, что нам необходимо для операции INFO.
Поэтому пришло время небольшого рефакторинга.
!!Читайте паттерн Command.
Однако, перед рефакторингом нужно еще разобраться в одном вопросе. Но об этом не сейчас.

 

package com.javarush.test.level26.lesson15.big01;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by promoscow on 20.02.17.
 */
public class CurrencyManipulator {
    private String currencyCode;
    public static Map<Integer, Integer> denominations = new HashMap<>();

    public String getCurrencyCode() {
        return currencyCode;
    }

    public CurrencyManipulator(String currencyCode) {
        this.currencyCode = currencyCode;
    }

    public void addAmount(int denomination, int count) {
        for (Map.Entry<Integer, Integer> entry : denominations.entrySet()) {
            if (entry.getKey() == denomination) {
                int cash = entry.getValue() + count;
                entry.setValue(cash);
                return;
            }
        }
        denominations.put(denomination, count);
    }

    public int getTotalAmount() {
        int count = 0;
        for (Map.Entry<Integer, Integer> entry : denominations.entrySet()) count += (entry.getKey() * entry.getValue());
        return count;
    }
}
****************************************************************
Задание 8
Пора привести в порядок наш main, уж очень там всего много, чего не должно быть.

1. Перенесите логику из main в DepositCommand и InfoCommand
Проверим, что там стало с main? Цикл, в котором спрашиваем операцию у пользователя, а потом вызываем метод у CommandExecutor.
И так до бесконечности... надо бы придумать условие выхода из цикла.
Исправь цикл, чтоб он стал do-while. Условие выхода - операция EXIT.

2. Давайте запустим прогу и пополним счет на EUR 100 2 и USD 20 6, и посмотрим на INFO.
Ничего не понятно, т.к. создались 2 манипулятора: первый для EUR, второй для USD.
Давайте улучшим логику InfoCommand. Надо вывести баланс по каждому манипулятору.

2.1. В классе CurrencyManipulatorFactory создайте статический метод getAllCurrencyManipulators(), который вернет Collection всех манипуляторов.
У вас все манипуляторы хранятся в карте, не так ли? Если нет, то рефакторьте.
2.2. В InfoCommand в цикле выведите [код валюты - общая сумма денег для выбранной валюты]
Запустим прогу и пополним счет на EUR 100 2 и USD 20 6, и посмотрим на INFO.
Все работает правильно?
 EUR - 200
 USD - 120
Отлично!

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
interface Command {
    void execute() throws InterruptOperationException, NotEnoughMoneyException;
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.Operation;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by promoscow on 21.02.17.
 */
public final class CommandExecutor {
    private static Map<Operation, Command> commands = new HashMap<>();

    private CommandExecutor() {
    }

    static {
        commands.put(Operation.DEPOSIT, new DepositCommand());
        commands.put(Operation.EXIT, new ExitCommand());
        commands.put(Operation.INFO, new InfoCommand());
        commands.put(Operation.WITHDRAW, new WithdrawCommand());
    }

    public static final void execute(Operation operation) throws NotEnoughMoneyException, InterruptOperationException {
        if (commands.containsKey(operation)) {
            commands.get(operation).execute();
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulator;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulatorFactory;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
class DepositCommand implements Command {
    @Override
    public void execute() throws InterruptOperationException, NotEnoughMoneyException {

        String currencyCode = ConsoleHelper.askCurrencyCode();
        CurrencyManipulator manipulator = CurrencyManipulatorFactory.getManipulatorByCurrencyCode(currencyCode);
        String[] digits = ConsoleHelper.getValidTwoDigits();
        manipulator.addAmount(Integer.parseInt(digits[0]), Integer.parseInt(digits[1]));
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

/**
 * Created by promoscow on 21.02.17.
 */
class ExitCommand implements Command {
    @Override
    public void execute() {

    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulator;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulatorFactory;

import java.util.Collection;

/**
 * Created by promoscow on 21.02.17.
 */
class InfoCommand implements Command {
    @Override
    public void execute() {
        Collection<CurrencyManipulator> collection = CurrencyManipulatorFactory.getAllCurrencyManipulators();
        boolean hasMoney = false;
        for (CurrencyManipulator currencyManipulator : collection) {
            hasMoney = (currencyManipulator.hasMoney() && currencyManipulator.getTotalAmount() != 0 || hasMoney);
            if (currencyManipulator.getTotalAmount() != 0) {
                ConsoleHelper.writeMessage(currencyManipulator.getCurrencyCode() + " - " + currencyManipulator.getTotalAmount());
            }
        }
        if (!hasMoney) ConsoleHelper.writeMessage("No money available.");
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

/**
 * Created by promoscow on 21.02.17.
 */
class WithdrawCommand implements Command {
    @Override
    public void execute() {

    }
}

 

package com.javarush.test.level26.lesson15.big01.exception;

/**
 * Created by promoscow on 20.02.17.
 */
public class InterruptOperationException extends Exception {
    public InterruptOperationException() {

    }
}

 

package com.javarush.test.level26.lesson15.big01.exception;

/**
 * Created by promoscow on 20.02.17.
 */
public class NotEnoughMoneyException extends Exception {
    public NotEnoughMoneyException() {

    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.command.CommandExecutor;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.Locale;

/**
 * Created by promoscow on 20.02.17.
 */
public class CashMachine {
    public static void main(String[] args) throws InterruptOperationException, NotEnoughMoneyException {
        Locale.setDefault(Locale.ENGLISH);
        Operation operation = null;
        do {
            operation = ConsoleHelper.askOperation();
            CommandExecutor.execute(operation);
        } while (!operation.equals(Operation.EXIT));
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Created by promoscow on 20.02.17.
 */
public class ConsoleHelper {

    private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static void writeMessage(String message) {
        System.out.println(message);
    }

    public static String readString() throws InterruptOperationException, NotEnoughMoneyException {

        String s = "";
        try {
            s = reader.readLine();
        } catch (IOException e) {

        }
        return s;
    }

    public static String askCurrencyCode() throws NotEnoughMoneyException, InterruptOperationException {
        writeMessage("ВВЕДИТЕ КОД ВАЛЮТЫ:");
        String currencyCode = "";
        while (true) {
            currencyCode = readString();
            if (isCorrectCurrency(currencyCode)) break;
            writeMessage("КОД ВАЛЮТЫ МОЖЕТ СОДЕРЖАТЬ 3 СИМВОЛА АНГЛИЙСКОГО АЛФАВИТА. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
        }
        return currencyCode.toUpperCase();
    }

    private static boolean isCorrectCurrency(String newNickname) {
        Pattern p = Pattern.compile("^[a-zA-Z]{3}$");
        Matcher m = p.matcher(newNickname);
        return m.matches();
    }

    public static String[] getValidTwoDigits() throws NotEnoughMoneyException, InterruptOperationException {
        writeMessage("ВВЕДИТЕ НОМИНАЛ И КОЛИЧЕСТВО БАНКНОТ (ЧЕРЕЗ ПРОБЕЛ):");
        String enter = "";
        while (true) {
            enter = readString();
            if (enter.matches("\\d+ \\d+")) break;
            writeMessage("НЕКОРРЕКТНЫЙ ВВОД. ВВЕДИТЕ НОМИНАЛ И КОЛ-ВО ВАЛЮТ.");
        }
        return enter.split(" ");
    }

    public static Operation askOperation() throws NotEnoughMoneyException, InterruptOperationException {
        Operation operation = null;
        while (true) {
            writeMessage("ВВЕДИТЕ КОД ОПЕРАЦИИ.");
            writeMessage("| INFO - 1 | DEPOSIT — 2 | WITHDRAW - 3 | EXIT - 4 |");
            try {
                operation = Operation.getAllowableOperationByOrdinal(Integer.valueOf(readString()));
                break;
            } catch (Exception e) {
                writeMessage("ДАННЫЕ НЕ ВЕРНЫ. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
            }
        }
        return operation;
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by promoscow on 20.02.17.
 */
public class CurrencyManipulator {
    public Map<Integer, Integer> denominations = new HashMap<Integer, Integer>();
    private String currencyCode = "";

    public CurrencyManipulator(String currencyCode) {
        this.currencyCode = currencyCode;
    }

    public String getCurrencyCode() {
        return currencyCode;
    }

    public void addAmount(int denomination, int count) {
        if(denominations.containsKey(denomination)){
            denominations.put(denomination, denominations.get(denomination) + count);
        }else{
            denominations.put(denomination, count);
        }
    }

    public int getTotalAmount() {
        int count = 0;
        for (Map.Entry<Integer, Integer> entry : denominations.entrySet()) count += (entry.getKey() * entry.getValue());
        return count;
    }

    public boolean hasMoney() {
        return (!denominations.isEmpty());
    }
}

 

package com.javarush.test.level26.lesson15.big01;

/**
 * Created by promoscow on 20.02.17.
 */
public enum Operation {
    INFO,
    DEPOSIT,
    WITHDRAW,
    EXIT;

    public static Operation getAllowableOperationByOrdinal(Integer i) {
        switch (i) {
            case 1:
                return INFO;
            case 2:
                return DEPOSIT;
            case 3:
                return WITHDRAW;
            case 4:
                return EXIT;
        }
        throw new IllegalArgumentException();
    }
}

==========

ЗАДАНИЕ 9

==========

****************************************************************
Задание 9
Сегодня мы займемся командой ExitCommand.
1. Реализуйте следующую логику в команде ExitCommand:
1.1. Спросить, действительно ли пользователь хочет выйти - варианты <y,n>.
1.2. Если пользователь подтвердит свои намерения, то попрощаться с ним.

Это всё хорошо, но бывают случаи, когда срочно нужно прервать операцию, например, если пользователь ошибся с выбором операции.
Для этого у нас есть InterruptOperationException.
2.Реализуйте следующую логику:
2.1. Если пользователь в любом месте ввел текст 'EXIT' любым регистром, то выбросить InterruptOperationException.
2.2. Найдите единственное место, куда нужно вставить эту логику. Реализуйте функционал в этом единственном методе.

3. Заверните тело метода main в try-catch и обработайте исключение InterruptOperationException.
Попрощайтесь с пользователем в блоке catch используя ConsoleHelper.


****************************************************************
Задание 8
Пора привести в порядок наш main, уж очень там всего много, чего не должно быть.

1. Перенесите логику из main в DepositCommand и InfoCommand
Проверим, что там стало с main? Цикл, в котором спрашиваем операцию у пользователя, а потом вызываем метод у CommandExecutor.
И так до бесконечности... надо бы придумать условие выхода из цикла.
Исправь цикл, чтоб он стал do-while. Условие выхода - операция EXIT.

2. Давайте запустим прогу и пополним счет на EUR 100 2 и USD 20 6, и посмотрим на INFO.
Ничего не понятно, т.к. создались 2 манипулятора: первый для EUR, второй для USD.
Давайте улучшим логику InfoCommand. Надо вывести баланс по каждому манипулятору.

2.1. В классе CurrencyManipulatorFactory создайте статический метод getAllCurrencyManipulators(), который вернет Collection всех манипуляторов.
У вас все манипуляторы хранятся в карте, не так ли? Если нет, то рефакторьте.
2.2. В InfoCommand в цикле выведите [код валюты - общая сумма денег для выбранной валюты]
Запустим прогу и пополним счет на EUR 100 2 и USD 20 6, и посмотрим на INFO.
Все работает правильно?
 EUR - 200
 USD - 120
Отлично!

3. Запустим прогу и сразу первой операцией попросим INFO. Ничего не вывело? Непорядок.
Добавьте в манипулятор метод boolean hasMoney(), который будет показывать, добавлены ли какие-то банкноты или нет.

4. В InfoCommand используйте метод п.3. и выведите фразу "No money available.", если нет денег в банкомате.


****************************************************************
Задание 7
Возвращаемся к паттерну Command.

1. Создадим пакет command, в нем будут все классы, относящиеся к этой логике.
Подумайте над модификатором доступа для всех классов в этом пакете.

2. Создадим интерфейс Command с методом void execute().

3. Для каждой операции создадим класс-команду, удовлетворяющую паттерну Command.
Имена классов DepositCommand, InfoCommand, WithdrawCommand, ExitCommand

4. Создадим public класс CommandExecutor, через который можно будет взаимодействовать со всеми командами.
Создадим ему статическую карту Map<Operation, Command>, которую проинициализируем всеми известными нам операциями и командами.

4.1 Создадим метод public static final void execute(Operation operation), который будет дергать метод execute у нужной команды.
Реализуйте эту логику.
4.2. Расставьте правильно модификаторы доступа учитывая, что единственная точка входа - это метод execute.

Проверяем, чтоб структура соответствовала тестам на сервере.
Логику будем переносить в следующем таске.


****************************************************************
Задание 6
Чтобы отрефакторить код в соответствии с паттерном Command, нужно выделить в коде несколько логических блоков кода.
У нас пока два таких блока: 1) код операции DEPOSIT, 2) код операции INFO.
Они захардкожены в методе main. Нужно от этого избавиться.
Нужно сделать так, чтобы пользователь сам выбирал, какую операцию на данный момент нужно выполнять.

1. В энум Operation добавьте статический метод Operation getAllowableOperationByOrdinal(Integer i)
Должен возвращать элемент энума: для 1 - INFO, 2 - DEPOSIT, 3 - WITHDRAW, 4 - EXIT;
На некорректные данные бросать IllegalArgumentException

2. В классе ConsoleHelper реализуйте логику статического метода Operation askOperation()
Спросить у пользователя операцию.
Если пользователь вводит 1, то выбирается команда INFO, 2 - DEPOSIT, 3 - WITHDRAW, 4 - EXIT;
Используйте метод, описанный в п.1.
Обработай исключение - запроси данные об операции повторно.


****************************************************************
Задание 5
1.В предыдущем таске мы реализовали основную логику операции DEPOSIT.
Но посмотреть результат так и не удалось.
Поэтому создадим в манипуляторе метод int getTotalAmount(), который посчитает общую сумму денег для выбранной валюты.

2. Добавим вызов метода getTotalAmount() в метод main.
Всё работает верно? Тогда движемся дальше.
Видно, что метод getTotalAmount() считает то, что нам необходимо для операции INFO.
Поэтому пришло время небольшого рефакторинга.
!!Читайте паттерн Command.
Однако, перед рефакторингом нужно еще разобраться в одном вопросе. Но об этом не сейчас.


****************************************************************
Задание 4
1. Выберем операцию, с которой мы сможем начать.
Подумаем. В банкомате еще денег нет, поэтому INFO и WITHDRAW протестить не получится.
Начнем с операции DEPOSIT - поместить деньги.
Считаем с консоли код валюты, потом считаем номинал и количество банкнот, а потом добавим их в манипулятор.

2. Чтобы считать код валюты, добавим статический метод String askCurrencyCode() в ConsoleHelper.
Этот метод должен предлагать пользователю ввести код валюты, проверять, что код содержит 3 символа.
Если данные некорректны, то сообщить об этом пользователю и повторить.
Если данные валидны, то перевести код в верхний регистр и вернуть.

3. Чтобы считать номинал и количество банкнот, добавим статический метод String[] getValidTwoDigits(String currencyCode) в ConsoleHelper.
Этот метод должен предлагать пользователю ввести два целых положительных числа.
Первое число - номинал, второе - количество банкнот.
Никаких валидаторов на номинал нет. Т.е. 1200 - это нормальный номинал.
Если данные некорректны, то сообщить об этом пользователю и повторить.
Пример вводимых данных:
200 5

4. В классе CurrencyManipulator создайте метод void addAmount(int denomination, int count),
который добавит введенные номинал и количество банкнот

5. Пора уже увидеть приложение в действии.
В методе main захардкодь логику пункта 1.
Кстати, чтобы не было проблем с тестами на стороне сервера, добавь в метод main первой строчкой Locale.setDefault(Locale.ENGLISH);
Запускаем, дебажим, смотрим.


****************************************************************
Задание 3
1. Создадим класс CurrencyManipulator, который будет хранить всю информацию про выбранную валюту.
String currencyCode - код валюты, например, USD. Состоит из трех букв
Map<Integer, Integer> denominations - это Map<номинал, количество>
Чтобы можно было посмотреть, к какой валюте относится манипулятор, добавим геттер для currencyCode
Очевидно, что манипулятор никак не может функционировать без названия валюты,
поэтому добавим конструктор с этим параметром и проинициализируем currencyCode

2. Валют может быть несколько, поэтому нам понадобится фабрика, которая будет создавать и хранить манипуляторы.
Создадим класс CurrencyManipulatorFactory со статическим методом getManipulatorByCurrencyCode(String currencyCode).
В этом методе будем создавать нужный манипулятор, если он еще не существует, либо возвращать ранее созданный.
Подумайте, где лучше хранить все манипуляторы.
Сделайте так, чтобы невозможно было создавать объекты CurrencyManipulatorFactory класса


****************************************************************
Задание 2
1. Создадим в ConsoleHelper два статических метода:
1.1 writeMessage(String message), который будет писать в консоль наше сообщение
1.2 String readString(), который будет считывать с консоли строку и возвращать ее.
Если возникнет какое-то исключение при работе с консолью, то перехватим его и не будем обрабатывать.
Кстати, создадим только один экземпляр BufferedReader-а

2. Создадим пакет exception, в который поместим два checked исключения:
2.1 InterruptOperationException будем кидать, когда нужно прервать текущую операцию и выйти из приложения
2.2 NotEnoughMoneyException будем кидать, когда не сможем выдать запрашиваемую сумму


****************************************************************
Задание 1

Давай напишем эмулятор работы банкомата.
Операции, которые будем поддерживать, следующие:
поместить деньги, снять деньги, показать состояние банкомата.
Также будем поддерживать мультивалютность.
Купюрами будем оперировать теми, которые поместим в банкомат.
Если для снятия требуемой суммы будет недостаточно банкнот, то сообщим юзеру об этом.
Понятно, что всё должно быть user friendly, поэтому придется наводить рюшечки.

Итак..
1. Создайте класс CashMachine с методом main.
2. Наши операции зададим в энуме Operation: INFO, DEPOSIT, WITHDRAW
Т.к. всё должно быть user friendly, то на выход из приложения надо попрощаться с юзером.
Поэтому добавим еще операцию EXIT
3. Т.к мы будем активно общаться с юзером, то будет много выводимого текста.
Чтобы работу с консолью сосредоточить в одном месте, создадим класс ConsoleHelper

2017-03-29_12-10-08

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
interface Command {
    void execute() throws InterruptOperationException;
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.Operation;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by promoscow on 21.02.17.
 */
public final class CommandExecutor {
    private static Map<Operation, Command> commands = new HashMap<>();

    static {
        commands.put(Operation.DEPOSIT, new DepositCommand());
        commands.put(Operation.EXIT, new ExitCommand());
        commands.put(Operation.INFO, new InfoCommand());
        commands.put(Operation.WITHDRAW, new WithdrawCommand());
    }

    private CommandExecutor() {
    }

    public static final void execute(Operation operation) throws InterruptOperationException {
        if (commands.containsKey(operation)) {
            commands.get(operation).execute();
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulator;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulatorFactory;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
class DepositCommand implements Command {
    @Override
    public void execute() throws InterruptOperationException {

        String currencyCode = ConsoleHelper.askCurrencyCode();
        CurrencyManipulator manipulator = CurrencyManipulatorFactory.getManipulatorByCurrencyCode(currencyCode);
        String[] digits = ConsoleHelper.getValidTwoDigits();
        manipulator.addAmount(Integer.parseInt(digits[0]), Integer.parseInt(digits[1]));
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
class ExitCommand implements Command {
    @Override
    public void execute() throws InterruptOperationException {
        ConsoleHelper.writeMessage("ВЫ ДЕЙСТВИТЕЛЬНО ХОТИТЕ ВЫЙТИ? (Y / N)");
        String answer = ConsoleHelper.readString().toLowerCase();
        if (answer.equals("y")) ConsoleHelper.writeMessage("УДАЧИ!");
        else if (answer.equals("n")) {}
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulator;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulatorFactory;

import java.util.Collection;

/**
 * Created by promoscow on 21.02.17.
 */
class InfoCommand implements Command {
    @Override
    public void execute() {
        Collection<CurrencyManipulator> collection = CurrencyManipulatorFactory.getAllCurrencyManipulators();
        boolean hasMoney = false;
        for (CurrencyManipulator currencyManipulator : collection) {
            hasMoney = (currencyManipulator.hasMoney() && currencyManipulator.getTotalAmount() != 0 || hasMoney);
            if (currencyManipulator.getTotalAmount() != 0) {
                ConsoleHelper.writeMessage(currencyManipulator.getCurrencyCode() + " - " + currencyManipulator.getTotalAmount());
            }
        }
        if (!hasMoney) ConsoleHelper.writeMessage("No money available.");
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

/**
 * Created by promoscow on 21.02.17.
 */
class WithdrawCommand implements Command {
    @Override
    public void execute() {

    }
}

 

package com.javarush.test.level26.lesson15.big01.exception;

/**
 * Created by promoscow on 20.02.17.
 */
public class InterruptOperationException extends Exception {
    public InterruptOperationException() {
//        ConsoleHelper.writeMessage("ВСЕГО ХОРОШЕГО.");
//        System.exit(0);
    }
}

 

package com.javarush.test.level26.lesson15.big01.exception;

/**
 * Created by promoscow on 20.02.17.
 */
public class NotEnoughMoneyException extends Exception {
    public NotEnoughMoneyException() {

    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.command.CommandExecutor;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.Locale;

/**
 * Created by promoscow on 20.02.17.
 */
public class CashMachine {
    public static void main(String[] args) {
        Locale.setDefault(Locale.ENGLISH);
            Operation operation = null;
        try {
            do {
                operation = ConsoleHelper.askOperation();
                CommandExecutor.execute(operation);
            } while (operation != Operation.EXIT);
        } catch (InterruptOperationException e) {
            ConsoleHelper.writeMessage("ВСЕГО ХОРОШЕГО.");
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Created by promoscow on 20.02.17.
 */
public class ConsoleHelper {

    private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static void writeMessage(String message) {
        System.out.println(message);
    }

    public static String readString() throws InterruptOperationException {

        String s = null;
        try {
            s = reader.readLine();
            if (s.toLowerCase().equals("exit")) {
                writeMessage("ВСЕГО ХОРОШЕГО!");
                throw new InterruptOperationException();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return s;
    }

    public static String askCurrencyCode() throws InterruptOperationException {
        writeMessage("ВВЕДИТЕ КОД ВАЛЮТЫ:");
        String currencyCode = "";
        while (true) {
            currencyCode = readString();
            if (currencyCode.matches("^[a-zA-Z]{3}$")) break;
            writeMessage("КОД ВАЛЮТЫ МОЖЕТ СОДЕРЖАТЬ 3 СИМВОЛА АНГЛИЙСКОГО АЛФАВИТА. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
        }
        return currencyCode.toUpperCase();
    }

    public static String[] getValidTwoDigits() throws InterruptOperationException {
        writeMessage("ВВЕДИТЕ НОМИНАЛ И КОЛИЧЕСТВО БАНКНОТ (ЧЕРЕЗ ПРОБЕЛ):");
        String enter = "";
        while (true) {
            enter = readString();
            if (enter.matches("\\d+ \\d+")) break;
            writeMessage("НЕКОРРЕКТНЫЙ ВВОД. ВВЕДИТЕ НОМИНАЛ И КОЛ-ВО ВАЛЮТ.");
        }
        return enter.split(" ");
    }

    public static Operation askOperation() throws InterruptOperationException {
        Operation operation = null;
        while (true) {
            writeMessage("ВВЕДИТЕ КОД ОПЕРАЦИИ.");
            writeMessage("| INFO - 1 | DEPOSIT — 2 | WITHDRAW - 3 | EXIT - 4 |");
            try {
                operation = Operation.getAllowableOperationByOrdinal(Integer.valueOf(readString()));
                break;
            } catch (Exception e) {
                writeMessage("ДАННЫЕ НЕ ВЕРНЫ. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
            }
        }
        return operation;
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by promoscow on 20.02.17.
 */
public class CurrencyManipulator {
    public Map<Integer, Integer> denominations = new HashMap<Integer, Integer>();
    private String currencyCode = "";

    public CurrencyManipulator(String currencyCode) {
        this.currencyCode = currencyCode;
    }

    public String getCurrencyCode() {
        return currencyCode;
    }

    public void addAmount(int denomination, int count) {
        if (denominations.containsKey(denomination)) {
            denominations.put(denomination, denominations.get(denomination) + count);
        } else {
            denominations.put(denomination, count);
        }
    }

    public int getTotalAmount() {
        int count = 0;
        for (Map.Entry<Integer, Integer> entry : denominations.entrySet()) count += (entry.getKey() * entry.getValue());
        return count;
    }

    public boolean hasMoney() {
        return (!denominations.isEmpty());
    }
}

 

package com.javarush.test.level26.lesson15.big01;

        import java.util.Collection;
        import java.util.HashMap;
        import java.util.Map;

/**
 * Created by promoscow on 20.02.17.
 */
public final class CurrencyManipulatorFactory {
    private static Map<String, CurrencyManipulator> manipulators = new HashMap<String, CurrencyManipulator>();

    private CurrencyManipulatorFactory() {
    }

    public static CurrencyManipulator getManipulatorByCurrencyCode(String currencyCode) {

        CurrencyManipulator result = null;
        if (manipulators.containsKey(currencyCode))
            result = manipulators.get(currencyCode);
        else {
            result = new CurrencyManipulator(currencyCode);
            manipulators.put(currencyCode, result);
        }
        return result;
    }


    public static Collection<CurrencyManipulator> getAllCurrencyManipulators () {
        return manipulators.values();
    }
}

 

package com.javarush.test.level26.lesson15.big01;

/**
 * Created by promoscow on 20.02.17.
 */
public enum Operation {
    INFO,
    DEPOSIT,
    WITHDRAW,
    EXIT;

    public static Operation getAllowableOperationByOrdinal(Integer i) {
        switch (i) {
            case 1:
                return INFO;
            case 2:
                return DEPOSIT;
            case 3:
                return WITHDRAW;
            case 4:
                return EXIT;
        }
        throw new IllegalArgumentException();
    }
}

==========

ЗАДАНИЕ 10.

==========

****************************************************************
Задание 10
Сегодня мы займемся командой WithdrawCommand - это самая сложная операция.

1. Реализуйте следующий алгоритм для команды WithdrawCommand:
1.1. Считать код валюты (метод уже есть)
1.2. Получить манипулятор для этой валюты.
1.3. Пока пользователь не введет корректные данные выполнять:
1.3.1. Попросить ввести сумму
1.3.2. Если введены некорректные данные, то сообщить об этом пользователю и вернуться к п. 1.3.
1.3.3. Проверить, достаточно ли средств на счету.
Для этого в манипуляторе создайте метод boolean isAmountAvailable(int expectedAmount), который вернет true, если денег достаточно для выдачи.
Если недостаточно, то вернуться к п. 1.3.
1.3.4. Списать деньги со счета. Для этого в манируляторе создайте метод
Map<Integer, Integer> withdrawAmount(int expectedAmount), который вернет карту Map<номинал, количество>.
Подробно логику этого метода смотрите в п.2.
1.3.5. Вывести пользователю результат из п. 1.3.4. в следующем виде:
<табуляция>номинал - количество
Сортировка - от большего номинала к меньшему.
Вывести сообщение об успешной транзакции.
1.3.6. Перехватить исключение NotEnoughMoneyException, уведомить юзера о нехватке банкнот и вернуться к п. 1.3.

2. Логика основного метода withdrawAmount:
2.1. Внимание!!! Метод withdrawAmount должен возвращать минимальное количество банкнот, которыми набирается запрашиваемая сумма.
Используйте Жадный алгоритм (use google).
Если есть несколько вариантов, то использовать тот, в котором максимальное количество банкнот высшего номинала.
Если для суммы 600 результат - три банкноты: 500 + 50 + 50 = 200 + 200 + 200, то выдать первый вариант.
Пример, надо выдать 600
В манипуляторе есть следующие банкноты:
500 - 2
200 - 3
100 - 1
50 - 12
Результат должен быть таким:
500 - 1
100 - 1
т.е. всего две банкноты (это минимальное количество банкнот) номиналом 500 и 100.

2.2. Мы же не можем одни и те же банкноты выдавать несколько раз, поэтому
если мы нашли вариант выдачи денег (п.2.1. успешен), то вычесть все эти банкноты из карты в манипуляторе.

2.3. метод withdrawAmount должен кидать NotEnoughMoneyException, если купюрами невозможно выдать запрашиваемую сумму.
Пример, надо выдать 600
В манипуляторе есть следующие банкноты:
500 - 2
200 - 2
Результат - данными банкнотами невозможно выдать запрашиваемую сумму. Кинуть исключение.
Не забудьте, что в некоторых случаях картой кидается ConcurrentModificationException.

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
interface Command {
    void execute() throws InterruptOperationException;
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.Operation;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;

import java.util.HashMap;
import java.util.Map;

/**
 * Created by promoscow on 21.02.17.
 */
public final class CommandExecutor {
    private static Map<Operation, Command> commands = new HashMap<>();

    static {
        commands.put(Operation.DEPOSIT, new DepositCommand());
        commands.put(Operation.EXIT, new ExitCommand());
        commands.put(Operation.INFO, new InfoCommand());
        commands.put(Operation.WITHDRAW, new WithdrawCommand());
    }

    private CommandExecutor() {
    }

    public static final void execute(Operation operation) throws InterruptOperationException {
        if (commands.containsKey(operation)) {
            commands.get(operation).execute();
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulator;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulatorFactory;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
class DepositCommand implements Command {
    @Override
    public void execute() throws InterruptOperationException {

        String currencyCode = ConsoleHelper.askCurrencyCode();
        CurrencyManipulator manipulator = CurrencyManipulatorFactory.getManipulatorByCurrencyCode(currencyCode);
        String[] digits = ConsoleHelper.getValidTwoDigits();
        manipulator.addAmount(Integer.parseInt(digits[0]), Integer.parseInt(digits[1]));
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

/**
 * Created by promoscow on 21.02.17.
 */
class ExitCommand implements Command {
    @Override
    public void execute() throws InterruptOperationException {
        ConsoleHelper.writeMessage("ВЫ ДЕЙСТВИТЕЛЬНО ХОТИТЕ ВЫЙТИ? (Y / N)");
        String answer = ConsoleHelper.readString().toLowerCase();
        if (answer.equals("y")) ConsoleHelper.writeMessage("УДАЧИ!");
        else if (answer.equals("n")) {}
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulator;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulatorFactory;

import java.util.Collection;

/**
 * Created by promoscow on 21.02.17.
 */
class InfoCommand implements Command {
    @Override
    public void execute() {
        Collection<CurrencyManipulator> collection = CurrencyManipulatorFactory.getAllCurrencyManipulators();
        boolean hasMoney = false;
        for (CurrencyManipulator currencyManipulator : collection) {
            hasMoney = (currencyManipulator.hasMoney() && currencyManipulator.getTotalAmount() != 0 || hasMoney);
            if (currencyManipulator.getTotalAmount() != 0) {
                ConsoleHelper.writeMessage(currencyManipulator.getCurrencyCode() + " - " + currencyManipulator.getTotalAmount());
            }
        }
        if (!hasMoney) ConsoleHelper.writeMessage("No money available.");
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulator;
import com.javarush.test.level26.lesson15.big01.CurrencyManipulatorFactory;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.*;

/**
 * Created by promoscow on 21.02.17.
 */
class WithdrawCommand implements Command {
    @Override
    public void execute() throws InterruptOperationException {
        String currencyCode = ConsoleHelper.askCurrencyCode();
        CurrencyManipulator manipulator = CurrencyManipulatorFactory.getManipulatorByCurrencyCode(currencyCode);
        try {
            int amount = 0;
            while (true) {
                ConsoleHelper.writeMessage("ВВЕДИТЕ СУММУ.");
                try {
                    amount = Integer.parseInt(ConsoleHelper.readString());
                    if (!manipulator.isAmountAvailable(amount)) {
                        ConsoleHelper.writeMessage("НЕДОСТАТОЧНО СРЕДСТВ НА СЧЁТЕ.");
                        continue;
                    }
                    Map<Integer, Integer> map = manipulator.withdrawAmount(amount);
                    ArrayList<Integer> list = new ArrayList<>(map.keySet());
                    Collections.sort(list);
                    Collections.reverse(list);
                    for (int i = 0; i < list.size(); i++) {
                        ConsoleHelper.writeMessage("\t" + list.get(i) + " - " + map.get(list.get(i)));
                    }
                    ConsoleHelper.writeMessage("ОПЕРАЦИЯ ПРОШЛА УСПЕШНО. ЗАБЕРИТЕ ДЕНЬГИ.");
                    break;

                } catch (NumberFormatException e) {
                    ConsoleHelper.writeMessage("ВВЕДИТЕ ЧИСЛО.");
                }
            }
        } catch (NotEnoughMoneyException e) {
            ConsoleHelper.writeMessage("НЕДОСТАТОЧНО КУПЮР ДЛЯ ВЫДАЧИ.");
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.command.CommandExecutor;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.Locale;

/**
 * Created by promoscow on 20.02.17.
 */
public class CashMachine {
    public static void main(String[] args) {
        Locale.setDefault(Locale.ENGLISH);

//        CurrencyManipulator manipulator = null;
//        String currencyCode = "RUR";
//        manipulator = CurrencyManipulatorFactory.getManipulatorByCurrencyCode(currencyCode);
//        manipulator.addAmount(5000, 2);
//        manipulator.addAmount(1000, 1);
//        manipulator.addAmount(500, 3);
//        manipulator.addAmount(100, 2);
//        manipulator.addAmount(50, 3);

            Operation operation = null;
        try {
            do {
                operation = ConsoleHelper.askOperation();
                CommandExecutor.execute(operation);
            } while (operation != Operation.EXIT);
        } catch (InterruptOperationException e) {
            ConsoleHelper.writeMessage("ВСЕГО ХОРОШЕГО.");
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Created by promoscow on 20.02.17.
 */
public class ConsoleHelper {

    private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

    public static void writeMessage(String message) {
        System.out.println(message);
    }

    public static String readString() throws InterruptOperationException {

        String s = null;
        try {
            s = reader.readLine();
            if (s.toLowerCase().equals("exit")) {
                throw new InterruptOperationException();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        return s;
    }

    public static String askCurrencyCode() throws InterruptOperationException {
        writeMessage("ВВЕДИТЕ КОД ВАЛЮТЫ:");
        String currencyCode = "";
        while (true) {
            currencyCode = readString();
            if (currencyCode.matches("^[a-zA-Z]{3}$")) break;
            writeMessage("КОД ВАЛЮТЫ МОЖЕТ СОДЕРЖАТЬ 3 СИМВОЛА АНГЛИЙСКОГО АЛФАВИТА. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
        }
        return currencyCode.toUpperCase();
    }

    public static String[] getValidTwoDigits() throws InterruptOperationException {
        writeMessage("ВВЕДИТЕ НОМИНАЛ И КОЛИЧЕСТВО БАНКНОТ (ЧЕРЕЗ ПРОБЕЛ):");
        String enter = "";
        while (true) {
            enter = readString();
            if (enter.matches("\\d+ \\d+")) break;
            writeMessage("НЕКОРРЕКТНЫЙ ВВОД. ВВЕДИТЕ НОМИНАЛ И КОЛ-ВО ВАЛЮТ.");
        }
        return enter.split(" ");
    }

    public static Operation askOperation() throws InterruptOperationException {
        Operation operation = null;
        while (true) {
            writeMessage("ВВЕДИТЕ КОД ОПЕРАЦИИ.");
            writeMessage("| INFO - 1 | DEPOSIT — 2 | WITHDRAW - 3 | EXIT - 4 |");
            try {
                operation = Operation.getAllowableOperationByOrdinal(Integer.valueOf(readString()));
                break;
            } catch (Exception e) {
                writeMessage("ДАННЫЕ НЕ ВЕРНЫ. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
            }
        }
        return operation;
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.*;

/**
 * Created by promoscow on 20.02.17.
 */
public class CurrencyManipulator {
    public Map<Integer, Integer> denominations = new HashMap<Integer, Integer>();
    private String currencyCode = "";

    public CurrencyManipulator(String currencyCode) {
        this.currencyCode = currencyCode;
    }

    public String getCurrencyCode() {
        return currencyCode;
    }

    public void addAmount(int denomination, int count) {
        if (denominations.containsKey(denomination)) {
            denominations.put(denomination, denominations.get(denomination) + count);
        } else {
            denominations.put(denomination, count);
        }

//        ArrayList<Integer> list = new ArrayList<>(denominations.keySet());
//        Collections.sort(list);
//        Collections.reverse(list);
//        for (Integer aList : list) {
//            ConsoleHelper.writeMessage("\t" + aList + " - " + denominations.get(aList));
//        }
    }

    public int getTotalAmount() {
        int count = 0;
        for (Map.Entry<Integer, Integer> entry : denominations.entrySet()) count += (entry.getKey() * entry.getValue());
        return count;
    }

    public boolean hasMoney() {
        return (!denominations.isEmpty());
    }

    public boolean isAmountAvailable(int expectedAmount) {
        return this.getTotalAmount() >= expectedAmount;
    }

    public Map<Integer, Integer> withdrawAmount(int expectedAmount) throws NotEnoughMoneyException {
        Map<Integer, Integer> map = new HashMap<>();
        ArrayList<Integer> list = new ArrayList<>(denominations.keySet());
        Collections.sort(list);
        Collections.reverse(list);
        for (Integer integer : list) {    //integer - номинал
            int x = expectedAmount / integer;    //сколько купюр данного номинала требуется в идеале
//            System.out.println("expected: denomination - " + integer + ", amount - " + x);
//            System.out.println(denominations.get(integer) + " value");
            if (x > 0) {
                if (denominations.get(integer) >= x) {
                    map.put(integer, x);
                    expectedAmount -= integer * x;
                }
                else {
                    map.put(integer, denominations.get(integer));
                    expectedAmount -= denominations.get(integer) * integer;
                }
            }
            if (expectedAmount == 0) break;
        }
        if (expectedAmount > 0) {
            throw new NotEnoughMoneyException();
        }
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            int m = denominations.get(entry.getKey());
            denominations.remove(entry.getKey());
            denominations.put(entry.getKey(), (m - entry.getValue()));
        }
        return map;
    }
}

 

package com.javarush.test.level26.lesson15.big01;

        import java.util.Collection;
        import java.util.HashMap;
        import java.util.Map;

/**
 * Created by promoscow on 20.02.17.
 */
public final class CurrencyManipulatorFactory {
    private static Map<String, CurrencyManipulator> manipulators = new HashMap<String, CurrencyManipulator>();

    private CurrencyManipulatorFactory() {
    }

    public static CurrencyManipulator getManipulatorByCurrencyCode(String currencyCode) {

        CurrencyManipulator result = null;
        if (manipulators.containsKey(currencyCode))
            result = manipulators.get(currencyCode);
        else {
            result = new CurrencyManipulator(currencyCode);
            manipulators.put(currencyCode, result);
        }
        return result;
    }


    public static Collection<CurrencyManipulator> getAllCurrencyManipulators () {
        return manipulators.values();
    }
}

 

package com.javarush.test.level26.lesson15.big01;

/**
 * Created by promoscow on 20.02.17.
 */
public enum Operation {
    INFO,
    DEPOSIT,
    WITHDRAW,
    EXIT;

    public static Operation getAllowableOperationByOrdinal(Integer i) {
        switch (i) {
            case 1:
                return INFO;
            case 2:
                return DEPOSIT;
            case 3:
                return WITHDRAW;
            case 4:
                return EXIT;
        }
        throw new IllegalArgumentException();
    }
}

ЗАДАНИЕ 11.

****************************************************************
Задание 11
Поздравляю, ты реализовал WithdrawCommand! Основной функционал завершен. Дальше можно допиливать и наводить красоту.
Реализуем одну плюшку. Можно и без нее, но с ней - красивее.
Это верификация кредитной карты пользователя. Нет, никакого API сторонних либ не будет. Только консольная обработка.

Итак, назовем эту операцию LOGIN и сделаем для нее команду.
1. Добавить в операции LOGIN с ординал=0
2. Запретим пользователю выбирать эту операцию из списка.
В единственном методе для поиска операций запретим доступ по ординал - бросим IllegalArgumentException.
3. Создадим LoginCommand по аналогии с другими командами, в котором захардкодим номер карточки с пином
123456789012 и 1234 соответственно.
4. Реализуйте следующую логику для команды LoginCommand:
4.1. Пока пользователь не введет валидные номер карты и пин - выполнять следующие действия
4.2. Запросить у пользователя 2 числа - номер кредитной карты, состоящий из 12 цифр, и пин - состоящий из 4 цифр
4.3. Вывести юзеру сообщение о невалидных данных, если они такими являются.
4.4. Если данные валидны, то проверить их на соответствие захардкоженным (123456789012 и 1234).
4.5. Если данные в п. 4.4. идентифицированы, то сообщить, что верификация прошла успешно.
4.6. Если данные в п. 4.4. НЕ идентифицированы, то вернуться к п.4.1.

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;

/**
 * Created by promoscow on 30.03.17.
 */
public class LoginCommand implements Command {
    @Override
    public void execute() throws InterruptOperationException {
        String number = "123456789012";
        String pin = "1234";

        while (true) {
            ConsoleHelper.writeMessage("ВВЕДИТЕ НОМЕР КАРТЫ (12 чисел).");
            String cardNum = ConsoleHelper.readString();
            ConsoleHelper.writeMessage("ВВЕДИТЕ PIN.");
            String enterPin = ConsoleHelper.readString();
            if (cardNum.length() != 12) {
                ConsoleHelper.writeMessage("НОМЕР КАРТЫ ДОЛЖЕН СОДЕРЖАТЬ 12 ЦИФР.");
                continue;
            }
            try {
                long checkNum = Long.parseLong(cardNum);
            } catch (NumberFormatException e) {
                ConsoleHelper.writeMessage("НОМЕР КАРТЫ ДОЛЖЕН СОДЕРЖАТЬ 12 ЦИФР.");
                continue;
            }
            if (enterPin.length() != 4) {
                ConsoleHelper.writeMessage("PIN ДОЛЖЕН СОДЕРЖАТЬ 4 ЦИФРЫ.");
                continue;
            }
            try {
                int checkPin = Integer.parseInt(enterPin);
            } catch (NumberFormatException e) {
                ConsoleHelper.writeMessage("PIN ДОЛЖЕН СОДЕРЖАТЬ 4 ЦИФРЫ.");
                continue;
            }
            if (number.equals(cardNum) && pin.equals(enterPin)) {
                ConsoleHelper.writeMessage("ДАННЫЕ ВЕРНЫ.");
                break;
            } else ConsoleHelper.writeMessage("ДАННЫЕ НЕ ВЕРНЫ. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.command.CommandExecutor;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;
import com.javarush.test.level26.lesson15.big01.exception.NotEnoughMoneyException;

import java.util.Locale;

/**
 * Created by promoscow on 20.02.17.
 */
public class CashMachine {
    public static void main(String[] args) {
        Locale.setDefault(Locale.ENGLISH);

//        CurrencyManipulator manipulator = null;
//        String currencyCode = "RUR";
//        manipulator = CurrencyManipulatorFactory.getManipulatorByCurrencyCode(currencyCode);
//        manipulator.addAmount(5000, 2);
//        manipulator.addAmount(1000, 1);
//        manipulator.addAmount(500, 3);
//        manipulator.addAmount(100, 2);
//        manipulator.addAmount(50, 3);

            Operation operation = null;
        try {
            CommandExecutor.execute(Operation.LOGIN);
            do {
                operation = ConsoleHelper.askOperation();
                CommandExecutor.execute(operation);
            } while (operation != Operation.EXIT);
        } catch (InterruptOperationException e) {
            ConsoleHelper.writeMessage("ВСЕГО ХОРОШЕГО.");
        }
    }
}

ЗАДАНИЕ 12.

****************************************************************
Задание 12
В задании 11 мы захардкодили номер кредитной карточки с пином, с которыми разрешим работать нашему банкомату.
Но юзеров может быть много. Не будем же мы их всех хардкодить! Если понадобится добавить еще одного пользователя,
то придется передеплоить наше приложение. Есть решение этой проблемы.

Смотри, добавился новый пакет resources, в котором мы будем хранить наши ресурсные файлы.
В этом пакете есть файл verifiedCards.properties, в котором заданы карточки с пинами.

1. В LoginCommand добавь поле private ResourceBundle validCreditCards.
При объявлении инициализируй это поле данными из файла verifiedCards.properties.
Почитай в инете, как это делается для ResourceBundle.

2. Замени хардкоженные данные кредитной карточки и пина на проверку наличия данных в ресурсе verifiedCards.properties.

3. Добавь обработку команды LoginCommand в начало нашего main внутрь блока try-catch

 

package com.javarush.test.level26.lesson15.big01;

import com.javarush.test.level26.lesson15.big01.command.CommandExecutor;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;

import java.util.Locale;

/**
 * Created by promoscow on 20.02.17.
 */
public class CashMachine {
    public static final String RESOURCE_PATH = "com.javarush.test.level26.lesson15.big01.resources.";
    public static void main(String[] args) {
        Locale.setDefault(Locale.ENGLISH);

//        CurrencyManipulator manipulator = null;
//        String currencyCode = "RUR";
//        manipulator = CurrencyManipulatorFactory.getManipulatorByCurrencyCode(currencyCode);
//        manipulator.addAmount(5000, 2);
//        manipulator.addAmount(1000, 1);
//        manipulator.addAmount(500, 3);
//        manipulator.addAmount(100, 2);
//        manipulator.addAmount(50, 3);

            Operation operation = null;
        try {
            CommandExecutor.execute(Operation.LOGIN);
            do {
                operation = ConsoleHelper.askOperation();
                CommandExecutor.execute(operation);
            } while (operation != Operation.EXIT);
        } catch (InterruptOperationException e) {
            ConsoleHelper.writeMessage("ВСЕГО ХОРОШЕГО.");
        }
    }
}

 

package com.javarush.test.level26.lesson15.big01.command;

import com.javarush.test.level26.lesson15.big01.CashMachine;
import com.javarush.test.level26.lesson15.big01.ConsoleHelper;
import com.javarush.test.level26.lesson15.big01.exception.InterruptOperationException;

import java.util.ResourceBundle;

/**
 * Created by promoscow on 30.03.17.
 */
public class LoginCommand implements Command {
    private ResourceBundle validCreditCards = ResourceBundle.getBundle(CashMachine.RESOURCE_PATH + "verifiedCards");
    @Override
    public void execute() throws InterruptOperationException {

        while (true) {
            ConsoleHelper.writeMessage("ВВЕДИТЕ НОМЕР КАРТЫ (12 чисел).");
            String cardNum = ConsoleHelper.readString();
            ConsoleHelper.writeMessage("ВВЕДИТЕ PIN.");
            String enterPin = ConsoleHelper.readString();
            if (cardNum.length() != 12) {
                ConsoleHelper.writeMessage("НОМЕР КАРТЫ ДОЛЖЕН СОДЕРЖАТЬ 12 ЦИФР.");
                continue;
            }
            try {
                long checkNum = Long.parseLong(cardNum);
            } catch (NumberFormatException e) {
                ConsoleHelper.writeMessage("НОМЕР КАРТЫ ДОЛЖЕН СОДЕРЖАТЬ 12 ЦИФР.");
                continue;
            }
            if (enterPin.length() != 4) {
                ConsoleHelper.writeMessage("PIN ДОЛЖЕН СОДЕРЖАТЬ 4 ЦИФРЫ.");
                continue;
            }
            try {
                int checkPin = Integer.parseInt(enterPin);
            } catch (NumberFormatException e) {
                ConsoleHelper.writeMessage("PIN ДОЛЖЕН СОДЕРЖАТЬ 4 ЦИФРЫ.");
                continue;
            }
            if (validCreditCards.containsKey(cardNum) && validCreditCards.getString(cardNum).equals(enterPin)) {
                ConsoleHelper.writeMessage("ДАННЫЕ ВЕРНЫ.");
                break;
            } else ConsoleHelper.writeMessage("ДАННЫЕ НЕ ВЕРНЫ. ПОПРОБУЙТЕ ЕЩЁ РАЗ.");
        }
    }
}