Что (не) объявлять при реализации интерфейса с абстрактным классом? - PullRequest
7 голосов
/ 09 декабря 2008

У меня есть интерфейс 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? Почему (нет)?

Ответы [ 6 ]

8 голосов
/ 09 декабря 2008

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

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() {
                // ...
        }
}

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

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

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

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

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

1 голос
/ 10 декабря 2008

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

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

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

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

1 голос
/ 09 декабря 2008

Я просто добавлю другой вариант.

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

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

0 голосов
/ 09 декабря 2008

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

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

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

0 голосов
/ 09 декабря 2008

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

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

...