Система управления списком контактов

Чтобы мы могли дальше двигаться не просто рассматривая новое, а со смыслом и практикой, предлагаю начать разработку очень простого приложения, которое позволит нам задействовать описываемые технологии. Оно будет даже проще варианта «Студенческий отдел кадров», который я планирую переделать на новый лад.
Чтобы не придумывать что-то очень сложное, я буду делать простой список контактов, который будет иметь возможность делать основные операции (назовем их для дальнейших рассуждений «бизнес-действие»):

  1. Просмотр списка контактов
  2. Добавление контакта
  3. Редактирование контакта
  4. Удаление контакта

Также предлагаю делать свой вариант — например список машин в автосалоне, список заказов пиццы, список книг. Пусть он будет выглядеть практически так же, как мой, но это будет ваш собственный проект.

В этой статье мы создадим каркас нашего приложения — основные классы и методы. При изучении нового материала будем расширять эту функциональность.
Для начала проектирования воспользуемся нашим набором функций и существительным «контакт». Эти слова на самом деле очень помогают при начальной разработке — вы по сути определяете предметную область и можете выделить какие-то базовые классы и их методы.
Естественно, что при наработке дальнейшего опыта и усложнении систем, которые вы будете разрабатывать, набор классов и их функциональность будет увеличиваться, но основные принципы остануться такие же, как и в нашем случае — смотрим описание и выделяем существительные и глаголы. В них основная идея и будет скрываться :).

Достаточно легко можно увидеть класс Contact, который будет использоваться как хранилище информации об одном контакте. Также нам потребуется класс, который предоставить нам нужные фукнции для работы со списокм контактов — удаление, добавление, редактирование, получение списка. Назовем его ContactManager. Также нам потребуется класс (классы) для хранения контактов в каком-то постоянном хранилище. Т.к. систем хранения у нас будет несколько — для фалов, для базы данных.
В нашем случае это не очень выразительно видно, но я очень хочу, чтобы вы уловили разницу между хранением данных в хранилище и действиями по редактированию. Этот момент важен по следующим соображениям:

  1. Функции редактирования могут быть гораздо сложнее обычного сохранения данных в хранилище. Например, добавление контакта может потребовать проверку данных на правильность полей, проверку на наличие такого контакта (причем такая проверка может быть весьма нетривиальной задачей — по имени или по e-mail или еще как). Также надо принимать во внимание возможность дальнейшего расширения системы. Добавление контакта может потребовать выполнить какие-то дополнительные действия — поиск сведений о контакте в социальных сетях, поиск через Гугл или синхронизацию данных с удаленным хранилищем. В итоге мы однозначно можем сказать, что бизнес-действие нередко включает несколько элементарных действия, среди которых будет и действия с хранилищем.
  2. Хранилища могут быть совершенно разными. Это может быть файл — причем в разных форматах: CSV, XML, какой-то текст, бинарное представлние (MS Word, MS Excel). Это может быть база данных — причем совершенно разных типов — например SQL и NoSQL. Это может быть та же 1С-Бухгалтерия или сервер MS Exchange. Или IBM Lotus Notes. В общем систем хранения может быть много и надо быть готовым к тому, чтобы перевести ваше приложение на новый вариант с текущего

Суммируя все вышеизложенное мы будем строить взаимодействие класса ContactManager с хранилищами через интерфейс , реализовать который должны все хранилища, которые мы будем создавать.

Давайте нарисуем упрощенную диаграмму наших классов:

Как видите, наш класс ContactManager взаимодействует с хранилищем не напрямую, а через интерфейс ContactDAO. Т.к. все хранилища его реализуют, то нам будет легко менять их фактически «на лету».

Коллекции

Мы еще не рассматривали классы-колекции — в нашем случае это List и ArrayList. Мы займемся этим сразу после этой главы, а пока примите это как данность. Обещаю, что мы очень скоро расставим все по своим местам.

Класс Contact

Этот класс не должен вызывать каких-то больших вопросов. Там перечислены нужные поля и для них сделаны сетеры и гетеры. Может вызывать сомнение набор конструкторов — я сделал для всех полей (в случае редактирования) и все поля кроме ИД — для случая добавления. Мне показалось, что так будет удобно. Переопределение метода toString сделано для удобства вывода информации о контакте.

Класс ContactManager

Здесь тоже особых сложностей нет — в данном случае я просто перечислил те фукнции, которые мы хотели реализовать. Выглядит это конечно несколько натянуто, т.к. кроме вызовов методов для работы с хранилищем в них ничего нет, но мы уже осбуждали возможность расширения. Единственное, на что надо обратить внимание — мы используем интерфейс ContactDAO, а не реальный класс. Почему мы так сделали — я тоже объяснял выше.

Почему мы создаем экземпляр ContactDAO с использованием класса ContactDAOFActory я объясню чуть позже.

Интерфейс ContactDAO

Прибавочка DAO — это Data Access Object — объект доступа к данным. Для работы с хранилищем любого типа мы создали интерфейс, который определяет контракт, по которому любой хранилище для работы с контактами должно реализовать определенный набор функций. Это позволит нам в дальнейшем заменять реализации хранилища без особых хлопот.

Класс ContactDAOFactory

Идея появления этого класса лежит в плоскости шаблонов проектирования. В данном случае это шаблон Abstract Factory. Поробую ответить на вопрос — а зачем он нужен ?
Если простыми словами — классы для хранилища могут использоваться во многих местах. Это у нас все достаточо просто — мы к нему по сути обращаемся только водном месте — в классе ContactManager. Но представим ситуацию, когда хранилище контактов потребуется не в одном классе, а например в 25-ти. Тогда если мы захотим поменять наше хранилище на другое, то создание надо будет переопределять в 25-ти местах. Можно запутаться. Класс ContactDAOFactory легко решает эту задачу. Создание хранилища происходит исключительно в нем и больше нигде. Это удобно.

Классы ContactSimpleDAO и ContactTest

Классы имеют исключительно утилитарное назначние — мы можем их использовать для проверки системы. ContactSimpleDAO реализует интерфейс ContactDAO и это дает нам возможность «смоделировать» хранилище. Что же касается класса ContactTest — он используется для вызова методов класса ContactManager и вывода результатов. Мы можем убедиться, что наша система (пусть пока и очень сырая) работает.

Проект на NetBeans вы можете скачать по этой ссылке: ContactProject_01.zip

И теперь нас ждет следующая статья: Коллекции — базовые принципы.