Architecture Flashcards
SOLID
Акроним, который описывает пять принципов объектно-ориентированного программирования и проектирования:
S - Каждый класс или сущность доложны решать лишь одну задачу, нельзя делать так чтобы класс разростался и делал много задач, что приведет к антипаттерну GodObject
O - Программные сущности (классы, модули, функции) должны быть открыты для расширения, но не для модификации. Надо стараться добавлять новый функционал не за счет изменения каких-то существующих сущностей, а за счет добавление новой сущности путем композиции, наследвоания и т.д., и реализовывать новый функционал уже там, что в свою очередь не приведет к нарушению работы программы и необходимости проводить регрессионное тестирование
L - Принцип подстановки Барбары Лисков. Наследуемый класс должен дополнять а не замещать поведение базового класса. Мы получаем более прозрачное поведение и более прозрачную структуру
I - Принцип разделения интерфейса. Нужно создавать узкоспециализированные интерфейсы, предназначенные для конкретного класса. Сабклассы не должны реализовывать методы, которые им не нужно использовать. Делать общее решение, какой-то общий интерфейс, и потом в классах пробрасывать налл или ошибку в методе - это антипатерн
D - Объектом зависимости должна быть абстракция, а не что-то конкретное. (Модули верхних уровней не должны зависеть от модулей нижних уровней. !!! В результате, например, может оказаться так, что высокоуровневые компоненты зависят от низкоуровневых компонентов.
ООП
Парадигма программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы образуют иерархию наследования
Абстракция - отделение концепции от реализации. В ООП абстракция означает, что для каждого объекта мы задаем минимальное количество методов, полей и описаний, которые позволят нам решить задачу. Чем меньше характеристик, тем лучше абстракция, но ключевые характеристики убирать нельзя.
Инкапсуляция - это ограничение доступа к методам и переменным объекта. Ну по сути это механизм, который объединяет данные и код, и защищает и то и другое от внешнего вмешательства или какого-то неправильного использования.
Наследование - объект может наследовать данные и функциональность некоторого существующего типа. нужно чтобы было достаточно на каждом иерархическом шаге учитывать только изменения, и не дублировать всё остальное.
Полиморфизм - способность функции обрабатывать данные разных типов. Один интерфейс — много реализаций Его делят еще на параметрический полиморфизм и ad-hoc-полиморфизм. Параметрический полиморфизм подразумевает исполнение одного и того же кода для всех допустимых типов аргументов, а вот ad-hoc-полиморфизм подразумевает исполнение разного кода для каждого типа аргумента.
Функциональное програмирование
Парадигма программирования, в которой процесс вычисления трактуется как вычисление значений функций в математическом понимании.
Чистые функции - функция, вызываемая от одних и тех же аргументов, всегда возвращает одинаковое значение. Во время выполнения функции не возникают побочные эффекты( Побочный эффект — это изменение чего-то отличного от функции, которая выполняется в текущий момент. Изменение переменной вне функции, вывод в консоль, вызов исключения, чтение данных из файла ).
Функции высшего порядка. - определяются как функции, принимающие другую функцию как аргумент или возвращающие функцию. Ну например map или filter.
Функции первого класса - это означает, что язык поддерживает передачу функций в качестве аргументов другим функциям, возврат их как результат других функций, присваивание их переменным или сохранение в структурах данных
Иммутабельность данных - в функциональном программировании вы не можете изменить переменную после ее инициализации. Вы можете создавать новые, но не можете изменять существующие — и благодаря этому вы можете быть уверены, что никакая переменная не изменится.
Относительная прозрачность - если вы можете заменить вызов функции на возвращаемое значение, и состояние при этом не изменится, то функция относительно прозрачна.
Лямбда исчисление - Функциональное программирование сильно опирается на эту математическую систему. В лямбда-исчислении все функции могут быть анонимными, поскольку единственная значимая часть заголовка функции — это список аргументов.При вызове все функции проходят процесс каррирования (если вызывается функция с несколькими аргументами, то сперва она будет выполнена лишь с первым аргументом и вернёт новую функцию, содержащую на 1 аргумент меньше, которая будет немедленно вызвана. Этот процесс рекурсивен и продолжается до тех пор, пока не будут применены все аргументы, возвращая финальный результат.)
Монады - особый тип данных в функциональных языках программирования, для которого возможно задать императивную последовательность выполнения некоторых операций над хранимыми значениями
Функтор - объект, который можно использовать как функцию
Реактивное програмирование
Парадигма програмирования, ориентированная на обработку потоков данных и событий, где компоненты программы реагируют на изменения данных и автоматически обновляются без явных инструкций.
Что такое big O notation?
Асимптотика из мат. анализа - характер изменения функции при стремлении ее аргумента к определённой точке. O - подсчет количества операций.
Порядок сложности:
O(1)
O(log n)
O(n)
O(n log n)
O(n`2)
O(2n)
O(n!) факториал
Пораждающие паттерны
Фабричный метод (Factory Method) — определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов.
Абстрактная фабрика (Abstract Factory) — позволяет создавать семейства связанных объектов, не привязываясь к конкретным классам создаваемых объектов.
Строитель (Builder) — позволяет создавать сложные объекты пошагово. Строитель даёт возможность использовать один и тот же код строительства для получения разных представлений объектов.
Прототип (Prototype) — позволяет копировать объекты, не вдаваясь в подробности их реализации.
Одиночка (Singleton)— гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Структурные паттерны
Адаптер (Adapter) — позволяет объектам с несовместимыми интерфейсами работать вместе.
Мост (Bridge) — разделяет один или несколько классов на две отдельные иерархии — абстракцию и реализацию, позволяя изменять их независимо друг от друга.
Компоновщик (Composite) — позволяет сгруппировать множество объектов в древовидную структуру, а затем работать с ней так, как будто это единичный объект.
Декоратор (Decorator) — позволяет динамически добавлять объектам новую функциональность, оборачивая их в полезные «обёртки».
Фасад (Facade) — предоставляет простой интерфейс к сложной системе классов, библиотеке или фреймворку.
Легковес (Flyweight) — позволяет вместить бóльшее количество объектов в отведённую оперативную память. Легковес экономит память, разделяя общее состояние объектов между собой, вместо хранения одинаковых данных в каждом объекте.
Заместитель (Proxy) — позволяет подставлять вместо реальных объектов специальные объекты-заменители. Эти объекты перехватывают вызовы к оригинальному объекту, позволяя сделать что-то до или после передачи вызова оригиналу.
Поведенческие паттерны
Цепочка обязанностей (Chain of Responsibility) —позволяет передавать запросы последовательно по цепочке обработчиков. Каждый последующий обработчик решает, может ли он обработать запрос сам и стоит ли передавать запрос дальше по цепи.
Команда (Command) — превращает запросы в объекты, позволяя передавать их как аргументы при вызове методов, ставить запросы в очередь, логировать их, а также поддерживать отмену операций.
Итератор (Iterator) — даёт возможность последовательно обходить элементы составных объектов, не раскрывая их внутреннего представления.
Посредник (Mediator) — позволяет уменьшить связанность множества классов между собой, благодаря перемещению этих связей в один класс-посредник.
Снимок (Memento) — позволяет сохранять и восстанавливать прошлые состояния объектов, не раскрывая подробностей их реализации.
Наблюдатель (Observer) — создаёт механизм подписки, позволяющий одним объектам следить и реагировать на события, происходящие в других объектах.
Состояние (State) — позволяет объектам менять поведение в зависимости от своего состояния. Извне создаётся впечатление, что изменился класс объекта.
Стратегия (Strategy) — определяет семейство схожих алгоритмов и помещает каждый из них в собственный класс, после чего алгоритмы можно взаимозаменять прямо во время исполнения программы.
Шаблонный метод (Template Method) — определяет скелет алгоритма, перекладывая ответственность за некоторые его шаги на подклассы. Паттерн позволяет подклассам переопределять шаги алгоритма, не меняя его общей структуры.
Посетитель (Visitor) — позволяет добавлять в программу новые операции, не изменяя классы объектов, над которыми эти операции могут выполняться.
Структуры данных
Структуры данных в общем можно разделить на линейные и нелинейные
Массивы
Это линейная последовательность значений, у каждого из которых есть свой номер. Одномерные/многомерные, статические(длина неизменна)/динамические(как в JS)
Очереди
То же что и массив, но разница в том, что доступ к этим элементам возможен только по принципу FIFO: First In, First Out. Это значит, что из очереди можно быстро и легко извлечь элемент, который расположен в самом ее начале и находится в ней дольше всего. А вот операций для доступа с конца или из середины может вообще не быть.
Стеки
Структура, обратная очереди. Это последовательность, в которой доступ работает по принципу LIFO: Last In, First Out. Элементы добавляются в конец, а быстро получить и извлечь их можно опять же с конца. То есть чем позже элемент добавили в стек, тем легче до него добраться.
Деки
Двусторонние очереди: они объединяют возможности и очереди, и стека. Такие структуры данных могут работать и по принципу FIFO, и по принципу LIFO. Доступ к элементам возможен с любого конца.
Связанные списки
Это последовательность элементов, каждый из которых хранит данные и ссылку на следующий или предыдущий элемент. Элементы, в отличие от массива, хранятся отдельно друг от друга. Есть односвязные (только следующий), двусвязные (следующий и предидущий) и круговые (замыкаются)
Множества (Set)
Элементы не имеют четкого порядка, зато уникальны по значению
Карты (Map)
Это набор пар из ключей и значений. Ее еще называют ассоциативным массивом или словарем
Хэш-таблицы
Эта структура данных похожа на ассоциативный массив и иногда реализуется через него. Разница в том, что ключ для каждого значения задается автоматически с помощью специальной формулы — хэш-формулы. Эта формула применяется к самому значению — в результате генерируется ключ, основанный на нем.
Графы
Нелинейная структура организации данных, которая состоит из «вершин» и «ребер» между ними. Каждая вершина — это значение, а ребра — пути, которые соединяют между собой вершины. Графы бывают неориентированными, когда ребра не имеют конкретного направления, и ориентированными
Деревья
Деревья можно назвать частным случаем графов. Это тоже структуры из вершин и ребер, но имеющие древовидный формат. Вершины деревьев называются узлами.
1) Бинарные деревья поиска — самый распространенный формат деревьев. У каждого узла может быть не более двух потомков. Если значение узла-потомка меньше предка, он располагается слева. Если равно или больше — справа.
2) Префиксные деревья, они же нагруженные деревья или боры — это деревья, которые хранят данные «по цепочке».
3) Двоичные кучи — двоичные деревья, заполненные целиком. У каждого узла два потомка. Потомки в зависимости от типа дерева должны быть строго больше предков или меньше либо равны им
Алгоритмы
Алгоритмы поиска:
Линейный поиск (Linear Search):
Сложность: O(n)
Описание: Этот алгоритм перебирает элементы массива по одному, начиная с начала, и сравнивает их с искомым значением до нахождения совпадения или достижения конца массива.
Бинарный поиск (Binary Search):
Сложность: O(log n)
Описание: Этот алгоритм применим только к отсортированным массивам. Он сравнивает искомое значение с элементом в середине массива и, в зависимости от результата сравнения, отсекает половину массива. Процесс повторяется до нахождения элемента или определения его отсутствия.
Алгоритмы сортировки:
Сортировка пузырьком (Bubble Sort):
Сложность: O(n^2)
Описание: Этот алгоритм сравнивает пары соседних элементов и меняет их местами, если они находятся в неправильном порядке. Процесс повторяется до тех пор, пока вся последовательность не станет отсортированной.
Сортировка вставками (Insertion Sort):
Сложность: O(n^2)
Описание: Этот алгоритм поочередно вставляет каждый элемент массива в отсортированную часть массива. На каждом шаге сравнивается текущий элемент с предыдущими элементами в отсортированной части.
Сортировка слиянием (Merge Sort):
Сложность: O(n log n)
Описание: Этот алгоритм разделяет массив на две равные части, сортирует их отдельно, а затем объединяет результаты слиянием. Он эффективен для сортировки больших массивов.
Быстрая сортировка (Quick Sort):
Сложность: В среднем O(n log n), в худшем случае O(n^2)
Описание: Этот алгоритм выбирает опорный элемент из массива, разделяет массив на две подгруппы (меньшие и большие элементы) и рекурсивно сортирует каждую из них. В среднем случае он быстрее большинства других сортировок.
DDD - domain driven design
Domain-Driven Design (DDD) - это подход к созданию программного обеспечения, который ставит в центр моделирование предметной области бизнеса. Основная идея - понимать, как работает бизнес, и отражать это понимание в структуре программы. DDD использует язык бизнеса для создания более понятного и эффективного кода, отражающего реальные потребности и процессы предметной области.
Применяется в проектах, а которых запутанная бизнес логика
Ubiquitos language - учит разработчиков разговаривать на языке бюизнеса