Что (не) объявлять при реализации интерфейса с абстрактным классом?

StackOverflow https://stackoverflow.com/questions/352474

Вопрос

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

Interface A {
    void doX();
}

abstract Class B implements A {
    protected void commonY() {
        // ...
    }

    @Override
    public abstract void doX();
}

Class C extends B {
    @Override
    public void doX() {
        // ...
    }
}

Class D extends B {
    @Override
    public void doX() {
        // ...
    }
}

Мой код работает как положено, но у меня есть несколько вопросов:

  • Должен ли я объявить абстрактный метод doX() в классе B?Почему нет)?

  • Должен ли я также явно объявить «инструменты A» в классах C и D?Почему нет)?

Это было полезно?

Решение

Я думаю, что лучше было бы сделать это следующим образом:

Interface A {
        void doX();
}

abstract Class B {
        protected void commonY() {
                // ...
        }
}

Class C extends B implements A{

        public void doX() {
                // ...
        }
}

Class D extends B implements A{

        public void doX() {
                // ...
        }
}

Не следует смешивать интерфейс (сигнатуру методов) с реализацией.

Другие советы

  • Должен ли я объявить абстрактный метод doX() в классе B?Почему нет)?

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

  • Должен ли я также явно объявить «инструменты A» в классах C и D?Почему нет)?

Нет, еще раз: поскольку ваш суперкласс (абстрактный базовый класс) реализует этот интерфейс, ваши конкретные подклассы будут гарантированно реализовывать этот интерфейс.

Я просто подкину другой вариант.

Превратите абстрактный класс B в класс AUtil, который не реализует A.Для работы сигнатур метода может потребоваться дополнительный аргумент типа A.

C и D реализуют A и внутри себя создают экземпляр AUtil.Это позволяет C и D расширять другие классы.

Я согласен с ДжиБи:рассмотрите возможность реализации своих вспомогательных методов где-нибудь кроме абстрактного базового класса.

Если ваш вспомогательный метод commonY() существует только в абстрактном базовом классе B, все классы, реализующие интерфейс A, должны будут также расширить базовый класс B, чтобы воспользоваться преимуществами этой реализации commonY().Но вы не всегда можете быть вынуждены расширить класс B.

А что, если в будущем вы захотите изменить реализацию commonY()?Затем вы повлияете на множество реализаций интерфейса A.Но если вы не контролируете все эти реализации интерфейса А, вы можете повлиять на их функциональность (плохим образом), даже не желая этого.

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

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

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

я бы не заявлял doX() в B и не добавлять"implements A" на C и D потому что ты должен не повторяйся.

Аннотация doX() в B ничего не добавляет, как уже указано в "implements A".То же самое относится и к добавлению "implements A" к C и D.

Единственным возможным использованием этих пунктов может быть документация:Если вы хотите сделать это очень явно, C (или D) это A, то вы можете добавить implements, но вы должны знать, что для компилятора это действительно не имеет значения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top