Я выберу Java в качестве примера, большинство людей это знают, хотя все остальные языки OO также работают.
Java, как и многие другие языки, имеет наследование интерфейса и наследование реализации. Например. класс Java может наследовать от другого, и каждый метод, который имеет реализацию там (при условии, что родитель не является абстрактным) также наследуется. Это означает, что интерфейс наследуется и реализуется для этого метода. Я могу перезаписать его, но мне не нужно. Если я не перезаписал его, я унаследовал реализацию.
Однако мой класс также может "наследовать" (а не на языке Java) только интерфейс без реализации. На самом деле интерфейсы на самом деле названы таким образом в Java, они обеспечивают наследование интерфейса, но не наследуют какую-либо реализацию, поскольку все методы интерфейса не имеют реализации.
Теперь появилась статья в которой лучше наследовать интерфейсы, чем реализации, вы можете прочитать ее (по крайней мере, в первой половине на первой странице), это довольно интересно. Это позволяет избежать проблем, таких как проблема хрупкого базового класса. Пока это имеет смысл и многие другие вещи, сказанные в статье, имеют для меня большой смысл.
Что меня беспокоит, это наследование реализации означает повторное использование кода, одно из важнейших свойств языков OO. Теперь, если у Java не было классов (например, Джеймс Гослинг, крестный отец Java пожелал в соответствии с этой статьей), он решает все проблемы наследования реализации, но как бы вы могли сделать повторное использование кода тогда?
например. если у меня есть класс Car и Car, у вас есть метод move(), который заставляет автомобиль двигаться. Теперь я могу подклассифицировать Car для разных типов автомобилей, это все автомобили, но все это специализированные версии автомобилей. Некоторые могут двигаться по-другому, они должны перезаписать move() в любом случае, но большинство из них просто сохранит унаследованный ход, поскольку они перемещаются одинаково, как абстрактный родительский автомобиль. Предположим на секунду, что в Java есть только интерфейсы, только интерфейсы могут наследовать друг от друга, класс может реализовывать интерфейсы, но все классы всегда являются окончательными, поэтому ни один класс не может наследовать ни от какого другого класса.
Как бы вы избежали этого, когда у вас есть классы интерфейса Car и сотни автомобилей, вам нужно реализовать одинаковый метод move() для каждого из них? Какие понятия для повторного использования кода, кроме наследования реализации, существуют в мире ОО?
В некоторых языках есть Mixins. Является ли Mixins ответом на мой вопрос? Я читал о них, но я не могу представить, как Mixins будет работать в Java-мире, и если они действительно могут решить проблему здесь.
Другая идея заключалась в том, что существует класс, который реализует интерфейс Car, позволяет называть его AbstractCar и реализует метод move(). Теперь другие автомобили реализуют интерфейс Car, а внутри они создают экземпляр AbstractCar, и они реализуют свой собственный метод move(), вызывая move() на своем внутреннем абстрактном Car. Но разве это не будет напрасно тратить ресурсы (метод, вызывающий только другой метод - хорошо, JIT может встроить код, но все же) и используя дополнительную память для хранения внутренних объектов, вам даже не понадобится с наследованием реализации? (ведь каждому объекту требуется больше памяти, чем просто сумма инкапсулированных данных). И не сложно ли программисту писать фиктивные методы, например
public void move() {
abstractCarObject.move();
}
?
Любой может себе представить, как избежать наследования реализации и все еще иметь возможность повторно использовать код в простой форме?