ООП. Объектно-ориентированное программирование продвинутого уровня
ООП дает мощные инструменты для разработки, но неправильное понимание может привести к усложнению кода и снижению его производительности. В этой статье мы покажем, как избежать типичных ошибок, связанных с наследованием, переопределением методов, использованием модификаторов доступа и проектированием классов. Также рассмотрим тестовые задачи с hh.ru для закрепления материала.
Вопрос 1
Какое определение наиболее точно отражает понятие инициализации класса в ООП?
- Процесс определения атрибутов и методов класса
- Процесс присвоения начальных значений полям данных класса
- Процесс определения конструкторов и деструкторов класса
- Процесс создания экземпляра класса
- Процесс определения связей между классами
Обоснование:
Инициализация класса в ООП — это процесс, связанный с присвоением начальных значений его полям (атрибутам) для подготовки объекта к использованию. Это чаще всего происходит при вызове конструктора класса, который автоматически инициализирует значения атрибутов.
- Процесс определения атрибутов и методов класса — это процесс проектирования класса, а не его инициализации.
- Процесс присвоения начальных значений полям данных класса — верно, так как это ключевая цель инициализации.
- Процесс определения конструкторов и деструкторов класса — это описание механизма, а не самого процесса инициализации.
- Процесс создания экземпляра класса — это процесс инстанцирования объекта, но не сам процесс инициализации значений.
- Процесс определения связей между классами — это больше относится к архитектурному проектированию.
📌Правильный ответ:
2. Процесс присвоения начальных значений полям данных класса
Вопрос 2
Какое из перечисленных действий нарушает принцип инкапсуляции в ООП?
- Определение всех методов класса как статических
- Непосредственное изменение приватных полей класса извне без использования методов класса
- Использование модификатора доступа public для всех методов класса
- Распределение данных и методов класса по разным модулям или файлам
- Открытие доступа к приватным полям класса через геттеры и сеттеры
Обоснование:
Инкапсуляция — это принцип ООП, который подразумевает скрытие внутренней реализации класса от внешнего мира и управление доступом к его данным через строго определенные методы. Инкапсуляция достигается с помощью модификаторов доступа (private, protected, public), которые ограничивают или разрешают доступ к данным и методам класса.
- Определение всех методов класса как статических — это не нарушает принцип инкапсуляции, но ограничивает возможности ООП, так как статические методы не работают с экземпляром класса.
- Непосредственное изменение приватных полей класса извне без использования методов класса — это прямое нарушение принципа инкапсуляции, так как приватные поля должны быть скрыты и изменяться только через методы (геттеры и сеттеры).
- Использование модификатора доступа public для всех методов класса — это снижает защищенность класса, но не является прямым нарушением принципа инкапсуляции, так как данные остаются защищенными.
- Распределение данных и методов класса по разным модулям или файлам — это вопрос организации кода, а не инкапсуляции.
- Открытие доступа к приватным полям класса через геттеры и сеттеры — это стандартная практика и не нарушает инкапсуляцию, так как доступ контролируется.
📌Правильный ответ:
2. Непосредственное изменение приватных полей класса извне без использования методов класса
Вопрос 3
Какой шаблон проектирования НЕ основан на реализации принципа инкапсуляции ООП?
Обоснование:
Принцип инкапсуляции подразумевает скрытие деталей реализации и управление доступом к объектам через строго определенные интерфейсы. Многие шаблоны проектирования, такие как Фасад, Стратегия и Наблюдатель, активно используют этот принцип, предоставляя упрощенные интерфейсы для взаимодействия или отделяя детали реализации.
- Фасад — активно использует инкапсуляцию, предоставляя клиенту упрощенный интерфейс для работы с подсистемой, скрывая ее внутренние детали.
- Стратегия — основана на инкапсуляции, так как отделяет алгоритм от клиента, предоставляя интерфейс для выбора поведения.
- Команда — использует принцип инкапсуляции, так как команды скрывают детали выполнения действия внутри себя и предоставляют единообразный интерфейс.
- Наблюдатель — реализует инкапсуляцию, так как субъект и наблюдатели взаимодействуют через известные интерфейсы, скрывая внутренние детали друг от друга.
- Информационный эксперт — это принцип, а не конкретный шаблон проектирования. Он предполагает назначение ответственности классу, который наиболее близко связан с нужными данными, но не обязательно связан с инкапсуляцией в прямом виде.
📌Правильный ответ:
5. Информационный эксперт
Вопрос 4
В каком из следующих случаев соблюден принцип открытости/закрытости?
- Класс Triangle содержит жестко заданные значения длин сторон, которые нельзя изменить после создания объекта.
- Класс Rectangle предоставляет только один конструктор, который ограничивает возможность создания прямоугольников с разными характеристиками.
- Класс Shape определяет абстрактный метод calculateArea(), и новые геометрические фигуры могут быть созданы путем наследования от Shape и реализации этого метода.
- Класс Circle имеет жестко заданные методы для вычисления площади и периметра круга, и их нельзя расширить для поддержки других геометрических фигур.
- Класс Polygon содержит методы для работы с многоугольниками, но они не могут быть переопределены для работы с окружностями.
Обоснование:
Принцип открытости/закрытости (Open/Closed Principle, OCP) из SOLID гласит, что классы, модули и функции должны быть открыты для расширения, но закрыты для модификации. Это означает, что поведение системы должно можно было расширить без изменения существующего кода.
- Класс Triangle содержит жестко заданные значения длин сторон... — нарушает принцип, так как класс не может быть расширен без изменения существующего кода.
- Класс Rectangle предоставляет только один конструктор... — нарушает принцип, так как класс ограничивает возможности расширения.
- Класс Shape определяет абстрактный метод calculateArea()... — соответствует принципу, так как новые фигуры могут быть добавлены без изменения существующего класса Shape.
- Класс Circle имеет жестко заданные методы... — нарушает принцип, так как класс нельзя расширить для поддержки других фигур.
- Класс Polygon содержит методы для работы с многоугольниками... — нарушает принцип, так как класс не позволяет переопределение для других типов фигур.
📌Правильный ответ:
3. Класс Shape определяет абстрактный метод calculateArea(), и новые геометрические фигуры могут быть созданы путем наследования от Shape и реализации этого метода.
Вопрос 5
Какой модификатор доступа следует использовать, чтобы обеспечить доступность полей и методов класса из самого класса, из производного класса и из других классов в той же сборке, но не из других сборок?
Обоснование:
Модификаторы доступа управляют областью видимости и доступности членов класса. Для решения задачи подходят следующие варианты:
- Protected Internal: Обеспечивает доступ к полям и методам:Внутри текущей сборки.
В производных классах даже из других сборок. Это НЕ подходит, так как доступ возможен и из других сборок. - Public Internal: В C# такого модификатора нет, поэтому его нельзя рассматривать.
- Public: Обеспечивает доступ отовсюду, что нарушает ограничение "только в пределах сборки".
- Private: Ограничивает доступ только самим классом, что не соответствует требуемой доступности.
- Protected: Ограничивает доступ самим классом и производными классами, но не обеспечивает доступ внутри той же сборки для других классов.
Правильный модификатор — Internal. Этот модификатор:
- Ограничивает доступность полей и методов только текущей сборкой.
- Исключает доступ из других сборок. Но если нужен доступ и производным классам внутри той же сборки, Protected Internal обеспечит это.
Вопрос 6
Если несколько интерфейсов, реализованных абстрактным классом, содержат одинаковые методы, то...
- ... конфликт возникнет в некоторых языках программирования, где запрещено неявное множественное наследование
- ... это вызовет конфликт: в абстрактном классе возникнет ошибка компиляции из-за конфликта имен методов
- ... это не вызывает конфликта: абстрактный класс автоматически наследует реализацию метода из первого интерфейса и игнорирует остальные
- ... это не вызывает конфликта: класс предоставляет единственную реализацию этого метода, и она будет удовлетворять обоим интерфейсам
- ... это не вызывает конфликта: компилятор создаст адаптеры для методов, чтобы избежать конфликта
Обоснование:
Когда несколько интерфейсов содержат методы с одинаковыми именами и сигнатурами, реализация метода в классе или абстрактном классе, который реализует эти интерфейсы, обычно удовлетворяет требованиям всех интерфейсов. Компилятор не вызывает ошибки, если методы идентичны по сигнатурам.
- Конфликт возникнет в некоторых языках программирования, где запрещено неявное множественное наследование — неверно. Множественное наследование интерфейсов разрешено, так как они не содержат реализаций.
- Это вызовет конфликт: в абстрактном классе возникнет ошибка компиляции из-за конфликта имен методов — неверно, если сигнатуры методов идентичны, ошибки не будет.
- Это не вызывает конфликта: абстрактный класс автоматически наследует реализацию метода из первого интерфейса и игнорирует остальные — неверно. Интерфейсы не содержат реализации, поэтому нечего наследовать.
- Это не вызывает конфликта: класс предоставляет единственную реализацию этого метода, и она будет удовлетворять обоим интерфейсам — верно. Если методы идентичны, достаточно одной реализации в классе.
- Это не вызывает конфликта: компилятор создаст адаптеры для методов, чтобы избежать конфликта — неверно, компилятор не создает адаптеры для таких случаев.
📌Правильный ответ:
4. ... это не вызывает конфликта: класс предоставляет единственную реализацию этого метода, и она будет удовлетворять обоим интерфейсам.
Вопрос 7
В какой из ситуаций ниже корректно применить статические методы класса?
- Когда нужно обеспечить доступ к методам без создания объекта
- Когда необходимо создать экземпляр класса
- Когда операции зависят от изменяющихся во времени данных, например, случайных чисел
- Когда операции требуют доступа к внутренним данным объекта
- Когда методы класса должны быть частью наследуемого интерфейса
Обоснование:
Статические методы в объектно-ориентированном программировании (ООП) принадлежат классу, а не его экземпляру. Они не могут обращаться к нестатическим полям или методам, так как их выполнение не связано с конкретным объектом. Эти методы чаще всего используются для выполнения операций, которые не требуют состояния объекта.
- Когда нужно обеспечить доступ к методам без создания объекта — это идеальный случай для использования статических методов, так как они не зависят от экземпляра класса.
- Когда необходимо создать экземпляр класса — неверно, так как создание экземпляра требует конструктора, а не статического метода.
- Когда операции зависят от изменяющихся во времени данных, например, случайных чисел — не связано напрямую со статическими методами, хотя такие операции могут быть реализованы статически.
- Когда операции требуют доступа к внутренним данным объекта — неверно, статические методы не могут обращаться к нестатическим данным.
- Когда методы класса должны быть частью наследуемого интерфейса — неверно, интерфейсы не поддерживают статические методы для наследования в классах.
Вопрос 8
- В Java дочерний класс может переопределить конструктор без параметров родительского класса.
- В Python дочерний класс всегда имеет доступ ко всем приватным членам родительского класса.
- В C++ наследование позволяет дочернему классу переопределить методы родительского класса.
- В Java в дочернем классе создается и хранится копия родительского класса.
- Для каждого дочернего класса в C# может существовать только один родительский класс.
- В Java дочерний класс может переопределить конструктор без параметров родительского класса — неверно. В Java конструкторы не наследуются и не могут быть переопределены. Однако можно вызывать конструктор родительского класса через super.
- В Python дочерний класс всегда имеет доступ ко всем приватным членам родительского класса — неверно. В Python приватные члены обозначаются как _ClassName__attribute (name mangling), и прямой доступ невозможен без обходных путей.
- В C++ наследование позволяет дочернему классу переопределить методы родительского класса — верно. В C++ поддерживается полиморфизм, и методы могут быть переопределены, если они объявлены как virtual в родительском классе.
- В Java в дочернем классе создается и хранится копия родительского класса — неверно. Дочерний класс наследует свойства и методы родителя, но копия класса не создается.
- Для каждого дочернего класса в C# может существовать только один родительский класс — верно. C# поддерживает только одиночное наследование классов, но допускает реализацию нескольких интерфейсов.
📌Правильный ответ:
5. Для каждого дочернего класса в C# может существовать только один родительский класс.
Вопрос 9
Динамический полиморфизм достигается в основном с помощью...
Обоснование:
Динамический полиморфизм позволяет вызывать методы, реализация которых определяется во время выполнения программы. Это достигается путем использования виртуальных методов в языках, таких как C++, C#, и Java. Виртуальные методы обеспечивают возможность переопределения методов базового класса в производных классах и их вызова через базовый тип.
- Шаблоны — относятся к параметрическому полиморфизму, а не динамическому.
- Множественное наследование — это концепция, связанная с архитектурой классов, а не с полиморфизмом.
- Виртуальные методы — правильный ответ, так как именно они используются для реализации динамического полиморфизма.
- Абстрактные классы — сами по себе не обеспечивают динамический полиморфизм, хотя часто используются в сочетании с виртуальными методами.
- Наследование — это базовая концепция ООП, но динамический полиморфизм требует наличия виртуальных методов.
📌Правильный ответ:
3. Виртуальных методов
Вопрос 10
Выберите НЕПОДХОДЯЩИЙ вариант продолжения тезиса:
"Снижения сильной связанности классов в иерархии наследования можно достигнуть с помощью..."
- Применения принципов композиции вместо наследования
- Применения принципа инверсии управления
- Использования статических классов
- Использования модификаторов доступа
- Использования интерфейсного наследования
Обоснование:
Связанность (Coupling) — это степень зависимости одного класса от другого. Сильная связанность усложняет модификацию и поддержку кода. Для снижения связности используются такие подходы, как композиция, интерфейсы и модификация принципов проектирования (например, инверсия управления).
- Применения принципов композиции вместо наследования — правильный подход, поскольку композиция позволяет уменьшить связанность, заменяя жесткие связи гибкими.
- Применения принципа инверсии управления — это уменьшает связанность, так как классы начинают зависеть от абстракций, а не от конкретных реализаций.
- Использования статических классов — неподходящий вариант. Статические классы усиливают связанность, так как их методы и данные жестко связаны с самим классом, а не с объектами, что нарушает гибкость.
- Использования модификаторов доступа — может помочь ограничить доступ к внутренним элементам, снижая связанность.
- Использования интерфейсного наследования — это помогает уменьшить связанность, предоставляя абстрактный уровень взаимодействия между классами.
📌Правильный ответ:
3. Использования статических классов
Вопрос 11
Выберите верное суждение о сериализации с наследованием.
- Сериализацию с наследованием нельзя использовать, когда один дочерний класс содержит ссылку на объект другого дочернего класса.
- При сериализации с наследованием объекты могут включать в себя методы, унаследованные от дилера.
- Под сериализацией с наследованием понимается преобразование методов в поток байтов для сохранения информации.
- В процессе сериализации с наследованием может быть использован механизм виртуальных функций.
- Виртуальные функции исключают возможность для объектов-наследников переопределить методы базового класса.
- Сериализацию с наследованием нельзя использовать, когда один дочерний класс содержит ссылку на объект другого дочернего класса — неверно. Сериализация с наследованием возможна, но требует дополнительных механизмов, таких как обработка сложных ссылок (например, граф объектов).
- При сериализации с наследованием объекты могут включать в себя методы, унаследованные от дилера — неверно. Сериализация сохраняет данные (состояние объекта), но не методы.
- Под сериализацией с наследованием понимается преобразование методов в поток байтов для сохранения информации — неверно. Сериализация касается данных, а не методов.
- В процессе сериализации с наследованием может быть использован механизм виртуальных функций — верно. Виртуальные функции могут использоваться для правильной десериализации объектов-наследников, поскольку они обеспечивают динамическое связывание.
- Виртуальные функции исключают возможность для объектов-наследников переопределить методы базового класса — неверно. Виртуальные функции специально предназначены для переопределения методов в наследниках.
📌Правильный ответ:
4. В процессе сериализации с наследованием может быть использован механизм виртуальных функций.
Вопрос 12
Какое из утверждений об особенностях объектно-ориентированных языков программирования верно?
- Множественное наследование может быть реализовано в Python и C++
- В Python используются такие типы модификаторов доступа, как private, protected, internal и protected internal
- ООП может быть реализовано в Fortran и Assembler
- Java, Python и C++ используют интерфейсы для реализации полиморфизма
- Ключевое слово «virtual» для реализации виртуальных функций используется в C#, TypeScript и JavaScript
- Множественное наследование может быть реализовано в Python и C++ — верно. Python поддерживает множественное наследование, а C++ позволяет реализовать его через виртуальное наследование.
- В Python используются такие типы модификаторов доступа, как private, protected, internal и protected internal — неверно. В Python используются только public, _protected и __private, модификаторов вроде internal или protected internal в Python нет.
- ООП может быть реализовано в Fortran и Assembler — неверно. Эти языки не поддерживают объектно-ориентированное программирование в классическом виде.
- Java, Python и C++ используют интерфейсы для реализации полиморфизма — верно частично. Java активно использует интерфейсы, в C++ применяются абстрактные классы, а Python может обходиться без явных интерфейсов.
- Ключевое слово «virtual» для реализации виртуальных функций используется в C#, TypeScript и JavaScript — неверно. В C# используется virtual, но в TypeScript и JavaScript ключевого слова virtual нет.
Вопрос 13
Вы создаете игрового персонажа для компьютерной игры с использованием ООП. Какие из перечисленных сущностей будут относиться к классу, объекту, атрибутам и методам?
- Класс — эльф, объект — маг, атрибуты — запас здоровья (HP), запас магии (мана), методы — заклинания, которые использует маг
- Класс — эльф, объекты — заклинания, которые использует маг, атрибут — маг, методы — запас здоровья (HP), запас магии (мана)
- Класс — маг, объекты — запас здоровья, запас магии (мана), атрибут — эльф, методы — скорость бега, скорость восстановления здоровья мага
- Класс — маг, объекты — запас здоровья (HP), запас магии (мана), атрибут — эльф, методы — заклинания, которые использует маг
- Класс — маг, объекты — запас здоровья, запас магии (мана), атрибуты — заклинания, которые использует маг, методы — эльф
Обоснование:
В объектно-ориентированном программировании (ООП):
- Класс — это шаблон или тип, определяющий свойства и методы. В данном случае "маг" является классом, поскольку это общий тип персонажа.
- Объект — это экземпляр класса. Например, конкретный персонаж с индивидуальными значениями атрибутов (запас здоровья, мана).
- Атрибуты — это свойства объекта (например, здоровье и мана).
- Методы — это функции или действия, которые может выполнять объект (например, использование заклинаний).
- Неверно, так как классом должен быть "маг", а не "эльф".
- Неверно, так как заклинания не могут быть объектами — они больше подходят для методов.
- Неверно, так как "скорость бега" и "скорость восстановления здоровья" не подходят в качестве методов, относящихся к магу.
- Верно, так как:
- Класс — "маг" (тип персонажа).
- Объекты — запас здоровья (HP) и запас магии (мана), которые являются конкретными значениями экземпляра.
- Атрибут — "эльф" (указывающий на вид персонажа, но не класс).
- Методы — заклинания, которые использует маг.
📌Правильный ответ:
4. Класс — маг, объекты — запас здоровья (HP), запас магии (мана), атрибут — эльф, методы — заклинания, которые использует маг.
Вопрос 14
Выберите верное суждение о компонентно-ориентированном программировании.
- Компонентно-ориентированное программирование направлено прежде всего на повышение надёжности закрытых статических систем.
- Компонентно-ориентированное программирование является одним из видов класс-ориентированного.
- Особенностью компонентно-ориентированного программирования является создание прототипов объектов, которые могут быть клонированы и изменены.
- Сходством агентно- и компонентно-ориентированного программирования является создание агентов, которые могут взаимодействовать друг с другом и с окружающей средой.
- Основная идея концепции — создание программных компонентов, которые могут быть использованы в разных приложениях.
Обоснование: Компонентно-ориентированное программирование (КОП) фокусируется на создании повторно используемых компонентов. Компоненты представляют собой модули с определённым интерфейсом и внутренней реализацией, которые могут быть использованы в различных системах и средах.
- Компонентно-ориентированное программирование направлено прежде всего на повышение надёжности закрытых статических систем — неверно. КОП направлено на создание модульности и повторное использование компонентов, а не только на надёжность статических систем.
- Компонентно-ориентированное программирование является одним из видов класс-ориентированного — неверно. КОП не является подвидом класс-ориентированного программирования, это отдельная парадигма.
- Особенностью компонентно-ориентированного программирования является создание прототипов объектов, которые могут быть клонированы и изменены — неверно. Это ближе к прототипно-ориентированному программированию.
- Сходством агентно- и компонентно-ориентированного программирования является создание агентов, которые могут взаимодействовать друг с другом и с окружающей средой — частично верно, но это не является ключевой особенностью КОП.
- Основная идея концепции — создание программных компонентов, которые могут быть использованы в разных приложениях — верно. Это главное преимущество компонентно-ориентированного подхода.
📌Правильный ответ:
5. Основная идея концепции — создание программных компонентов, которые могут быть использованы в разных приложениях.
Вопрос 15
Выберите верное суждение об объектно-ориентированных базах данных.
- Для работы с объектно-ориентированными базами данных можно использовать Java, Python и Ruby.
- Реляционным базам данных характерен более гибкий и масштабируемый подход к хранению данных, чем объектно-ориентированным.
- Под объектом в объектно-ориентированной базе данных понимается строка в таблице базы данных.
- Недостатком объектно-ориентированных баз данных является то, что в них возможны только два типа связей: один к одному и один к многим.
- В объектно-ориентированной базе данных можно использовать только одиночное наследование.
Обоснование:
- Для работы с объектно-ориентированными базами данных можно использовать Java, Python и Ruby — это неверное утверждение. Эти языки можно использовать для работы с объектно-ориентированными базами данных, но само утверждение не указывает на особенности баз данных, а лишь перечисляет языки программирования.
- Реляционным базам данных характерен более гибкий и масштабируемый подход к хранению данных, чем объектно-ориентированным — верное утверждение. Реляционные базы данных имеют более стандартную модель хранения, что делает их масштабируемыми и гибкими для большинства задач. Объектно-ориентированные базы данных более специфичны и часто применяются в узких областях.
- Под объектом в объектно-ориентированной базе данных понимается строка в таблице базы данных — это неверно, так как объект в объектно-ориентированной базе данных представляет собой экземпляр класса, а не строку таблицы.
- Недостатком объектно-ориентированных баз данных является то, что в них возможны только два типа связей: один к одному и один к многим — это неверно. Объектно-ориентированные базы данных поддерживают сложные связи, включая ассоциации и композиции.
- В объектно-ориентированной базе данных можно использовать только одиночное наследование — это неверное утверждение, так как многие объектно-ориентированные базы данных поддерживают множественное наследование.
2. Реляционным базам данных характерен более гибкий и масштабируемый подход к хранению данных, чем объектно-ориентированным.