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

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

  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

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

16 comments to Список контактов — начало

  • Евгений  says:

    Класс ContactManager тоже реализует паттерн Проектирования, если добавить проверку на доступность совершения операций вставки/удаления/изменения, то получится Заместитель, а так получается Фасад.

  • zdeniz  says:

    в методе generateContactId() не может так получиться, что сгенерится ID, который уже был?

    • admin  says:

      Если используется однопотоковое приложение, то не может — см. код. В данном случае это (на мой взгляд) вполне допустимое предположение, т.к. это ДАО мы используем исключительно для демонстрационных целей.

  • Антон  says:

    Тип данных char в методе toString всё равно же будет переведён в String? И написанное Вами ‘}’ само преобразует в «}»?

    • admin  says:

      Этот код генерируется автоматически IDE. Что получилось, то и получилось.

  • Alexandr  says:

    Небольшие опечатки:
    В данном случае это шаблон Anstract Factory
    Интерфейс для определения функций хранлиза данных о контактах

  • Кирилл  says:

    В классе ContactTest при создании ContactManager нужно передать параметр ContactDAO
    ContactDAO dao = ContactDAOFactory.getContactDAO();
    ContactManager manager = new ContactManager(dao);

    • admin  says:

      На данный момент инициализация DAo сделана в конструкторе. Так что не требуется. Хотя в принципе сеттер для DAO надо сделать — но я хочу это сделать позже.

  • Василий Фрайман  says:

    Привет! Во-первых, хотел поблагодарить за отличный, пожалуй, лучший самоучитель по Java)

    Я так и не понял разницу между хранением данных в хранилище и действиями по редактированию — пожалуйста, коллеги, кто разобрался — поясните=)

    И, вторая просьба: так и не понял, зачем нам сразу 6(!) классов. Чисто умозрительно кажется, что хватит всего 3 классов:
    1 — класса для работы с контактами (из создание, обновление данных) — Contact;
    2 — класса для управления списком (внутри класса создаем массив-хранилище и обслуживающие его методы) — типа ContactSimpleDAO;
    3 — управляющего класса чтобы это просто запустить — типа ContactTest.

    Поясните, пожалуйста, зачем к этому списку добавлять еще и интерфейс, странную конструкцию ContactDAOFactory, которая только что и вызывает ContactSimpleDAO, и посредника ContactManager, который только и умеет, что через ContactManager оперировать методами ContactSimpleDAO.

    Вот честно — не понял(((

    • admin  says:

      ContactManager — есть ли разница между операцией «добавить пользователя» в систему и «добавить запись в базу данных» ? В первом случае это моежт быть НЕ ТОЛЬКО добавление в базу — это может породить и другие действия.
      Регистрация почтового адреса, выделение квоты на файл-сервере, регистрация пользователя в домене, отправка почты секретарю, в отдел кадров и в бухгалтерию.
      Второй случай — это просто добавление в базу данных. Если мы уберем ContactManager, то потом, когда нам захочется что-то добавить, то куда мы это сможем добавить ? В какой класс ?

      Точно так же и интерфейс ContactDAO — там же не только SQL база данных может использоваться для хранения данных. А вдруг появится что-то другое — логику опять менять ?

  • Станислав  says:

    Ошибка в тексте. Исправьте Abstract Factory.

    • admin  says:

      Я не понял замечание — где именно Abstract Factory находится ?

      • Yu  says:

        В тексте статьи: «В данном случае это шаблон Anstract Factory». Надо поменять слово на «Abstract».

        • admin  says:

          Спасибо — теперь нашел и исправил.

  • Yury  says:

    В тему данной статьи пытаюсь выяснить вопрос:
    Предположим имеется список строк с именами text1, text2, text3 Строки с такими именами имеют различное содержимое (содержимое неизвестно). Сам список выглядит примерно так.
    private List lstKey = new ArrayList();
    String t1 = «text1»;
    String t2 = «text2»;
    String t3 = «text3»;
    lstKey.add(t1);
    lstKey.add(t2);
    lstKey.add(t3);
    Можно-ли как-то получить содержимое строк имея только список их имен?

    • admin  says:

      Вопрос не понял — если мы говорим о ключе и значении, то это не список, это Map (ассоциативный массив). А у вас — List. Не укладывается в голове 🙂

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.