Sunday, July 1, 2012

Java Практика - Занятие 3

На третьем занятии мы уже подошли к объектам и проектированию. Я рассмотрел создание программы с позиции объектно-ориентированного дизайна. Бегло прошелся по теме третьего урока из курса Java для тестировщиков, чтобы вспомнить, что такое объект и как с ним работать. Далее мы решали задачу, немного похожую на реальный пример: выделяли объекты, рисовали диаграммы и реализовывали методы. 

На этом занятии я также впервые упомянул про одну из очень полезных книг, а именно книгу по шаблонам проектирования: Приемы объектно-ориентированного проектирования. Паттерны проектирования ("Банда четырёх": Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидс). Я считаю, что каждый программист просто обязан изучить эту книгу и по возможности использовать шаблоны в своих программах. Конечно, это не легко будет делать сразу - понимание, где и какой шаблон лучше применять, приходит с опытом. Также, не расстраивайтесь, если Вы сразу не поймете эту книгу. Продолжайте изучать программирование и больше практикуйтесь писать программы - со временем Вы поймете, насколько мощный инструмент у Вас в руках. Однако, есть небольшое предостережение по поводу шаблонов проектирования: фокусируйтесь на простых решениях проблем, прежде чем сразу браться за применение сложных "рецептов" шаблонов. Так что не забывайте: Keep It Simple :)

Задачу, которую мы решали на занятии следующая:
Необходимо реализовать программу, которая будет позволять вводить сделки купли-продажи товаров между двумя участниками. В каждой сделке может быть несколько товаров, сумма сделки рассчитывается из суммы всех товаров. Сумма каждого товара рассчитывается из его стоимости и количества. Программа должна позволить ввести информацию о сделках, сохранить ее в памяти и вывести на экран. Ввод информацию осуществляется с экрана (консоли). Количество дополнительной информацию о сделке, участнике, товаре придумать самому (больше одного поля для класса). 
Форматы данных для хранения информации, которые я предложил, конечно же, не самые оптимальные. Например, использование массивов вместо коллекций, а также использование double для представления денег. Но это не главное для данного примера. Также, вводить информацию с консоли - это долго и нудно, но это тоже не главное. Я не хотел углубляться в способы представления определенной информации, в способы работы с файлами или базой данных - это все темы следующих занятий. Цель этого занятия - это научится выделять объекты, строить между ними связи и попрактиковаться программировать несложную логику. Поэтому ввод с консоли тут идеально подходит, ведь надо будет подумать, как последовательно все ввести, да еще чтобы это было красиво :)

На видео я вспоминаю про метод keyboard, который позволяет вводить данные с консоли, и который я обещал выслать слушателям. Итак, вот он: 
private String keyboard(String message) {
     System.out.print(message + ": ");
     Scanner scan = new Scanner(System.in);
     String rez = scan.next();
     scan.close();
     return rez;
}
Я также написал возможное решение этой задачи, если вдруг кому-то будет очень сложно. Скачать исходные файлы можно тут: JavaPractice03.zip (3,4 KB)
Чтобы откомпилировать и запустить этот пример, выполните следующие команды: 
cd <каталог_куда_распаковали_архив>
cd src 
javac *.java
java Program
Также, если Вы уже умеете работать со средой разработки Eclipse, то можете импортировать этот проект в нее и запустить. 

В качестве дополнительного задания, можно написать отдельные класс Keyboard, который будет содержать статические методы для ввода строки (String), целого числа (Integer) и дробного числа (Double). Методы по вводу чисел будет проверять, а число ли введено вообще, и выдавать сообщение об ошибке или требовать правильный ввод.

Ну и собственно видео:


33 comments:

Anonymous said...

Здравствуйте, Юрий. Помогите пожалуйста советом.

Текущие знания:
- Java Core
- JSP, JSF
- Swing, Hibernate, Spring
- NetBeans
- Tomcat / Glassfish
- MySQL, PostgreSQL
- *nix (Arch Linux)
- Шаблоны (по Банде 4х)

Чего еще нехватает разработчику уровня Junior? Или уже можно смело в бой? Не хочу быть обузой для компании первые месяцы работы.

Yuriy Tkach said...

Если эти знания у тебя только на теоретическом уровне, то необходима хоть какая-то практика, чтобы ты смог доказать, что ты таки умеешь программировать. В принципе для Junior достаточно знать Java Core, шаблоны и уметь программировать :)
Если же у тебя есть практика работы со всем тем, что ты перечислил, то думаю, что даже на Middle-разработчика ты сможешь потянуть :)

Anonymous said...

Да, практика есть, писал несколько "академических проектов" для себя: библиотека, магазин и т.п. Большое спасибо за ответ =) Все еще вызывает вопросы грамотное проектирование, не подскажете литературу, наподобие http://www.intuit.ru/department/se/oopbases/1/ этой, но более ориентированную на java? Можно на английском.

Anonymous said...

Немного не ту ссылку дал =)
http://www.intuit.ru/department/se/ooad/1/

Anonymous said...

Anonymous 1 - Ты себя не любишь. Ты никогда не сможешь быть на 100% нужным человеком. Тебя будут направлять более опытные коллеги и рассказывать какая у них грамотное проектирование. Нужно быть открытым к изменениям и не боятся экспериментировать.
Читай коммент и вперед писать резюме!
Или сворачивать горы на фриланс сайтах.

Юра, спасибо за видео.
Наконец то понял что такое Spring. Кстати как идею можно сделать видео обзор всех технологий Java (ну или тех что знаешь). Новичок упирается в такое разнообразие названий, что быстро отпадает желание это изучать.
Если в Киеве напиши - сходим на пиво.

Yuriy Tkach said...

Спасибо за приглашение :)

Только, куда ж писать то? Вы ж пишете коменты как Anonymous :)

Рад, что ты понял Spring. Про обзор всех технологий - это задача непростая - слишком много чего есть. Хотя идея интересная. Надо будет сделать занятие такое где-то под конец курса Java Практики.

Anonymous said...

Ну Ты же знаешь нас - украинцев. Мы самая скрытная нация в мире. Нас даже ЦРУ не может найти.

Писать можно сюда http://vk.com/id176292559

Anonymous said...

Привет. Подскажи для чего в конструкторе класса Deal используется ключевое слово
super().
На сколько я понимаю оно используется для вызова родительского метода при наследовании, а здесь не пойму.
Заранее спасибо.

Yuriy Tkach said...

super в конструкторе используется для вызова конструктора родительского класса. Если у родителя он один, то он в любом случае будет вызван, но если их несколько, то можно указать, какой именно мы хотим вызвать.

Anonymous said...

Тоесть для вызова конструктора по умолчанию, чтобы тот в свою очередь проинициализировал поле Date ?

Egor said...

Привет Юра! Спасиюо огромное за уроки! Многое встало на свои места.
Один вопрос к тебе по методу keyboard.
Здесь открывается поток, его не нужно закрывать?

Yuriy Tkach said...

to Egor: Да, Scanner неплохо было бы закрыть после использования. Спасибо, что подметил!

Anonymous said...

Чтобы многократно использовать сканнер, надо вместо scaner.close();
использовать scanner.reset();
вот только как его потом закрыть ... и надо ли его закрывать ?

Anonymous said...

Здравствуйте! Данный Вами метод почему то вываливается с java.util.NoSuchElementException

Anonymous said...

может я что-то не то делаю?

Yuriy Tkach said...

Если вываливается java.util.NoSuchElementException, то, наверное, что-то не так делаешь. Это исключение может вываливаться, когда читаешь из закрытого сканера. Попробуй использовать проверку scanner.hasNext() прежде чем читать из него.

Roman Muschinskiy said...

Помогло, спасибо! Но я решил просто "сбрасывать" сканнер - scan.reset(). Отличные лекции у Вас получаются! Как раз то, что отсутствует в любой книжке по Java. Вроде и код читаешь, и конструкции знаешь... но вот когда дело доходит до воплощения в жизнь.. Просто не понимаешь, как все должно работать.. а именно как должны взаимодействовать между собой объекты.. В этом как раз моя проблема...

Алексей Богданов said...

Юрий добрый день.
В дополнение к теме про шаблоны.
Есть хорошая книга из серии HeadFirst "Design patterns", в которой шаблоны рассматриваются в доступной форме:
http://www.headfirstlabs.com/books/hfdp/

Anonymous said...

Юрий, привет. Имеется вопросик следующего характера. Почему бы не использовать, как я считаю, метод ввода с клавиатуры проще, подключив import java.util.*;
........
написав:

Scanner in = new Scanner(System.in);
.........
вызывая к примеру
num = in.nextInt();
.........
????
Это не проще? Или свои минусы?
заранее благодарочка.

Anonymous said...

понял, это тоже самое, только методом))

Unknown said...

Юрий, а зачем в классе Deal переменные:
private final Date date = new Date();

private final Party buyer;

private final Party seller;

private final Product[] products;

объявлены как "final"?

Yuriy Tkach said...

Поля в классе Deal объявлены как final, потому что они устанавливаются в конструкторе и больше никогда не изменяются, т.е. сеттеров для их установки нету в классе. В связи с этим, оптимизатор кода в моем Eclipse решил, что поля должны быть final, чтобы программисту не хотелось их изменить, например, в подклассах и т.п.
Конечно, для этого примера это не обязательно, и возможно надо даже сделать сеттеры, чтобы изменять поля при необходимости.

Anonymous said...

Лекция отличная и очень понравилась поставленная задача.Единственный минус - девушка-невежа в первом ряду:(

Евгений said...

Юрий, вы выше указали, что для Junior достаточно знать Java Core, шаблоны + практика - не могли бы вы уточнить, что минимально необходимое входит в понятие Java Core - только семантика языка и осн.классы или все пункты ваших лекций "для тестировщиков" :-) Заранее спасибо.

Yuriy Tkach said...

2 Евгений:
Семантика языка - это семантика. В Java Core входят основные классы, которые используются для программирования. Это все из области Strings, Numbers, Collections, I/O, Exceptions, Generics, и т.п. В принципе, почти все то, что я рассказывал :)

Евгений said...

Юрий, если можно, еще вопрос задам, извините если глупый, снова про Core:

Основные классы и др. необходимо вызубрить? В JavaDoc, посмотрел, только работа со строками - 64 метода (если со счета не сбился) + переопределение методов + исключения (с длиннющими названиями, например, как для массива).

И может порекомендуете какие талмуды (или авторов) чтобы "заполировать" ваши лекции :-) Так, чтобы зашел в отдел кадров - и там сразу увидели - Java программист :-)

Anonymous said...

Привет Юра! Я прочел книгу, посмотрел видео уроки, но ничего не понял! Но вот сегодня после просмотра 3 урока практики у тебя-я прозре:)
Может у тя есть еще какой нить пример-скинь плизз unikornsergey@mail.ru? Спс Рад,что нарвался на тя

Anonymous said...

Юрий, доброго времени суток.
Дошли руки посмотреть Ваши замечальные ролики и поковыряться с практикой.
Появился вопрос(ы) по 3му заданию, что из практики, решил взглянуть на Ваши примеры, но обнаружил, что архив с исходниками недоступен по ссылке. Перезалейте пжлст.
Alex.

Yuriy Tkach said...

Ссылка работает нормально. Пробуйте еще раз

Alex Marusik said...

Здравствуйте, Юрий. Спасибо вам за уроки. Очень интересно и полезно.

В связи с ними возник вопрос по кейборду. Я привык разные функциональные части программы разносить по разным классам. Соответственно вынес ваш метод кейборд в отдельный класс.

Первое обращение он обрабатывает нормально и возвращает введенный стринг. А вот любое следующее обращение вызывает исключение NullPointerException в этом методе.

Я погуглил и узнал, что в данном случае получается, что сканер закрыт после первого обащения и наново не открывается при других обращениях из главного потока.

Конечно, есть вариант закоментить .close(), тогда чтение из сканера происходит нормально, сколько бы раз мы в него не обращались. Но это же не правильно оставлять незакрытые ресурсы.

Подскажите, плз, как у вас решается данная проблема. Спасибо

Alex Marusik said...

Поправка, возникает исключение NoSuchElementException, а не NullPointerException.

Yuriy Tkach said...

2 Alex Marusik:

Ты получаешь NoSuchElementException, потому что ты перед этим закрыл сканер, а вместе с ним и системный поток ввода System.in.

Мы создаешь сканер, передавая ему на вход системый поток ввода. Если ты вызываешь close на сканере, то он также закрывает и тот потом. Потом, когда ты снова создаешь сканер, потом все равно закрыт и ты получаешь исключение.

Как вариант, ты можешь сделать одно из:
- как писали выше в комментариях, делай scanner.reset() - это очищает кэши и сбрасывает в первоначальные настройки.
- создай один объект сканера статический и всегда к нему обращайся, а закроешь его при выходе из программы.

Alex Marusik said...

Спасибо.