Подтвердить что ты не робот

Есть ли причины, чтобы иметь абстрактный класс с каждым методом в определенном классе?

Кажется, что абстрактный класс означает, что определение класса не является полным и, следовательно, не может быть инстанцировано.

И я увидел простой Java-код, который имеет абстрактный класс со всеми определенными методами. Тогда мне было интересно, почему они делают это как абстрактный класс вместо реального класса? Они делают это, поэтому мы не можем создать экземпляр из этого абстрактного класса? Или они получают другие преимущества от создания абстрактного класса со всем, что определено?

4b9b3361

Ответ 1

Возможно, что несмотря на то, что все методы имели реализацию по умолчанию, эти реализации не имели смысла в контексте приложения. Методы могут выполнять только внутреннюю бухгалтерскую отчетность, в то время как фактически полезная реализация должна предоставляться производным классом, который выполняет то, что ему нужно, а затем вызывает метод суперкласса.

Однако это всего лишь предположение. Вам нужно будет показать фактический пример, чтобы рассказать, что может быть причиной этого дизайна.

В качестве примера возьмем простой игровой движок. У меня много разных GameObject в моей игре.

  • Некоторые из них видны, поэтому мой базовый класс получает метод draw(). Но могут быть невидимые объекты, такие как триггерные области, которые вообще не отображаются, поэтому я реализую его как нет-op в базовом классе.

  • Некоторые делают что-то, когда сталкиваются с чем-то, поэтому каждый получает метод collide(other). Но некоторые не делают ничего, когда сталкиваются, как чисто визуальный эффект частицы, поэтому я также предоставляю no-op в базовом классе.

  • Некоторые делают что-то в каждой игре, поэтому получают метод update(). Но некоторые объекты, как стена, могут вообще ничего не делать сами по себе. Поэтому я также предоставляю для этого no-op.

Итак, что мне делать, когда у меня есть невидимый объект, ничего не делает сам по себе и не взаимодействует ни с чем? В игре нет причин иметь это. Поэтому я делаю этот базовый класс abstract. Теоретически вы можете это выразить, потому что все методы имеют реализацию, но практически у вас нет причин когда-либо делать это, и когда вы пытаетесь, вы неправильно поняли, как работает мой игровой движок.

Ответ 2

Одним из типичных вариантов использования является создание класса адаптера. Подумайте о интерфейсе обратного вызова, в котором вы можете получать уведомления о 10 различных событиях, но обычно их интересуют только некоторые из них. С классом адаптера вы можете предоставить пустые реализации таким образом, чтобы фактический обратный вызов требовал реализовать те методы, которые представляют интерес, после расширения адаптера. Вывод абстрактного адаптера, вы выражаете тот факт, что нет смысла создавать экземпляр самого адаптера, поскольку он ничего не полезен.

Начиная с Java 8, вы больше не будете использовать такой адаптер, но будете использовать методы по умолчанию для интерфейса.

Ответ 3

Да, есть. Иногда вы знаете, что создаете абстрактный класс - тот, который должен быть получен, чтобы сделать какой-либо фактический смысл, но вы хотите предоставить реализацию по умолчанию всем методам. Это не так много, но это происходит.

UPDATE: У меня просто было такое дело. Я записываю различные пользовательские события. Каждое событие имеет TimeSpan и описание, и все они имеют другие вещи. Я создал базовый класс событий:

public abstract class BaseEvent
{
    public TimeSpan EventTime {get; private set;}
    public string Description {get; protected set;}

    public BaseEvent(TimeSpan time, string desc) ...
}

Конечно, это С#, а не Java, но если бы я написал это на Java, я бы сделал то же самое)

Ответ 4

У вас может быть абстрактный класс, который реализует несколько интерфейсов. Вам не нужно реализовывать эти методы в абстрактном классе, но вам необходимо реализовать их в подклассе вашего абстрактного класса.

например.

public interface MyInterface{
    void hello();
}

public abstract class Clazzy implements MyInterface {
//I need not have the interface method.
}

public class MySubclass extends Clazzy {

    @Override
    public void hello() {
        // I need to be here
    }

}

Ответ 5

Если класс Java объявлен абстрактным, но все его методы объявлены, то они делают это, поэтому он не может быть создан, хотя он может быть подклассом.

"Абстрактные классы не могут быть созданы, но они могут быть подклассифицированы". См. Здесь: https://docs.oracle.com/javase/tutorial/java/IandI/abstract.html

Ответ 6

У вас могут быть некоторые классы, которые не имеют смысла в контексте вашего приложения, но они работают в дизайне. Глупый пример: Абстрактное животное класса, воплощение рождается и умирает. Вы не хотите "животного". Вы хотите Собака. Таким образом, вам не нужно повторять код каждого добавляемого вами класса. Теперь вы можете иметь собаку, кошку или все, что хотите, это было бы веской причиной, так или иначе ее трудно найти.

Ответ 7

Я вижу, что этот вопрос уже отмечен, но я хотел бы предоставить другое альтернативное объяснение.

Еще одна причина такого кода - предоставить базовую реализацию для всех производных классов этого абстрактного класса.

Затем при реализации новых производных классов у вас есть исполняемая реализация, которую затем вы можете переопределить методы для настройки поведения для этого производного экземпляра.

Возьмем случай BaseItemBuilder, который является абстрактным и предоставляет логику доступа к данным на основе общего аргумента, такого как ItemNumber.

(Извините за код С#, но этот вопрос в значительной степени относится к теории программирования, а не к определенному языку)

public abstract class BaseItemBuilder { /*I don't want anyone using this directly but I do want the base specification*/
    public virtual void GetInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetItemInfo(itemNumber);
        //project values on to internal representation of item
    }
    public virtual void GetMoreInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetMoreItemInfo(itemNumber);
        //project values on to internal representation of item
    }
    public virtual void GetEvenMoreInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetEvenMoreItemInfo(itemNumber);
        //project values on to internal representation of item
    }
    public virtual void GetYetMoreInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetYetMoreItemInfo(itemNumber);
        //project values on to internal representation of item
    }
}

Затем вы можете получить NormalItemBuilder, который использует базовую реализацию. Это составляет 80% элементов, которые вы отслеживаете.

public class BaseItemBuilder { 
    /*I use the base implementation!*/
}

Затем вы получаете SpecialType1ItemBuilder, который отправляется нескольким различным службам данных для получения информации об этом конкретном типе элемента, но по-прежнему использует некоторые базовые значения по умолчанию для реализации. Это покрывает следующие 10%.

public class SpecialType1ItemBuilder { /*I don't want anyone using this directly but I do want the base specification*/
    public override void GetInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetType1ItemInfo(itemNumber);
        //project values on to internal representation of item
    }

    public override void GetYetMoreInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetYetMoreType1ItemInfo(itemNumber);
        //project values on to internal representation of item
    }
}

Затем вы получаете "SpecialType2ItemBuilder", который переходит к еще одному набору спорадических dataservices для завершения изображения этого элемента. Этот алгоритм отменяет другой набор методов, отличных от Type2ItemBuilder. Это покрывает ваши последние 10%.

public class SpecialType2ItemBuilder { /*I don't want anyone using this directly but I do want the base specification*/
    public override void GetInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetType2ItemInfo(itemNumber);
        //project values on to internal representation of item
    }
    public override void GetMoreInfoAboutItem(int itemNumber){ 
        var infoModel = _infoDataService.GetMoreType2ItemInfo(itemNumber);
        //project values on to internal representation of item
    }
}