Генеалогическое древо
Вы когда-нибудь хотели создать родословную семьи? Что вы знаете о своих предках? Несомненно, бабушка рассказала вам о своих родителях, возможно, она упомянула своих дедушек и бабушек. Кто они, что они делали, где жили люди более ранних поколений?
Знакомство с историей ваших родственников может быть увлекательным приключением. Так создайте генеалогическое древо!
Генеалогическое древо – а зачем?
Известные роды знают свою историю, хранят память о своих предках и их достижениях. Вероятно, каждый из нас видел генеалогическое древо королевских династий и аристократических семей. А почему бы не объединить историю своей семьи, даже скромную? Стоит узнать свои корни. Стоит знать своё происхождение, чьи гены мы унаследовали. Стоит подумать о том, кто мы есть, откуда пришли. Бурная история страны запутала судьбы многих поколений. Давайте попробуем их воссоздать. Ведь наши близкие стоят нашей памяти, а также памяти наших детей и будущих поколений.
Знакомство с родственными связями — это как переход в прошлое. Его можно рассматривать как приключение, как археологическую экспедицию, в ходе которой можно сделать интересные открытия.
Как приступить к созданию генеалогического древа?
Семейное древо являет собой графический способ представления родственных отношений. Необходимо «докапываться» до наших прародителей как «в глубину», так и «в ширину». Следует установить кровные и близкие связи, вероисповедание, узнать даты рождения и смерти, даты создания брачного союза и развода. Будет ли древо раскидистое, зависит от численности рода и наших усилий по розыску информации.
Где искать информацию и документы?
Необходимо начать с разговоров с пожилыми членами семьи. Они много помнят из рассказов своих дедушек и бабушек. Но так как память ненадёжна, услышанную информацию стоит подтвердить документально. Во многих домах хранятся семейные архивы: документы, метрики, свидетельства о смерти и браке, пожелтевшие фотографии.
Стоит их все пересмотреть и систематизировать.Информация о членах семьи может быть также найдена в летописях отдельных населённых пунктов, в списках переписи населения или в т.н. ревизских сказках, стоит также посетить кладбище, если вы знаете, откуда родом Ваши предки, чтобы разыскать забытые надгробия.
Было бы хорошо знать наименования местностей, где жили Ваши прародичи, сколько было у них детей, какого пола, какую религию исповедовали. В архивах тех местностей хранятся акты гражданского состояния, метрические книги.
Настоящим кладезем знаний являются списки церковных приходов, в которых велись записи всех важных дат: рождения, брака, смерти. Их, как и ревизские сказки, можно разыскать в региональных исторических или государственных архивах. Сегодня отличным подспорьем является Интернет. Есть много сайтов, посвященных генеалогии, поисковым системам, которые помогают в розыске семейных связей.
Трудно ли «докопаться» до своих корней?
Генеалогическое древо семьи, если это нужно сделать добросовестно и достоверно, требует много работы и времени. Сравнительно легко найти данные XX века, многие документы XIX века также находятся в сохранности. Намного легче справиться с установлением истории дворянских семей, потому как у них были фамилии уже с XVI-XVII века (в то время как крестьяне до XVIII-XIX веков были бесфамильные) и они закрепляли историю своей жизни записями и документами.
Тем не менее, «обычная» семья также заслуживает увековечивания и передачи знаний о ней будущим поколениям.
А может «готовое» генеалогическое древо?
Познание истории и происхождения фамилии
требует большого упорства и времени. Необходимо просматривать груды документов, ездить по учреждениям и архивам, находящихся в разной степени удалённости, возможно за границей, делать телефонные звонки, вести переписку и т.д. Необходимо собственно нарисовать семейное древо. Правильный шаблон генеалогического древа можно найти в Интернете. Более того, в Интернете есть генеалогические программы, которые облегчают весь процесс составления родословной.
Можно также заказать генеалогическое древо у специализирующейся в этой области компании. Однако ничто не может заменить эмоции, которые сопровождают «собственноручное» распутывание связей и загадок своих близких и дальних родственников. Да и с точки зрения мотивации в создании достоверной и максимально полной истории семьи ни одно
Используйте возможности ДНК тестов
С развитием науки в последние годы всё шире раскрываются возможности ДНК генеалогии. ДНК тесты и их результаты представляют собой удивительную шанс преодолеть время и загляну в историю своего происхождения.
Построение с помощью шаблонов: древовидный шаблон
Многие из шаблонов проектирования схем, которые мы рассмотрели до сих пор, подчеркивали, что экономия времени на операциях JOIN является преимуществом. Данные, к которым обращаются вместе, должны храниться вместе, и некоторое дублирование данных допустимо. Хорошим примером является шаблон проектирования схемы, такой как расширенная ссылка. Однако что, если данные, которые нужно объединить, являются иерархическими? Например, вы хотите определить цепочку отчетности от сотрудника до генерального директора? MongoDB предоставляет оператор $graphLookup для навигации по данным в виде графиков, и это может быть одним из решений. Однако, если вам нужно выполнить много запросов к этой иерархической структуре данных, вы можете применить то же правило хранения вместе данных, к которым осуществляется доступ вместе. Здесь мы можем использовать шаблон дерева.
Шаблон дерева
Существует множество способов представить дерево в устаревшей табличной базе данных. Наиболее распространенные из них для узла в графе, чтобы перечислить своего родителя и для узла, чтобы перечислить своих дочерних элементов. Оба эти представления могут потребовать множественного доступа для построения цепочки узлов.
В качестве альтернативы мы можем сохранить полный путь от узла к вершине иерархии. В этом случае мы в основном будем хранить «родителей» для каждого узла. В табличной базе данных это, скорее всего, будет сделано путем кодирования списка родителей. Подход в MongoDB состоит в том, чтобы просто представить это как массив.
Как видно здесь, в этом представлении есть некоторое дублирование данных. Если информация относительно статична, как в генеалогии, ваши родители и предки не изменятся, что упрощает управление этим массивом. Однако в нашем примере с корпоративной структурой, когда что-то меняется и происходит реструктуризация, вам нужно будет обновить иерархию по мере необходимости. Это все еще небольшие затраты по сравнению с преимуществами, которые вы можете получить, если не будете все время рассчитывать деревья.
Пример использования
Каталоги товаров — еще один очень хороший пример использования шаблона «Дерево». Часто товары относятся к категориям, которые являются частью других категорий. Например, твердотельный накопитель может находиться в разделе Жесткие диски , который находится в разделе Хранилище , который находится в разделе Компьютерные детали . Иногда организация категорий может меняться, но не слишком часто.
Обратите внимание в документе выше на поле ancestor_categories
, которое отслеживает всю иерархию. У нас также есть поле родительская_категория
. Дублирование непосредственного родителя в этих двух полях — это передовой метод, который мы разработали после работы со многими клиентами, использующими древовидный шаблон. Включение поля «родительский» часто бывает удобным, особенно если вам нужно поддерживать возможность использования $graphLookup в ваших документах.
Хранение предков в массиве дает возможность создать многоключевой индекс для этих значений. Это позволяет легко найти всех потомков данной категории. Что касается непосредственных дочерних элементов, они доступны при просмотре документов, у которых данная категория является непосредственным «родителем». Мы только что сказали вам, что это поле будет удобно.
Заключение
Как и для многих шаблонов, при их использовании часто приходится идти на компромисс между простотой и производительностью. В случае древовидного шаблона вы получаете лучшую производительность, избегая множественных объединений, однако вам нужно будет управлять обновлениями вашего графа.
В следующем посте этой серии будет рассмотрен шаблон предварительного распределения .
Если у вас есть вопросы, пожалуйста, оставьте комментарии ниже.
Предыдущие части здания с узорами:
- Полиморфный паттерн
- Шаблон атрибута
- Модель «Ведро»
- Образец выброса
- Вычисленный шаблон
- Шаблон подмножества
- Шаблон расширенного эталона
- Шаблон приближения
Композитный
НАЧАЛА ЗИМНЯЯ СКИДКА!
/ Шаблоны проектирования / Структурные модели
Также известен как: Дерево объектов
IntentComposite — это структурный шаблон проектирования, который позволяет объединять объекты в древовидные структуры, а затем работать с этими структурами, как если бы они были отдельными объектами.
ПроблемаИспользование составного шаблона имеет смысл только в том случае, если базовая модель вашего приложения может быть представлена в виде дерева.
Например, представьте, что у вас есть два типа объектов: Продукты
и Коробки
. Коробка
может содержать несколько продуктов
, а также несколько меньших коробок
. Эти маленькие коробки
также могут содержать некоторые продуктов
или даже меньшие коробки
и так далее.
Допустим, вы решили создать систему заказов, использующую эти классы. Заказы могут содержать как простые товары без какой-либо упаковки, так и коробки с продуктами… и другие коробки. Как бы вы определили общую стоимость такого заказа?
Заказ может включать в себя различные продукты, упакованные в коробки, которые упакованы в большие коробки и так далее. Вся конструкция выглядит как перевернутое дерево.
Вы можете попробовать прямой подход: разверните все коробки, просмотрите все продукты и подсчитайте сумму. Это было бы выполнимо в реальном мире; но в программе это не так просто, как запустить цикл. Вы должны заранее знать классы Продуктов
и Коробок
, через которые вы проходите, уровень вложенности коробок и другие неприятные детали. Все это делает прямой подход либо слишком неудобным, либо даже невозможным.
Составной шаблон предполагает, что вы работаете с Товарами
и Ящиками
через общий интерфейс, который объявляет метод расчета общей цены.
Как работает этот метод? Для продукта он просто возвращает цену продукта. Для коробки он просматривает каждый предмет, содержащийся в коробке, спрашивает его цену, а затем возвращает общую сумму для этой коробки. Если бы одним из этих предметов была коробка меньшего размера, эта коробка также начала бы перебирать свое содержимое и так далее, пока не были бы рассчитаны цены всех внутренних компонентов. Коробка может даже добавить некоторые дополнительные расходы к окончательной цене, например стоимость упаковки.
Шаблон Composite позволяет рекурсивно запускать поведение для всех компонентов дерева объектов.
Наибольшее преимущество этого подхода заключается в том, что вам не нужно заботиться о конкретных классах объектов, составляющих дерево. Вам не нужно знать, является ли объект простым продуктом или сложной коробкой. Вы можете работать с ними одинаково через общий интерфейс. Когда вы вызываете метод, объекты сами передают запрос вниз по дереву.
Аналогия из реального мираПример военного строения.
Армии большинства стран имеют иерархическую структуру. Армия состоит из нескольких дивизий; дивизия — это совокупность бригад, а бригада состоит из взводов, которые могут быть разбиты на отделения. Наконец, отряд — это небольшая группа настоящих солдат. Приказы отдаются наверху иерархии и передаются на каждый уровень до тех пор, пока каждый солдат не узнает, что нужно делать.
СтруктураИнтерфейс компонента описывает операции, общие как для простых, так и для сложных элементов дерева.
Лист — это базовый элемент дерева, не имеющий подэлементов.
Обычно конечные компоненты выполняют большую часть реальной работы, поскольку им некому делегировать эту работу.
Контейнер (также известный как составной ) — это элемент, который имеет подэлементы: листья или другие контейнеры. Контейнер не знает конкретных классов своих потомков. Работает со всеми подэлементами только через интерфейс компонента.
При получении запроса контейнер делегирует работу своим подэлементам, обрабатывает промежуточные результаты и затем возвращает конечный результат клиенту.
Клиент работает со всеми элементами через интерфейс компонента. В результате клиент может одинаково работать как с простыми, так и со сложными элементами дерева.
В этом примере шаблон Composite позволяет реализовать наложение геометрических фигур в графическом редакторе.
Пример редактора геометрических фигур.
Класс CompoundGraphic
— это контейнер, который может содержать любое количество подформ, включая другие составные формы. Составная форма имеет те же методы, что и простая форма. Однако вместо того, чтобы делать что-то самостоятельно, составная фигура рекурсивно передает запрос всем своим дочерним элементам и «суммирует» результат.
Клиентский код работает со всеми фигурами через единый интерфейс, общий для всех классов фигур. Таким образом, клиент не знает, работает ли он с простой формой или сложной. Клиент может работать с очень сложными структурами объектов, не привязываясь к конкретным классам, формирующим эту структуру.
// Интерфейс компонента объявляет общие операции для обоих
// простые и сложные объекты композиции.
Интерфейс Графика есть
метод переместить (х, у)
метод рисования()
// Листовой класс представляет конечные объекты композиции. А
// листовой объект не может иметь подобъектов. Обычно это лист
// объекты, выполняющие реальную работу, а только составные объекты
// делегировать их подкомпонентам.
класс Dot реализует графику
поле х, у
конструктор Dot(x, y) { ... }
метод move(x, y)
это.х += х, это.у += у
метод draw() есть
// Нарисуйте точку в точках X и Y.
// Все классы компонентов могут расширять другие компоненты.
класс Circle extends Dot is
радиус поля
конструктор Circle(x, y, радиус) { ... }
метод draw() есть
// Нарисуйте окружность по X и Y с радиусом R.
// Составной класс представляет сложные компоненты, которые могут
// есть дети. Составные объекты обычно делегируют фактическую
// работаем со своими детьми, а потом "суммируем" результат.
класс CompoundGraphic реализует графику
дочерние поля: массив графических
// Составной объект может добавлять или удалять другие компоненты
// (как простой, так и сложный) в или из его дочернего списка.
метод add(child: Graphic)
// Добавляем дочерний элемент в массив дочерних элементов.
метод удаления (дочерний элемент: графика)
// Удалить дочерний элемент из массива дочерних элементов.
метод move(x, y)
foreach (ребенок в детях) делать
ребенок. двигаться (х, у)
// Композит выполняет свою основную логику в конкретном
// способ. Он рекурсивно проходит через всех своих потомков,
// сбор и подведение их итогов. Поскольку
// потомки композита передают эти вызовы своим
// дочерние элементы и т. д., просматривается все дерево объектов
// как результат.
метод draw() есть
// 1. Для каждого дочернего компонента:
// - Нарисовать компонент.
// - Обновить ограничивающий прямоугольник.
// 2. Нарисуйте пунктирный прямоугольник, используя ограничивающий
// координаты.
// Клиентский код работает со всеми компонентами через их базу
// интерфейс. Таким образом, клиентский код может поддерживать простой лист.
// компоненты, а также сложные композиты.
класс ImageEditor
поле все: CompoundGraphic
метод загрузки ()
все = новый CompoundGraphic()
all.add (новая точка (1, 2))
all.add(новый круг(5, 3, 10))
// ...
// Объединение выбранных компонентов в один сложный композит
// компонент.
метод groupSelected (компоненты: массив графики)
группа = новый CompoundGraphic()
foreach (компонент в компонентах) делать
group.add(компонент)
все.удалить(компонент)
все.добавить(группа)
// Будут отрисованы все компоненты.
все.рисовать()
ПрименимостьИспользуйте составной шаблон, когда необходимо реализовать древовидную структуру объекта.
Шаблон Composite предоставляет два основных типа элементов с общим интерфейсом: простые листья и сложные контейнеры. Контейнер может состоять как из листьев, так и из других контейнеров. Это позволяет создавать вложенную структуру рекурсивных объектов, напоминающую дерево.
Используйте шаблон, если вы хотите, чтобы клиентский код одинаково обрабатывал как простые, так и сложные элементы.
Все элементы, определенные шаблоном Composite, имеют общий интерфейс. Используя этот интерфейс, клиенту не нужно беспокоиться о конкретном классе объектов, с которыми он работает.
Как реализоватьУбедитесь, что основная модель вашего приложения может быть представлена в виде древовидной структуры. Попробуйте разбить его на простые элементы и контейнеры. Помните, что контейнеры должны содержать как простые элементы, так и другие контейнеры.
Объявите интерфейс компонента со списком методов, подходящих как для простых, так и для сложных компонентов.
Создайте конечный класс для представления простых элементов. Программа может иметь несколько разных конечных классов.
Создайте класс контейнера для представления сложных элементов. В этом классе предоставьте поле массива для хранения ссылок на вложенные элементы. Массив должен иметь возможность хранить как листья, так и контейнеры, поэтому убедитесь, что он объявлен с типом интерфейса компонента.
При реализации методов интерфейса компонента помните, что контейнер должен делегировать большую часть работы подэлементам.
Наконец, определите методы добавления и удаления дочерних элементов в контейнере.
Имейте в виду, что эти операции могут быть объявлены в интерфейсе компонента. Это нарушило бы принцип разделения интерфейса , потому что методы в конечном классе будут пустыми. Однако клиент сможет относиться ко всем элементам одинаково, даже при составлении дерева.
- Вы можете более удобно работать со сложными древовидными структурами: используйте полиморфизм и рекурсию в своих интересах.
- Открытый/Закрытый Принцип . Вы можете вводить в приложение новые типы элементов, не нарушая существующий код, который теперь работает с деревом объектов.
- Может быть сложно предоставить общий интерфейс для классов, функциональность которых слишком сильно различается. В некоторых сценариях вам потребуется чрезмерно обобщить интерфейс компонента, что усложнит его понимание.
Вы можете использовать Builder при создании сложных составных деревьев, потому что вы можете запрограммировать его этапы построения для рекурсивной работы.
Chain of Responsibility часто используется в сочетании с Composite. В этом случае, когда листовой компонент получает запрос, он может передать его по цепочке всех родительских компонентов до корня дерева объектов.
Вы можете использовать итераторы для обхода составных деревьев.
Вы можете использовать Visitor для выполнения операции над всем составным деревом.
Вы можете реализовать общие конечные узлы составного дерева как приспособленцы, чтобы сэкономить немного оперативной памяти.
Composite и Decorator имеют схожие структурные диаграммы, поскольку оба полагаются на рекурсивную композицию для организации неограниченного количества объектов.
Декоратор похож на Composite , но имеет только один дочерний компонент. Есть еще одно существенное отличие: Decorator добавляет дополнительные обязанности обернутому объекту, а Composite просто «суммирует» результаты своих дочерних элементов.
Однако шаблоны также могут взаимодействовать: вы можете использовать Decorator для расширения поведения определенного объекта в Composite дереве.
Проекты, в которых интенсивно используются Composite и Decorator, часто могут выиграть от использования Prototype.