December 7, 2024

ООП. Объектно-ориентированное программирование продвинутого уровня

ООП дает мощные инструменты для разработки, но неправильное понимание может привести к усложнению кода и снижению его производительности. В этой статье мы покажем, как избежать типичных ошибок, связанных с наследованием, переопределением методов, использованием модификаторов доступа и проектированием классов. Также рассмотрим тестовые задачи с hh.ru для закрепления материала.

Вопрос 1

Какое определение наиболее точно отражает понятие инициализации класса в ООП?

Варианты ответа:

  1. Процесс определения атрибутов и методов класса
  2. Процесс присвоения начальных значений полям данных класса
  3. Процесс определения конструкторов и деструкторов класса
  4. Процесс создания экземпляра класса
  5. Процесс определения связей между классами

Обоснование:
Инициализация класса в ООП — это процесс, связанный с присвоением начальных значений его полям (атрибутам) для подготовки объекта к использованию. Это чаще всего происходит при вызове конструктора класса, который автоматически инициализирует значения атрибутов.

Разберем варианты:

  1. Процесс определения атрибутов и методов класса — это процесс проектирования класса, а не его инициализации.
  2. Процесс присвоения начальных значений полям данных класса — верно, так как это ключевая цель инициализации.
  3. Процесс определения конструкторов и деструкторов класса — это описание механизма, а не самого процесса инициализации.
  4. Процесс создания экземпляра класса — это процесс инстанцирования объекта, но не сам процесс инициализации значений.
  5. Процесс определения связей между классами — это больше относится к архитектурному проектированию.

📌Правильный ответ:
2. Процесс присвоения начальных значений полям данных класса

Вопрос 2

Какое из перечисленных действий нарушает принцип инкапсуляции в ООП?

Варианты ответа:

  1. Определение всех методов класса как статических
  2. Непосредственное изменение приватных полей класса извне без использования методов класса
  3. Использование модификатора доступа public для всех методов класса
  4. Распределение данных и методов класса по разным модулям или файлам
  5. Открытие доступа к приватным полям класса через геттеры и сеттеры

Обоснование:
Инкапсуляция — это принцип ООП, который подразумевает скрытие внутренней реализации класса от внешнего мира и управление доступом к его данным через строго определенные методы. Инкапсуляция достигается с помощью модификаторов доступа (private, protected, public), которые ограничивают или разрешают доступ к данным и методам класса.

Разберем варианты:

  1. Определение всех методов класса как статических — это не нарушает принцип инкапсуляции, но ограничивает возможности ООП, так как статические методы не работают с экземпляром класса.
  2. Непосредственное изменение приватных полей класса извне без использования методов класса — это прямое нарушение принципа инкапсуляции, так как приватные поля должны быть скрыты и изменяться только через методы (геттеры и сеттеры).
  3. Использование модификатора доступа public для всех методов класса — это снижает защищенность класса, но не является прямым нарушением принципа инкапсуляции, так как данные остаются защищенными.
  4. Распределение данных и методов класса по разным модулям или файлам — это вопрос организации кода, а не инкапсуляции.
  5. Открытие доступа к приватным полям класса через геттеры и сеттеры — это стандартная практика и не нарушает инкапсуляцию, так как доступ контролируется.

📌Правильный ответ:
2. Непосредственное изменение приватных полей класса извне без использования методов класса

Вопрос 3

Какой шаблон проектирования НЕ основан на реализации принципа инкапсуляции ООП?

Варианты ответа:

  1. Фасад
  2. Стратегия
  3. Команда
  4. Наблюдатель
  5. Информационный эксперт

Обоснование:
Принцип инкапсуляции подразумевает скрытие деталей реализации и управление доступом к объектам через строго определенные интерфейсы. Многие шаблоны проектирования, такие как Фасад, Стратегия и Наблюдатель, активно используют этот принцип, предоставляя упрощенные интерфейсы для взаимодействия или отделяя детали реализации.

Разберем каждый вариант:

  1. Фасад — активно использует инкапсуляцию, предоставляя клиенту упрощенный интерфейс для работы с подсистемой, скрывая ее внутренние детали.
  2. Стратегия — основана на инкапсуляции, так как отделяет алгоритм от клиента, предоставляя интерфейс для выбора поведения.
  3. Команда — использует принцип инкапсуляции, так как команды скрывают детали выполнения действия внутри себя и предоставляют единообразный интерфейс.
  4. Наблюдатель — реализует инкапсуляцию, так как субъект и наблюдатели взаимодействуют через известные интерфейсы, скрывая внутренние детали друг от друга.
  5. Информационный эксперт — это принцип, а не конкретный шаблон проектирования. Он предполагает назначение ответственности классу, который наиболее близко связан с нужными данными, но не обязательно связан с инкапсуляцией в прямом виде.

📌Правильный ответ:
5. Информационный эксперт

Вопрос 4

В каком из следующих случаев соблюден принцип открытости/закрытости?

Варианты ответа:

  1. Класс Triangle содержит жестко заданные значения длин сторон, которые нельзя изменить после создания объекта.
  2. Класс Rectangle предоставляет только один конструктор, который ограничивает возможность создания прямоугольников с разными характеристиками.
  3. Класс Shape определяет абстрактный метод calculateArea(), и новые геометрические фигуры могут быть созданы путем наследования от Shape и реализации этого метода.
  4. Класс Circle имеет жестко заданные методы для вычисления площади и периметра круга, и их нельзя расширить для поддержки других геометрических фигур.
  5. Класс Polygon содержит методы для работы с многоугольниками, но они не могут быть переопределены для работы с окружностями.

Обоснование:
Принцип открытости/закрытости (Open/Closed Principle, OCP) из SOLID гласит, что классы, модули и функции должны быть открыты для расширения, но закрыты для модификации. Это означает, что поведение системы должно можно было расширить без изменения существующего кода.

Разберем варианты:

  1. Класс Triangle содержит жестко заданные значения длин сторон... — нарушает принцип, так как класс не может быть расширен без изменения существующего кода.
  2. Класс Rectangle предоставляет только один конструктор... — нарушает принцип, так как класс ограничивает возможности расширения.
  3. Класс Shape определяет абстрактный метод calculateArea()... — соответствует принципу, так как новые фигуры могут быть добавлены без изменения существующего класса Shape.
  4. Класс Circle имеет жестко заданные методы... — нарушает принцип, так как класс нельзя расширить для поддержки других фигур.
  5. Класс Polygon содержит методы для работы с многоугольниками... — нарушает принцип, так как класс не позволяет переопределение для других типов фигур.

📌Правильный ответ:
3. Класс Shape определяет абстрактный метод calculateArea(), и новые геометрические фигуры могут быть созданы путем наследования от Shape и реализации этого метода.

Вопрос 5

Какой модификатор доступа следует использовать, чтобы обеспечить доступность полей и методов класса из самого класса, из производного класса и из других классов в той же сборке, но не из других сборок?

Варианты ответа:

  1. Protected Internal
  2. Public Internal
  3. Public
  4. Private
  5. Protected

Обоснование:
Модификаторы доступа управляют областью видимости и доступности членов класса. Для решения задачи подходят следующие варианты:

  • Protected Internal: Обеспечивает доступ к полям и методам:Внутри текущей сборки.
    В производных классах даже из других сборок. Это НЕ подходит, так как доступ возможен и из других сборок.
  • Public Internal: В C# такого модификатора нет, поэтому его нельзя рассматривать.
  • Public: Обеспечивает доступ отовсюду, что нарушает ограничение "только в пределах сборки".
  • Private: Ограничивает доступ только самим классом, что не соответствует требуемой доступности.
  • Protected: Ограничивает доступ самим классом и производными классами, но не обеспечивает доступ внутри той же сборки для других классов.

Правильный модификатор — Internal. Этот модификатор:

  • Ограничивает доступность полей и методов только текущей сборкой.
  • Исключает доступ из других сборок. Но если нужен доступ и производным классам внутри той же сборки, Protected Internal обеспечит это.

📌Правильный ответ:

  1. Protected Internal

Вопрос 6

Если несколько интерфейсов, реализованных абстрактным классом, содержат одинаковые методы, то...

Варианты ответа:

  1. ... конфликт возникнет в некоторых языках программирования, где запрещено неявное множественное наследование
  2. ... это вызовет конфликт: в абстрактном классе возникнет ошибка компиляции из-за конфликта имен методов
  3. ... это не вызывает конфликта: абстрактный класс автоматически наследует реализацию метода из первого интерфейса и игнорирует остальные
  4. ... это не вызывает конфликта: класс предоставляет единственную реализацию этого метода, и она будет удовлетворять обоим интерфейсам
  5. ... это не вызывает конфликта: компилятор создаст адаптеры для методов, чтобы избежать конфликта

Обоснование:
Когда несколько интерфейсов содержат методы с одинаковыми именами и сигнатурами, реализация метода в классе или абстрактном классе, который реализует эти интерфейсы, обычно удовлетворяет требованиям всех интерфейсов. Компилятор не вызывает ошибки, если методы идентичны по сигнатурам.

Разберем варианты:

  1. Конфликт возникнет в некоторых языках программирования, где запрещено неявное множественное наследование — неверно. Множественное наследование интерфейсов разрешено, так как они не содержат реализаций.
  2. Это вызовет конфликт: в абстрактном классе возникнет ошибка компиляции из-за конфликта имен методов — неверно, если сигнатуры методов идентичны, ошибки не будет.
  3. Это не вызывает конфликта: абстрактный класс автоматически наследует реализацию метода из первого интерфейса и игнорирует остальные — неверно. Интерфейсы не содержат реализации, поэтому нечего наследовать.
  4. Это не вызывает конфликта: класс предоставляет единственную реализацию этого метода, и она будет удовлетворять обоим интерфейсам — верно. Если методы идентичны, достаточно одной реализации в классе.
  5. Это не вызывает конфликта: компилятор создаст адаптеры для методов, чтобы избежать конфликта — неверно, компилятор не создает адаптеры для таких случаев.

📌Правильный ответ:
4. ... это не вызывает конфликта: класс предоставляет единственную реализацию этого метода, и она будет удовлетворять обоим интерфейсам.

Вопрос 7

В какой из ситуаций ниже корректно применить статические методы класса?

Варианты ответа:

  1. Когда нужно обеспечить доступ к методам без создания объекта
  2. Когда необходимо создать экземпляр класса
  3. Когда операции зависят от изменяющихся во времени данных, например, случайных чисел
  4. Когда операции требуют доступа к внутренним данным объекта
  5. Когда методы класса должны быть частью наследуемого интерфейса

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

Рассмотрим варианты:

  1. Когда нужно обеспечить доступ к методам без создания объекта — это идеальный случай для использования статических методов, так как они не зависят от экземпляра класса.
  2. Когда необходимо создать экземпляр класса — неверно, так как создание экземпляра требует конструктора, а не статического метода.
  3. Когда операции зависят от изменяющихся во времени данных, например, случайных чисел — не связано напрямую со статическими методами, хотя такие операции могут быть реализованы статически.
  4. Когда операции требуют доступа к внутренним данным объекта — неверно, статические методы не могут обращаться к нестатическим данным.
  5. Когда методы класса должны быть частью наследуемого интерфейса — неверно, интерфейсы не поддерживают статические методы для наследования в классах.

📌Правильный ответ:

  1. Когда нужно обеспечить доступ к методам без создания объекта.

Вопрос 8

Какое утверждение верно?

Варианты ответа:

  1. В Java дочерний класс может переопределить конструктор без параметров родительского класса.
  2. В Python дочерний класс всегда имеет доступ ко всем приватным членам родительского класса.
  3. В C++ наследование позволяет дочернему классу переопределить методы родительского класса.
  4. В Java в дочернем классе создается и хранится копия родительского класса.
  5. Для каждого дочернего класса в C# может существовать только один родительский класс.

Обоснование:

  1. В Java дочерний класс может переопределить конструктор без параметров родительского класса — неверно. В Java конструкторы не наследуются и не могут быть переопределены. Однако можно вызывать конструктор родительского класса через super.
  2. В Python дочерний класс всегда имеет доступ ко всем приватным членам родительского класса — неверно. В Python приватные члены обозначаются как _ClassName__attribute (name mangling), и прямой доступ невозможен без обходных путей.
  3. В C++ наследование позволяет дочернему классу переопределить методы родительского класса — верно. В C++ поддерживается полиморфизм, и методы могут быть переопределены, если они объявлены как virtual в родительском классе.
  4. В Java в дочернем классе создается и хранится копия родительского класса — неверно. Дочерний класс наследует свойства и методы родителя, но копия класса не создается.
  5. Для каждого дочернего класса в C# может существовать только один родительский класс — верно. C# поддерживает только одиночное наследование классов, но допускает реализацию нескольких интерфейсов.

📌Правильный ответ:
5. Для каждого дочернего класса в C# может существовать только один родительский класс.

Вопрос 9

Динамический полиморфизм достигается в основном с помощью...

Варианты ответа:

  1. Шаблонов
  2. Множественного наследования
  3. Виртуальных методов
  4. Абстрактных классов
  5. Наследования

Обоснование:
Динамический полиморфизм позволяет вызывать методы, реализация которых определяется во время выполнения программы. Это достигается путем использования виртуальных методов в языках, таких как C++, C#, и Java. Виртуальные методы обеспечивают возможность переопределения методов базового класса в производных классах и их вызова через базовый тип.

Разберем варианты:

  1. Шаблоны — относятся к параметрическому полиморфизму, а не динамическому.
  2. Множественное наследование — это концепция, связанная с архитектурой классов, а не с полиморфизмом.
  3. Виртуальные методы — правильный ответ, так как именно они используются для реализации динамического полиморфизма.
  4. Абстрактные классы — сами по себе не обеспечивают динамический полиморфизм, хотя часто используются в сочетании с виртуальными методами.
  5. Наследование — это базовая концепция ООП, но динамический полиморфизм требует наличия виртуальных методов.

📌Правильный ответ:
3. Виртуальных методов

Вопрос 10

Выберите НЕПОДХОДЯЩИЙ вариант продолжения тезиса:
"Снижения сильной связанности классов в иерархии наследования можно достигнуть с помощью..."

Варианты ответа:

  1. Применения принципов композиции вместо наследования
  2. Применения принципа инверсии управления
  3. Использования статических классов
  4. Использования модификаторов доступа
  5. Использования интерфейсного наследования

Обоснование:
Связанность (Coupling) — это степень зависимости одного класса от другого. Сильная связанность усложняет модификацию и поддержку кода. Для снижения связности используются такие подходы, как композиция, интерфейсы и модификация принципов проектирования (например, инверсия управления).

Разберем варианты:

  1. Применения принципов композиции вместо наследования — правильный подход, поскольку композиция позволяет уменьшить связанность, заменяя жесткие связи гибкими.
  2. Применения принципа инверсии управления — это уменьшает связанность, так как классы начинают зависеть от абстракций, а не от конкретных реализаций.
  3. Использования статических классовнеподходящий вариант. Статические классы усиливают связанность, так как их методы и данные жестко связаны с самим классом, а не с объектами, что нарушает гибкость.
  4. Использования модификаторов доступа — может помочь ограничить доступ к внутренним элементам, снижая связанность.
  5. Использования интерфейсного наследования — это помогает уменьшить связанность, предоставляя абстрактный уровень взаимодействия между классами.

📌Правильный ответ:
3. Использования статических классов

Вопрос 11

Выберите верное суждение о сериализации с наследованием.

Варианты ответа:

  1. Сериализацию с наследованием нельзя использовать, когда один дочерний класс содержит ссылку на объект другого дочернего класса.
  2. При сериализации с наследованием объекты могут включать в себя методы, унаследованные от дилера.
  3. Под сериализацией с наследованием понимается преобразование методов в поток байтов для сохранения информации.
  4. В процессе сериализации с наследованием может быть использован механизм виртуальных функций.
  5. Виртуальные функции исключают возможность для объектов-наследников переопределить методы базового класса.

Обоснование:

  1. Сериализацию с наследованием нельзя использовать, когда один дочерний класс содержит ссылку на объект другого дочернего класса — неверно. Сериализация с наследованием возможна, но требует дополнительных механизмов, таких как обработка сложных ссылок (например, граф объектов).
  2. При сериализации с наследованием объекты могут включать в себя методы, унаследованные от дилера — неверно. Сериализация сохраняет данные (состояние объекта), но не методы.
  3. Под сериализацией с наследованием понимается преобразование методов в поток байтов для сохранения информации — неверно. Сериализация касается данных, а не методов.
  4. В процессе сериализации с наследованием может быть использован механизм виртуальных функций — верно. Виртуальные функции могут использоваться для правильной десериализации объектов-наследников, поскольку они обеспечивают динамическое связывание.
  5. Виртуальные функции исключают возможность для объектов-наследников переопределить методы базового класса — неверно. Виртуальные функции специально предназначены для переопределения методов в наследниках.

📌Правильный ответ:
4. В процессе сериализации с наследованием может быть использован механизм виртуальных функций.

Вопрос 12

Какое из утверждений об особенностях объектно-ориентированных языков программирования верно?

Варианты ответа:

  1. Множественное наследование может быть реализовано в Python и C++
  2. В Python используются такие типы модификаторов доступа, как private, protected, internal и protected internal
  3. ООП может быть реализовано в Fortran и Assembler
  4. Java, Python и C++ используют интерфейсы для реализации полиморфизма
  5. Ключевое слово «virtual» для реализации виртуальных функций используется в C#, TypeScript и JavaScript

Обоснование:

  1. Множественное наследование может быть реализовано в Python и C++ — верно. Python поддерживает множественное наследование, а C++ позволяет реализовать его через виртуальное наследование.
  2. В Python используются такие типы модификаторов доступа, как private, protected, internal и protected internal — неверно. В Python используются только public, _protected и __private, модификаторов вроде internal или protected internal в Python нет.
  3. ООП может быть реализовано в Fortran и Assembler — неверно. Эти языки не поддерживают объектно-ориентированное программирование в классическом виде.
  4. Java, Python и C++ используют интерфейсы для реализации полиморфизма — верно частично. Java активно использует интерфейсы, в C++ применяются абстрактные классы, а Python может обходиться без явных интерфейсов.
  5. Ключевое слово «virtual» для реализации виртуальных функций используется в C#, TypeScript и JavaScript — неверно. В C# используется virtual, но в TypeScript и JavaScript ключевого слова virtual нет.

📌Правильный ответ:

  1. Множественное наследование может быть реализовано в Python и C++

Вопрос 13

Вы создаете игрового персонажа для компьютерной игры с использованием ООП. Какие из перечисленных сущностей будут относиться к классу, объекту, атрибутам и методам?

Варианты ответа:

  1. Класс — эльф, объект — маг, атрибуты — запас здоровья (HP), запас магии (мана), методы — заклинания, которые использует маг
  2. Класс — эльф, объекты — заклинания, которые использует маг, атрибут — маг, методы — запас здоровья (HP), запас магии (мана)
  3. Класс — маг, объекты — запас здоровья, запас магии (мана), атрибут — эльф, методы — скорость бега, скорость восстановления здоровья мага
  4. Класс — маг, объекты — запас здоровья (HP), запас магии (мана), атрибут — эльф, методы — заклинания, которые использует маг
  5. Класс — маг, объекты — запас здоровья, запас магии (мана), атрибуты — заклинания, которые использует маг, методы — эльф

Обоснование:
В объектно-ориентированном программировании (ООП):

  • Класс — это шаблон или тип, определяющий свойства и методы. В данном случае "маг" является классом, поскольку это общий тип персонажа.
  • Объект — это экземпляр класса. Например, конкретный персонаж с индивидуальными значениями атрибутов (запас здоровья, мана).
  • Атрибуты — это свойства объекта (например, здоровье и мана).
  • Методы — это функции или действия, которые может выполнять объект (например, использование заклинаний).

Разберем варианты:

  1. Неверно, так как классом должен быть "маг", а не "эльф".
  2. Неверно, так как заклинания не могут быть объектами — они больше подходят для методов.
  3. Неверно, так как "скорость бега" и "скорость восстановления здоровья" не подходят в качестве методов, относящихся к магу.
  4. Верно, так как:
  • Класс — "маг" (тип персонажа).
  • Объекты — запас здоровья (HP) и запас магии (мана), которые являются конкретными значениями экземпляра.
  • Атрибут — "эльф" (указывающий на вид персонажа, но не класс).
  • Методы — заклинания, которые использует маг.
  1. Неверно, так как "заклинания" не могут быть атрибутами, а "эльф" не подходит в качестве метода.

📌Правильный ответ:
4. Класс — маг, объекты — запас здоровья (HP), запас магии (мана), атрибут — эльф, методы — заклинания, которые использует маг.

Вопрос 14

Выберите верное суждение о компонентно-ориентированном программировании.

Варианты ответа:

  1. Компонентно-ориентированное программирование направлено прежде всего на повышение надёжности закрытых статических систем.
  2. Компонентно-ориентированное программирование является одним из видов класс-ориентированного.
  3. Особенностью компонентно-ориентированного программирования является создание прототипов объектов, которые могут быть клонированы и изменены.
  4. Сходством агентно- и компонентно-ориентированного программирования является создание агентов, которые могут взаимодействовать друг с другом и с окружающей средой.
  5. Основная идея концепции — создание программных компонентов, которые могут быть использованы в разных приложениях.

Обоснование: Компонентно-ориентированное программирование (КОП) фокусируется на создании повторно используемых компонентов. Компоненты представляют собой модули с определённым интерфейсом и внутренней реализацией, которые могут быть использованы в различных системах и средах.

  1. Компонентно-ориентированное программирование направлено прежде всего на повышение надёжности закрытых статических систем — неверно. КОП направлено на создание модульности и повторное использование компонентов, а не только на надёжность статических систем.
  2. Компонентно-ориентированное программирование является одним из видов класс-ориентированного — неверно. КОП не является подвидом класс-ориентированного программирования, это отдельная парадигма.
  3. Особенностью компонентно-ориентированного программирования является создание прототипов объектов, которые могут быть клонированы и изменены — неверно. Это ближе к прототипно-ориентированному программированию.
  4. Сходством агентно- и компонентно-ориентированного программирования является создание агентов, которые могут взаимодействовать друг с другом и с окружающей средой — частично верно, но это не является ключевой особенностью КОП.
  5. Основная идея концепции — создание программных компонентов, которые могут быть использованы в разных приложениях — верно. Это главное преимущество компонентно-ориентированного подхода.

📌Правильный ответ:
5. Основная идея концепции — создание программных компонентов, которые могут быть использованы в разных приложениях.

Вопрос 15

Выберите верное суждение об объектно-ориентированных базах данных.

Варианты ответа:

  1. Для работы с объектно-ориентированными базами данных можно использовать Java, Python и Ruby.
  2. Реляционным базам данных характерен более гибкий и масштабируемый подход к хранению данных, чем объектно-ориентированным.
  3. Под объектом в объектно-ориентированной базе данных понимается строка в таблице базы данных.
  4. Недостатком объектно-ориентированных баз данных является то, что в них возможны только два типа связей: один к одному и один к многим.
  5. В объектно-ориентированной базе данных можно использовать только одиночное наследование.

Обоснование:

  1. Для работы с объектно-ориентированными базами данных можно использовать Java, Python и Ruby — это неверное утверждение. Эти языки можно использовать для работы с объектно-ориентированными базами данных, но само утверждение не указывает на особенности баз данных, а лишь перечисляет языки программирования.
  2. Реляционным базам данных характерен более гибкий и масштабируемый подход к хранению данных, чем объектно-ориентированным — верное утверждение. Реляционные базы данных имеют более стандартную модель хранения, что делает их масштабируемыми и гибкими для большинства задач. Объектно-ориентированные базы данных более специфичны и часто применяются в узких областях.
  3. Под объектом в объектно-ориентированной базе данных понимается строка в таблице базы данных — это неверно, так как объект в объектно-ориентированной базе данных представляет собой экземпляр класса, а не строку таблицы.
  4. Недостатком объектно-ориентированных баз данных является то, что в них возможны только два типа связей: один к одному и один к многим — это неверно. Объектно-ориентированные базы данных поддерживают сложные связи, включая ассоциации и композиции.
  5. В объектно-ориентированной базе данных можно использовать только одиночное наследование — это неверное утверждение, так как многие объектно-ориентированные базы данных поддерживают множественное наследование.

📌Правильный ответ:

2. Реляционным базам данных характерен более гибкий и масштабируемый подход к хранению данных, чем объектно-ориентированным.

👉🏻Навигация и ссылки по всем материалам в Telegram