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 - учит разработчиков разговаривать на языке бюизнеса
Layered architecture
Layered architecture is a way to divide code into layers, where each layer is responsible for its own task: one accepts requests (controller), another processes logic (service), and the third works with the database (repository). Each layer interacts only with its neighbors, which simplifies development, testing, and support.
Middleware - Responsible for intermediate responses handling
=>
Controller - Checks the request for basic errors. Transfers control further (to the service). Returns the response to the user
=>
Service - Does the main work: checks conditions, applies rules and calculates.
If something from the database is needed, it accesses the repository
=>
Repository - Finds, adds, deletes or updates data in the database.
Inversion of control
Each component of the system should be as isolated from others as possible, not relying on the implementation details of other components to operate
Dependency Injection
Process of providing an external dependency to a software component