Как вы проектируете объектно-ориентированные проекты?
Я работаю над большим проектом (для меня), который будет иметь много классов и должен быть расширяемым, но я не уверен, как планировать свою программу и как классы должны взаимодействовать.
Я взял курс OOD несколько семестров назад и многому научился у него; как написание UML и перевод документов требований в объекты и классы. Мы также выучили диаграммы последовательности, но почему-то я пропустил лекцию или что-то в этом роде, они на самом деле не придерживались меня.
В предыдущих проектах я пытался использовать методы, которые я выучил из курса, но обычно получаю код, который, как только я могу сказать "да, это похоже на то, что я имел в виду", у меня нет желания копаться в гадости, чтобы добавить новые возможности.
У меня есть копия " Завершенного кода" Стива Макконнелла, которая, как я постоянно слышу, удивительна здесь и в других местах. Я прочитал главу о дизайне и, похоже, не смог найти нужную мне информацию. Я знаю, что он говорит, что это не частый процесс, который в основном основан на эвристике, но я не могу взять всю его информацию и применить ее к своим проектам.
Итак, что вы делаете на этапе проектирования высокого уровня (перед тем, как начать программирование), чтобы определить, какие классы вам нужны (особенно те, которые не основаны на каких-либо "объектах реального мира") и как они будут взаимодействовать друг с другом?
В частности, меня интересует, какие методы вы используете? Какой процесс вы используете, который обычно приводит к хорошему, чистому дизайну, который будет точно представлять конечный продукт?
23 ответа
Шаги, которые я использую для начального проектирования (добраться до диаграммы классов):
Сбор требований. Поговорите с клиентом и выделите варианты использования, чтобы определить, какие функции должны иметь программное обеспечение.
Составьте повествование об отдельных случаях использования.
Пройдите повествование и выделите существительные (личность, место, предмет) как классы-кандидаты, а глаголы (действия) - как методы / поведения.
Откажитесь от дублирующих существительных и исключите общие функциональные возможности.
Создать диаграмму классов. Если вы Java-разработчик, NetBeans 6.7 от Sun имеет UML-модуль, который позволяет создавать диаграммы, а также разрабатывать схемы в обоих направлениях, и это БЕСПЛАТНО. Eclipse (Java IDE с открытым исходным кодом) также имеет среду моделирования, но у меня нет опыта работы с ней. Вы также можете попробовать ArgoUML, инструмент с открытым исходным кодом.
Применяйте принципы OOD для организации ваших классов (с учетом общей функциональности, построения иерархий и т. Д.)
У меня пока недостаточно репутации, чтобы комментировать (присоединился сегодня), или я бы просто прокомментировал ответ Скотта Дэвиса. Добавляя к тому, что он должен был сказать:
Перед тем, как начать, убедитесь, что вы знаете, о чем ваша программа. Какая у вас программа? Что это не будет делать? Какую проблему он пытается решить?
Ваш первый набор вариантов использования не должен быть детальным списком всего, что программа в конечном итоге сделает. Начните с наименьшего количества вариантов использования, которые вы можете придумать, которые по-прежнему отражают суть того, для чего предназначена ваша программа. Например, для этого веб-сайта основными вариантами использования могут быть вход в систему, задание вопроса, ответ на вопрос и просмотр вопросов и ответов. Ничего о репутации, голосовании или вики-сообществе, а только о сути того, за что вы стреляете.
Когда вы придумываете потенциальные классы, не думайте о них только с точки зрения того, какое существительное они представляют, но какие обязанности они несут. Я обнаружил, что это самая большая помощь в выяснении того, как классы связаны друг с другом во время выполнения программы. Легко придумать такие отношения, как "собака - это животное" или "у щенка одна мать". Обычно сложнее выяснить отношения, описывающие взаимодействия между объектами во время выполнения. Алгоритмы вашей программы, по крайней мере, так же важны, как и ваши объекты, и их гораздо легче спроектировать, если вы подробно определили, какова задача каждого класса.
Как только вы получите этот минимальный набор вариантов использования и объектов, начните кодировать. Получите что-то, что на самом деле работает, как можно скорее, даже если это мало что делает и, вероятно, выглядит как дерьмо. Это отправная точка, и она заставит вас ответить на вопросы, которые вы можете затушевать на бумаге.
Теперь вернитесь и выберите больше вариантов использования, напишите, как они будут работать, измените модель своего класса и напишите больше кода. Точно так же, как ваш первый урок, берите как можно меньше за раз, добавляя что-то значимое. Промыть и повторить.
Просто мои два цента. Надеюсь, это полезно.
Когда у меня был шанс, я обычно использую то, что я называю "правилом трех итераций".
На первой итерации (или при запуске) я разрабатываю общий макет приложения в соответствии с объектами модели, алгоритмами и ожидаемыми (действительно ожидаемыми, а может и не ожидаемыми) будущими направлениями. Я не пишу проектные документы, но если мне приходится координировать работу нескольких людей, конечно, необходим грубый набросок процедуры, вместе с анализом зависимостей и предположением о необходимом времени. Постарайтесь свести этот этап к минимуму, если, как и я, вы предпочитаете более гибкий метод. Существуют случаи, когда необходима сильная фаза проектирования, в частности, когда все известно и верно о логике вашей программы, и если вы планируете много взаимодействий между функциями в вашем коде. В этом случае примеры использования или истории пользователей являются хорошей идеей высокого уровня, особенно для приложений с графическим интерфейсом. Для приложений командной строки и, в частности, для библиотек, попробуйте написать "программные истории", в которых вы будете кодировать библиотеку, которую вы должны разработать, и проверить, как она выглядит. Эти программы станут функциональными тестами вашей библиотеки после завершения.
После этой первой итерации вы будете лучше понимать, как все взаимодействует, узнавать подробности и неровности, решать проблемы с помощью исправленного патча с клейкой лентой. Вы готовы использовать этот опыт для улучшения, очистки, полировки, разделения того, что было слишком большим, объединения того, что было слишком фрагментировано, определения и использования шаблонов проектирования, анализа узких мест производительности и нетривиальных проблем безопасности. В целом, все эти изменения будут иметь огромное влияние на написанные вами модульные тесты, но не на функциональные тесты.
Когда вы закончите эту вторую итерацию, у вас будет небольшой драгоценный камень, хорошо проверенный, хорошо документированный и хорошо разработанный. Теперь у вас есть и опыт, и код для третьей итерации. Вы добавите новые функции и варианты использования для улучшения вашего приложения. Вы найдете грубые пятна и в конце концов войдете в четвертую итерацию, аналогичную второй. Промыть и повторить.
Это мой общий подход к разработке программного обеспечения. Он похож на спиральный дизайн с короткими трехмесячными итерациями и элементами гибкой разработки, что позволяет вам изучить проблемы и познакомиться с вашим программным обеспечением и областью его применения. Конечно, это вопрос масштабируемости, поэтому, если приложение настолько велико, что в нем участвуют сотни разработчиков, все будет немного сложнее, чем это, но в конце я думаю, что идея всегда одна и та же, разделяй и властвуй.
Итак подведем итоги:
- В первой итерации вы почувствуете вкус этого и узнаете
- На второй итерации вы очищаете свой продукт и готовите его к будущему
- В третьей итерации вы добавляете новые функции и узнаете больше
- перейти к 2
Самый интересный источник, о котором я знаю, это часть D " Построения объектно-ориентированного программного обеспечения", 2-е издание, Бертран Мейер.
Часть D: Объектно-ориентированная методология: хорошее применение метода
19: по методологии, 20: шаблон проектирования: многопанельные интерактивные системы, 21: пример с наследованием: "отмена" в интерактивной системе, 22: как найти классы, 23: принципы проектирования классов, 24: хорошее использование наследования, 25: полезные методы, 26: чувство стиля, 27: объектно-ориентированный анализ, 28: процесс создания программного обеспечения, 29: обучение методу
Интересно, что глава 22. Как найти занятия доступна онлайн.
Это часто повторяется, но совершенно верно - поймите ваши данные.
Для ООП ваши классы должны описывать существенные фрагменты информации и то, как они взаимодействуют.
Если у вас есть ментальная модель, которая хорошо описывает поведение и время жизни данных, вам будет легко планировать свои занятия.
Это просто продолжение: точно знайте, что вы пытаетесь сделать.
Попробуйте использовать поведенческую разработку. Тяжело будет отказаться от своих старых привычек, но я обнаружил, что BDD действительно является лучшим выбором для разработки в реальном мире.
Проблема с большими проектами заключается в том, что вы не можете контролировать все взаимодействия между компонентами. Таким образом, важно уменьшить сложность проекта. Диаграммы классов и последовательностей слишком подробны для этого этапа проектирования.
Сначала попробуйте думать с более высокого уровня абстракции. Подумайте об основных компонентах и их обязанностях (их интерфейсе с другими компонентами), посмотрите на некоторые архитектурные шаблоны для вдохновения (нет, не шаблоны проектирования, это слишком низкий уровень! MVC и Multi-Tier являются примерами архитектурных шаблонов). Для достаточно крупных проектов такое представление должно состоять из 3-5 компонентов.
Только тогда вы увеличиваете масштаб определенного компонента и пытаетесь создать его. Теперь мы находимся на уровне шаблонов проектирования и диаграмм классов. Попробуйте сосредоточиться на этой части проекта, если вы обнаружите, что вам нужно добавить ответственность к одному из других компонентов, просто добавьте его в список документации / задач. Не тратьте время на размышления о последствиях, в этот момент они меняются слишком быстро, рассмотрите, когда дизайн станет более надежным.
Вам не нужно полностью разрабатывать каждый компонент на этом этапе, хотя, вероятно, разумно иметь фрагмент кода, который реализует интерфейс неосуществленных компонентов и генерирует простые, но полезные ответы. Таким образом, вы можете начать разработку (и дизайн) по одному компоненту за раз и протестировать его в достаточной степени.
Конечно, когда новые компоненты готовы, вы должны проверить, как (и если) они интегрируются друг с другом, прежде чем двигаться дальше.
Короче говоря: возьмите ОО и принцип сокрытия информации и поднимите его на новый уровень!
PS: Делайте наброски во время проектирования, это как настоящая архитектура!
PPS: Постарайтесь подойти к этому вопросу с разных сторон, подумайте нестандартно (хотя это может быть подход), для этого может быть полезно обсуждение со сверстниками... и вам есть о чем поговорить за обедом.
Техника, которую я использовал в реальных проектах с достаточным успехом, - это дизайн, основанный на ответственности, вдохновленный книгой Уирфа-Брока.
Начните с пользовательских историй верхнего уровня, а с коллегами за доской сделайте набросок взаимодействий высокого уровня, которые они подразумевают. Это дает вам первое представление о том, что такое большие модули; и одну или две итерации CRC-карты высокого уровня, такие как игра, в которой вы должны были стабилизировать список основных компонентов, что они делают и как они взаимодействуют.
Затем, если какая-либо из обязанностей большая или сложная, уточните эти модули до тех пор, пока у вас не появятся вещи, которые достаточно малы и просты, чтобы быть объектами, путем воспроизведения взаимодействий внутри модуля для каждой из основных операций, определенных взаимодействиями более высокого уровня.,
Знание, когда остановиться, является вопросом суждения (которое приходит только с опытом).
Шаблоны проектирования
Шаблоны креационного дизайна
Singleton - убедитесь, что создан только один экземпляр класса, и предоставьте глобальную точку доступа к объекту.
Factory (упрощенная версия Factory Method)- создает объекты без предоставления клиенту логики создания экземпляров и ссылается на вновь созданный объект через общий интерфейс.
Factory Method - определяет интерфейс для создания объектов, но позволяет подклассам решать, какой класс создавать, и ссылается на вновь созданный объект через общий интерфейс.
Абстрактная фабрика - предлагает интерфейс для создания семейства связанных объектов без явного указания их классов.
Builder - Определяет экземпляр для создания объекта, но позволяет подклассам решать, какой класс создавать, и позволяет более точно контролировать процесс построения.
Прототип. Укажите типы объектов, создаваемых с использованием прототипа, и создайте новые объекты, скопировав этот прототип.
Поведенческие шаблоны дизайна
Цепочка ответственности - позволяет избежать прикрепления отправителя запроса к его получателю, предоставляя таким образом другим объектам возможность обработки запроса. - Объекты становятся частями цепочки, и запрос отправляется от одного объекта к другому по цепочке, пока один из объектов не обработает его.
Команда - инкапсулирует запрос в объекте. Позволяет параметризовать клиентов с разными запросами и позволяет сохранять запросы в очереди.
Интерпретатор - для данного языка определите представление для его грамматики вместе с интерпретатором, который использует представление для интерпретации предложений на языке / сопоставьте домен с языком, язык с грамматикой и грамматику с иерархическим объектно-ориентированным дизайном
Итератор - предоставляет способ последовательного доступа к элементам агрегатного объекта, не раскрывая его базовое представление.
Посредник - Определите объект, который инкапсулирует, как взаимодействует набор объектов. Посредник способствует слабой связи, не позволяя объектам явно ссылаться друг на друга, и позволяет независимо изменять их взаимодействие.
Наблюдатель - определите зависимость "один ко многим" между объектами, чтобы при изменении состояния одного объекта все его иждивенцы уведомлялись и обновлялись автоматически.
Стратегия - определите семейство алгоритмов, инкапсулируйте каждый и сделайте их взаимозаменяемыми. Стратегия позволяет алгоритму варьироваться независимо от клиентов, которые его используют.
Шаблонный метод - Определяет каркас алгоритма в операции, откладывая некоторые шаги до подклассов / Шаблонный метод позволяет подклассам переопределять определенные шаги алгоритма, не позволяя им изменять структуру алгоритма.
Посетитель - представляет операцию, выполняемую с элементами структуры объекта. Посетитель позволяет определить новую операцию, не изменяя классы элементов, с которыми она работает.
Null Object - Предоставить объект в качестве заменителя отсутствия объекта данного типа. / Шаблон нулевого объекта обеспечивает интеллектуальное поведение "ничего не делать", скрывая детали от его соавторов.
Структурные шаблоны проектирования
Адаптер - Преобразуйте интерфейс класса в другой интерфейс, ожидаемый клиентами. / Adapter позволяет классам работать вместе, что иначе невозможно из-за несовместимых интерфейсов.
Мост - объединяет объекты в древовидные структуры для представления иерархий части-целого. / Composite позволяет клиентам одинаково относиться к отдельным объектам и композициям объектов.
Composite - объединяет объекты в древовидные структуры для представления иерархий части-целого. / Composite позволяет клиентам одинаково относиться к отдельным объектам и композициям объектов.
Декоратор - динамически добавлять дополнительные обязанности к объекту.
Flyweight - используйте общий доступ для поддержки большого количества объектов, которые имеют общую часть своего внутреннего состояния, когда другая часть состояния может изменяться.
Памятка - захватывает внутреннее состояние объекта, не нарушая инкапсуляцию и, таким образом, предоставляет средство для восстановления объекта в исходное состояние при необходимости.
Прокси - предоставьте "Заполнитель" для объекта, чтобы управлять ссылками на него.
Я бы порекомендовал вам использовать BlueJ, а также ActiveWriter для обучения, а также для развития хорошего понимания объектов. Книга рекомендуется также хороший ресурс.
Из Википедии:
BlueJ - интегрированная среда разработки для языка программирования Java, разработанная главным образом для образовательных целей, но также подходящая для разработки небольших программ.
Кроме того, он использует UML, и для меня это был хороший ресурс для понимания нескольких вещей о моделировании объектов.
http://www.ryanknu.com/ryan/bluej.png
ActiveWriter - это инструмент для моделирования сущностей и отношений, он также генерирует код и легко вносит изменения. Это сэкономит вам время и для гибкой разработки очень подходит.
Просто цитирую http://www.fysh.org/~katie/computing/methodologies.txt
А в основе RUP лежит небольшая область, где вы должны использовать таланты ОО-дизайна... если у вас их нет, это все равно, что иметь методологию для бега на 100 метров.
"Шаг 1: написать о беге очень быстро. Шаг 2: Иди и нарисуй план ипподрома. Шаг 3: пойди и купи действительно обтягивающие шорты из лайкры. Шаг 4: беги очень, очень, очень быстро. Шаг 5: сначала пересечь линию "
Это тот четвертый шаг, который сложный. Но если вы сделаете упор на 1,2,3 и 5, то, возможно, никто не заметит, и тогда вы, вероятно, сможете заработать много денег, продавая методологию тем спортсменам, которые думают, что есть какой-то "секрет" в беге на 100 метров. бегущий
Вы задали вопрос, который многие авторы используют для написания книги. Существует несколько методологий, и вы должны выбрать ту, которая кажется вам "самой красивой".
Я могу порекомендовать книгу Эрика Эванса "Дизайн, управляемый доменом". Также проверьте сайт http://dddcommunity.org/.
Прежде всего - дизайн должен исходить из вашей души. Вы должны чувствовать это каждым своим волокном. Я обычно спускаюсь по ней два или три месяца, прежде чем начать что-либо делать, просто ходить по улицам (правда). И думаешь. Знаешь, ходьба - это хорошая медитация. Так что это позволяет вам хорошо концентрироваться.
Во-вторых, используйте ООП и классы только там, где существует естественная иерархия объектов. Не "вверните" это к этому искусственно. Если строгой иерархии не существует (как в большинстве бизнес-приложений) - переходите к процедурным / функциональным или, по крайней мере, используйте объекты только в качестве контейнеров данных с изолированными средствами доступа.
И последнее - попробуйте прочитать это: Алгоритм творческого мышления
Я думаю, что ответ здесь должен быть очень разным в зависимости от реального опыта парня, спрашивающего.
Если у вас есть только один или два года опыта работы, вы должны перейти к вопросу: как вы дойдете до того, что вы действительно знаете свои данные и точно понимаете, что вы пытаетесь сделать?
Да, если вы работали в реальном мире более 5 лет, то вы бы выбрали любую из множества моделей процессов или методов разработки программного обеспечения.
Но вы не получаете опыт, только читая книги. Вы должны учиться, работая в хорошей группе под хорошим руководством.
Если это невозможно, то вы должны сделать это самостоятельно. Начните итерацию, кодируя, вероятно, очень неприятный фрагмент кода, изучая ваши ошибки, выкидывая все это, кодируя лучший и так далее.
Вы узнаете много нового о своей кодовой базе. Инструменты есть инструменты, они ничему вас не научат.
- изучение и освоение дизайна шаблонов.
- Далее узнайте о домене, управляемом дизайном
- После этого изучите сбор требований
Я взял курс OOD несколько семестров назад и многому научился у него; как написание UML и перевод документов требований в объекты и классы. Мы также выучили диаграммы последовательности, но почему-то я пропустил лекцию или что-то в этом роде.
Вы знаете о шаге 3. Вы должны освоить его. Я имею в виду, благодаря большой практике, чтобы это стало вашей второй натурой. Это потому, что метод, который вы изучаете, просто противоречит тому, что мы привыкли иметь. Таким образом, вы должны действительно освоить это. В противном случае вы всегда вернетесь к своему первоначальному образу жизни. Это похоже на Test Driven Process, где многие разработчики Java отказываются от него после нескольких попыток. Если они полностью не справляются с этим, иначе это просто бремя для них
Напишите варианты использования, особенно для альтернативного курса. Альтернативный курс занимает более 50% нашего времени разработки. Обычно, когда ваш PM назначает вам задачу, например, создает систему входа в систему, он думает, что это прямо, вы можете потратить 1 день, чтобы завершить ее. Но он никогда не принимает во внимание то, что вам нужно учитывать: 1. что если пользователь введет неверный пароль, 2. что если пользователь введет неверный пароль 3 раза, 3. что если пользователь не введет имя пользователя и т. Д. Вам нужно перечислить их и показать в личку, попросить его перенести срок.
Если у вас есть экспертиза предметной области в проекте, вы собираетесь работать, как, скажем, банковское дело. Ваши объекты легко структурировать, и вы знаете, как эти улучшения появляются каждый день.
Если у вас нет этого опыта, работайте с кем-то, кто обладает этим опытом, и преобразуйте эти идеи в технические детали.
Если вы не уверены, как структурировать дизайн вашего проекта. Слепо следуйте книге "Прагматичный программист". Я был в такой же ситуации, попробуйте прочитать главу из этой книги. вы увидите разницу, она изменит ваше мышление разработчика программного обеспечения.
Я использую Test-Driven Design (TDD). Написание теста на самом деле помогает привести вас к чистому и правильному дизайну. См. http://en.wikipedia.org/wiki/Test-driven_development.
Изучите шаблоны проектирования. За последние два года это была моя личная революция в отношении ООП. Получить книгу. Я бы порекомендовал вам это:
Он есть в Java, но может быть расширен на любой язык.
Боюсь, что это не тот ответ, который людям нравится слышать. В любом случае, позвольте мне высказать свое мнение.
ООП следует рассматривать как одну из парадигм, а не как высшую парадигму. ООП хорош для решения определенных задач, таких как разработка библиотеки GUI. Это также вписывается в стиль разработки программного обеспечения, за которым обычно следуют крупные компании-разработчики программного обеспечения - элитная команда дизайнеров или архитекторов излагает дизайн программного обеспечения в диаграммах UML или некотором другом подобном носителе, а менее просвещенная команда разработчиков переводит этот дизайн в исходный код. ООП мало что дает, если вы работаете в одиночку или с небольшой командой высококвалифицированных программистов. Тогда лучше использовать язык, который поддерживает несколько парадигм и поможет вам быстро создать прототип. Python, Ruby, Lisp/Scheme и т. Д. Являются хорошим выбором. Прототип - это ваш дизайн. Тогда вы улучшите это. Используйте парадигму, которая лучше всего подходит для решения проблемы. При необходимости оптимизируйте горячие точки с помощью расширений, написанных на C или другом системном языке. Используя один из этих языков, вы также получаете расширяемость бесплатно, не только на уровне программиста, но и на уровне пользователя. Такие языки, как Lisp, могут динамически генерировать и выполнять код, а это означает, что ваши пользователи могут расширять приложение путем написания небольших фрагментов кода на языке, на котором написано само программное обеспечение! Или, если вы решили написать программу на C или C++, рассмотрите возможность встраивания интерпретатора для небольшого языка, такого как Lua. Предоставьте функциональность в виде плагинов, написанных на этом языке.
Я думаю, что в большинстве случаев ООП и ООД создают программное обеспечение, которое является жертвой чрезмерного дизайна.
Подводя итог, мой предпочтительный способ написания программного обеспечения:
- Используйте динамический язык.
- Напишите дизайн (прототип) на этом языке.
- При необходимости оптимизируйте определенные области, используя C/C++.
- Обеспечить расширяемость посредством интерпретатора самого языка реализации.
Последняя функция позволяет программному обеспечению легко адаптироваться к конкретным требованиям пользователя (включая меня!).
Во время моих приключений по разработке структур классов я заметил, что очень полезно начать с написания некоторого псевдокода. Это означает: я начинаю с "написания" некоторых общих фрагментов кода приложения на самом высоком уровне, играю с ним и обнаруживаю элементы, которые появляются - на самом деле, элементы, которые я - как программист - хотел бы использовать. Это очень хорошая отправная точка для разработки общей структуры модулей и их взаимодействия. После нескольких итераций вся структура начинает больше походить на полную систему классов. Это очень гибкий способ разработки частей кода. Вы можете назвать это программист-ориентированным дизайном.
Честно говоря, хорошим шагом было бы вернуться назад и посмотреть на диаграмму потоков и диаграмму последовательности. Есть множество хороших сайтов, которые показывают вам, как это сделать. Я считаю, что это неоценимо, когда я смотрю на то, как я хочу разбить программу на классы, поскольку я точно знаю, что программа должна вводить, вычислять и выводить, и каждый шаг можно разбить на одну часть программы.
Один из полезных методов - связать ваше уникальное описание проблемы с тем, что вы можете найти в реальном мире. Например, вы моделируете сложную систему здравоохранения, которая покорит мир штурмом. Есть ли примеры, которые вы можете с готовностью использовать для моделирования этого?
В самом деле. Посмотрите, как будет работать боковая аптека или кабинет врача.
Довести проблему вашего домена до чего-то понятного вам; то, к чему вы можете относиться.
Затем, когда "игроки" в домене начинают казаться очевидными, и вы начинаете моделировать свой код, выберите подход моделирования "поставщик-потребитель", т.е. ваш код является "поставщиком" модели, а вы - "потребителем". ".
Отношение к области и понимание ее на высоком уровне является ключевой частью любого дизайна.
В ответ на вопрос " Каков рабочий процесс, которым вы руководствуетесь при разработке программного обеспечения, которое собираетесь писать?"