нашем любимом Юнити. Предположим, есть фигуры, которые реализуют интерфейс IMovable, в котором сопрограмма MovingTo(Vector2 point). Так вот, реализуя этот метод, не ломается ли принцип ООП - инкапсуляция из-за публичности сопрограммы?
1) это не сопрограмма, а метод 2) таким образом реализуется абстрагирование, инкапсуляция здесь не у дел
Интерфайс тебе гарантирует наличие метода, а реализация будет инкапсулирована внутри классов, реализующих интерфейс. В этом и заключается инкапсуляция, иначе у тебя вместо myObject.MoveTo() было бы что-то вроде if (myObject is Type1) { /// двигаем объект типа Type1 } else if (myObject is Type2) { // двигает по-другому } ...
Разве любой другой желающий класс, имеющий доступ к экземпляру с интерфейсом, не может сказать, чтобы он начал движение к определенной точке?
1) В первом случае я реализую IEnumerator. public interface IMovable { IEnumerator MoveToPoint(Vector2 point); }
А второй случай я уже написал Константину
Могут, интерфейс для этого и нужен чтобы любой внешний класс мог вызвать метод. Если ты хочешь сделать его скрытым от внешних классов, тогда сделай например базовый класс с реализацией метода и пометь protected, если нужно переопределять в наследниках - protected virtual
Лучше тогда рассказать о полной картине: абстрактный класс Figure, у него есть 3 дочки, а именно Drag, Drop, Reducing. Только первый и третий могут передвигаться. Так как уже реализовано наследование от Figure, то остаётся вариант использования интерфейсов. Поэтому логично, что реализуя в них IMovable, метод передвижения будет открытым для других классов с экземпляром фигуры. Но мне нужно, чтобы при срабатывании ивента в фигуре происходило движение. То есть только сама фигура может вызывать данный метод и никто иначе
А чем это нарушает инкапсуляцию?
Делаешь в Fugure protected virtual MoveTo() { // тут реализация } а в наследнике который не должен двигаться делаешь protected override MoveTo() { // тут ничего не происходит } тогда реализация метода MoveTo будет вызвана в соответстии с фактическим типом обекта. Интерфейс тут тебе не нужен т.к. набор методов базового класса это уже фактически "интерфейс" для наследников - им все эти методы будут видны (только если они не private)
Вот как раз тут и выходит сама архитектура кода, которая при увеличении будет некорректна и просто неправильная. Добавлю ещё 10 классов, и 5 из них не будут передвигаться. Значит для каждого отдельно обнулять метод передвижения? Как только что сказал Phantom, это разрешение SOLID
Если есть такие глобальные подмножества наследников, можно сделать FigureMovable : Figure { protected override MoveTo() { // двигаем } и FigureNotMovable : Figure { protected override MoveTo() { // не двигаем } а от них уже все остальные наследуются
Зачем FigureNotMovable с пустым методом?
Затем что в Figure должен существовать MoveTo с который будет какой-то код в базовом классе работать
Не должен. Выше было более подробное описание задачи.
> Но мне нужно, чтобы при срабатывании ивента в фигуре происходило движение. То есть только сама фигура может вызывать данный метод и никто иначе вот это можно трактовать: - либо как "каждый класс сам подписывается на событие и реализует движение" - тут подойдёт private у каждого класса с индивидуальным алгоритмом движения, - либо как "базовый класс Figure должен подписаться на событие и вызывать MoveTo" - тут не обойтись без наличия MoveTo в базовом классе Figure, а значит придёся его переопределить пустым методом
Все верно, но есть ещё одна проблема в abstract Figure имеетсч метод abstract OnPointerDown от интерфейса IPointerDownHandler. Если подбронее, основная задача Figure - быть выбранным для дальнейших действий. При добавлении MovingFigure придется реализовать OnPointerDown, но по-хорошему нужно чтобы каждая конкретная дочка реализовывала метод OnPointerDown по-своему
Нет и нет. Выше я давал ответ.
Не придется. MovingFigure тоже может быть абстрактным.
Да, все теперь отлично. Спасибо за советы
Обсуждают сегодня