Интерфейс следует использовать за абстрактным классом, когда он предлагает что-то, что вам нужно, и что абстрактный класс не может предложить.
Создайте интерфейс без каких-либо конкретных причин, но поскольку вы считаете, что interface==OOP
приносит издержки и доказывает, что вы неправильно поняли, что такое ООП.
В вашем случае, если в прикладном коде вы заметили, что вы можете удалить интерфейс за абстрактным классом и что у вас нет реального эффекта во время компиляции, вы можете задаться вопросом, является ли абстракция интерфейса не просто накладные расходы. Это может быть полезно, поскольку это не полезно. Я буду развивать его.
Использование интерфейса за абстрактным классом открывает возможности реализации: вы можете воспользоваться этим абстрактным классом, связанным с интерфейсом, но вы также можете реализовать интерфейс в конкретных классах без использования абстрактного класса, поэтому, как вы пожелаете. Написание реализации от A до Z может быть подходящим, поскольку оно не подходит в соответствии с нашими потребностями.
Лично я считаю, что интерфейс полезен позади абстрактного класса в двух случаях:
- интерфейс является общим для на всех типах целевых конкретных классов, но абстрактный класс актуален не для всех типы целевых конкретных классов.
Например, при реализации декоратора у вас есть общий интерфейс для представления как украшенных классов, так и классов декораторов.
Классы декораторов имеют разную логику и данные из украшенных классов. Таким образом, наш абстрактный класс для классов декоратора или для украшенных классов может отличаться.
Здесь представлен простой пример для представления Decorator для документа.
Общий интерфейс:
public interface IDocumentInput {
void read();
byte[] getBytes();
String getStringContent();
}
оформленный документ:
public class DocumentInput implements IDocumentInput {
private byte[] bytes;
public DocumentInput(byte[] bytes) {
this.bytes = bytes;
}
public byte[] getBytes() {
return bytes;
}
public void read() {
}
public String getStringContent() {
return new String(getBytes(),StandardCharsets.UTF_8);
}
}
абстрактный класс для декораторов:
public abstract class AbstractDocumentInputDecorator implements IDocumentInput {
protected IDocumentInput document;
protected byte[] bytes;
public AbstractDocumentInputDecorator(IDocumentInput document) {
this.document = document;
}
public byte[] getBytes() {
return bytes;
}
public final String getStringContent() {
return new String(getBytes(),StandardCharsets.UTF_8);
}
}
Бетон декоратор:
public class SecuredDocumentInputDecorator extends AbstractDocumentInputDecorator {
public SecuredDocumentInputDecorator(IDocumentInput document) {
super(document);
}
@Override
public void read() {
document.read();
processUnsecuring();
}
private void processUnsecuring() {
byte[] originalBytes = document.getBytes();
bytes = Base64.decodeBase64(originalBytes);
}
}
В этом случае представляется логичным ввести интерфейс, потому что абстрактного класса недостаточно для представления общего поведения и/или данных всех конкретных классов.
Вы хотите предоставить разработчикам возможность создать собственную реализацию интерфейса с использованием или без использования абстрактного класса. В общем, желательно создать открытый API. Коллекции в классах JDK очень хорошо иллюстрируют это.
Действительно, если вы хотите создать расширяемость интерфейса/контракта, когда вы предоставляете только абстрактный класс, разработчики, которые хотят создать свою реализацию, вынуждены использовать абстрактный класс, даже если они этого не хотят. Что нежелательно.
Вы используете библиотеку, которая заставляет вас использовать интерфейсы. Например, с помощью EJB 3.0 и Spring в этих первых версиях использование абстрактного класса или класса не позволяет использовать некоторые из их функций.
Его действительно хорошая практика для использования таких интерфейсов. Посмотрите информацию о интерфейсах. –
Хорошая практика ???? Для классов API да, в противном случае, просто накладные расходы. – davidxxx
@davidhxxx Это точно я тоже думал .. –