Абстрактный класс и интерфейс вместе?
У меня есть раздел моего кода, в котором некоторые классы реализуют интерфейс.
Он чувствует себя правильно, но между дочерними классами существует небольшое дублирование, а именно 3 метода.
Итак, это кричит, чтобы использовать абстрактный класс.
Мой вопрос: будут ли какие-либо недостатки в использовании как абстрактного класса, так и интерфейса в следующих ситуациях:
- Абстрактный класс для реализации интерфейса и дочерних классов для расширения абстрактного класса
- Детские классы для расширения абстрактного класса и реализации интерфейса
или
Если абстрактные классы и интерфейсы не будут использоваться вместе вообще?
Ответы
Ответ 1
Совершенно нормально использовать эти два вместе. Рассмотрим, например, AbstractList
(внедрение List
) и AbstractMap
(реализация Map
) в JDK.
Моя реакция на коленный рефлекс заключалась бы в том, чтобы абстрактный класс реализовал интерфейс, а затем из него получили конкретные классы:
abstract class Base implements TheInterface {
/* ...shared methods... */
}
class Concrete1 extends Base { }
class Concrete1 extends Base { }
Но ваш вопрос, поднимающий другую возможность, заставлял меня думать, и я не вижу большого аргумента против этого:
abstract class Base {
/* ...shared methods... */
}
class Concrete1 extends Base implements TheInterface { }
class Concrete1 extends Base implements TheInterface { }
Кроме того, я могу видеть аргумент для этого, в частности, что он устраняет связь между абстрактным классом и интерфейсом. Если у вас есть еще один класс, который нуждается в функциональности Base
, но ему не нужно реализовывать интерфейс, у вас есть возможность сделать это.
Также есть третий вариант: Композиция. У вас не может быть абстрактного класса вообще, но, скорее, несколько конкретных классов, реализующих интерфейс, используют общий вспомогательный класс в своей реализации:
class Helper {
/* ...shared methods... */
}
class Concrete1 implements TheInterface {
/* ...uses instance of Helper */
}
class Concrete1 implements TheInterface {
/* ...uses instance of Helper */
}
Это имеет ту же гибкость в другой форме.
Ответ 2
Я не думаю, что существует такое эмпирическое правило. При проектировании старайтесь следовать принципам SOLID, чтобы выяснить, хорошо ли это или плохо. Эти принципы можно найти в здесь. В этом конкретном случае я бы подумал, что вы должны убедиться, что соблюдаете принцип "открытого закрытия".
Ответ 3
Лично я предпочитаю утверждение, что абстрактный класс является фоном для других классов, поэтому, если у трех других классов есть что-то общее, их общий предок, абстрактный класс, созданный только для этих трех других классов, должен также содержать код из интерфейса, Это сделало бы абстрактный класс "полным" (на его пути), обеспечивающим все эти свойства и методы, которые разделяют три класса.
Однако, в конечном итоге, не имеет значения, будут ли они реализовывать один и тот же интерфейс. Понятие абстрактного класса, дающее все, что является общим, на мой взгляд более ясным образом. Затем легче сравнивать классы, глядя только на то, что отличается.