Интерфейсы и наследование абстрактных классов, реализация в расширенных классах - PullRequest
34 голосов
/ 16 июня 2011

В каждом примере, который я видел, расширенные классы реализуют интерфейсы своих родителей. Для справки приведем следующий пример:

interface MyInterface{
    public function foo();
    public function bar();
}

abstract class MyAbstract implements MyInterface{
    public function foo(){ /* stuff */ }
    public function bar(){ /* stuff */ }
}

// what i usually see
class MyClass extends MyAbstract implements MyInterface{}

// what i'm curious about
class MyOtherClass extends MyAbstract{}

Является ли неудача в реализации интерфейса у ребенка, который реализуется родителем, считается плохой практикой или что-то в этом роде? Существуют ли какие-либо технические недостатки для исключения реализации у ребенка?

Ответы [ 5 ]

20 голосов
/ 16 июня 2011

Я бы посчитал, что вы на правильном пути.Нет необходимости объявлять, что вы реализуете интерфейс, когда расширяете класс, который уже implements это.Для меня это просто еще один кусок кода, который нужно поддерживать, если необходимы изменения.Так что да, вы правы!

18 голосов
/ 16 июня 2011

Является ли неудача в реализации интерфейса у ребенка, который реализуется родителем, считается плохой практикой или что-то в этом роде?Есть ли какие-либо технические недостатки в том, что мы не можем реализовать реализацию в дочернем элементе?

Я просто не могу ответить на ваш вопрос лучше, чем этот парень:

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

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

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

Ссылка

Таким образом, эторешать вам, основываясь на том, кто собирается использовать (создавать экземпляры) ваши классы и кто собирается их писать.Если вы являетесь единственным пользователем и автором своих классов, то, может быть, просто может быть, вам не нужны оба.Но, если вы хотите, чтобы все урезали до макета основные биты для автора (ов) класса и пользователя (ов) класса, то вам следует рассмотреть возможность использования как абстрагирования, так и реализации.

1 голос
/ 02 июня 2018

Возможно, немного опоздал к таблице, но я вижу, что вышеупомянутые комментарии не проясняют главное недоразумение, лежащее в основе вопроса ОП.

Итак, основные вопросы:

  • Почемуиспользовать класс Abstract и интерфейс на одной строке?
  • Должны ли оба абстрактных метода и интерфейса объявлять одни и те же методы вообще?

Но перед некоторыми разъяснениями, почему использовать любой из двух выше:

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

    1. объявлений структур данных (необязательно),
    2. базовая реализация методов (и их сигнатуры, необязательно)
    3. просто объявления методов (аналогично использованию интерфейса, необязательно).
  • Интерфейс используется, чтобы предоставить конкретному классу план методов с помощью

    1. просто методов (и т.подписи наследников, необязательно) объявления.

Вот пример для абстрактных и конкретных классов.

abstract class MyAbstractClass {

    public function foo() {
        // Base implementation of the method here.
    }

    public function bar() {
        // Base implementation of the method here.
    }

    // Effectively similar to baz() declaration within some interface:
    public abstract function baz($value);

}

class MyConcreteClass extends MyAbstractClass {

    // foo() and bar() are inherited here from MyAbstractClass.

    // baz() must be implemented or declared abstract again.
    public function baz($value) {
        // implementation.
    }

}

Тогда возникают вопросы:

  1. Зачем нам здесь интерфейс?
  2. Нужен ли нам интерфейс для дублирования объявлений одного и того же метода?

Ответы:

  1. Из-за того, что PHP допускает только одиннаследование для каждого подкласса (вы не можете написать class MyConcreteClass extends MyAbstractClass, MyAnotherClass {}), когда нам нужно расширить функциональность конкретного класса за пределы уже используемого класса Abstract, мы должны объявить эту дополнительную функциональность через один или несколько интерфейсов.

    Вот так:

    class MyConcreteClass 
        extends MyAbstractClass 
        implements MyInterface, MyAnotherInterface {
        // Methods and data implementations go here.
    }
    
  2. В результате ответа 1 интерфейс лучше не дублировать объявления методов абстрактного класса (это в основном бесполезно).Интерфейс (ы) должен деалектировать методы, которые могут помочь улучшить конкретную (или другой класс Abstract, почему бы и нет) функциональность, чтобы предоставить программисту, который будет использовать их с твердым контрактом для каждого объекта, созданного поверх этих классов и интерфейсов.

Наконец, ответ на вопрос OP, использовать ли интерфейс для абстрактного класса или для конкретного класса:

  • использовать для одного или обоих(или по мере необходимости), пока Интерфейс расширяет контракт класса с помощью объявлений новых методов.
0 голосов
/ 05 февраля 2018

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

0 голосов
/ 16 июня 2011

Является ли неудача в реализации интерфейса у ребенка, который реализуется родителем, считается плохой практикой или что-то в этом роде?

Ребенок всегда реализует интерфейс, он не может обойтись этим.

Я понятия не имею, если это плохая практика или что-то в этом роде. Я бы сказал, что это особенность языка.

Существуют ли какие-либо технические недостатки при пропуске реализации в дочернем элементе?

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

Тем не менее, абстрактный класс уже является интерфейсом, так что технически им самим не нужен интерфейс, но вы можете сделать это, чтобы сохранить текучесть в наследстве.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...