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

При разработке своего программного обеспечения я начал с интерфейсов, так как это кажется «стандартом». Затем я переключился на абстрактные классы, потому что они кажутся более подходящими для решения поставленной задачи. Однако я не уверен, что упустил некоторые соображения при выборе этого дизайна. Помимо проблем, связанных с предметной областью, о которых я думал, какие более общие факторы следует учитывать при выборе между интерфейсами и абстрактными классами?


person deltanovember    schedule 25.01.2010    source источник
comment
Дублируйте много раз: stackoverflow.com/questions/376642/ и другие   -  person cletus    schedule 25.01.2010


Ответы (5)


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

Минус в обоих случаях: больше слизи.

пример псевдокода:

interface IVehicle
{
    void PutCarInGear(Int speed);
}

abstract class Vehicle : IVehicle
{
    public void PutCarInGear(Int speed)
    {
        //base implementation
    }
}

Обратите внимание, что в этом примере кто-то может создать свой собственный класс, реализующий IVehicle, а затем передать его всему, что принимает IVehicle. Этот объект НЕ должен быть дочерним элементом абстрактного класса Vehicle. Поэтому, если вы ожидаете, что в методе PutCarInGear() произойдет что-то конкретное, вполне вероятно, что этот новый класс НЕ оправдает это ожидание. Однако до тех пор, пока не имеет значения, что делают реализации IVehicle, наиболее гибкой абстракцией является наличие как абстрактного базового класса, так и интерфейса.

person Kevin Won    schedule 25.01.2010

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

person Ignacio Vazquez-Abrams    schedule 25.01.2010

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

person dsimcha    schedule 25.01.2010

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

Скажем, у вас есть три парсера. Один разграничивает данные файла с помощью ",", другой с помощью " ", а третий с помощью "|"

Затем вы можете иметь CommaParser, SpaceParser и PipeParser, все из которых являются подклассами Abstract Parser и переопределяют абстрактный метод, getDelimiter()

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

person Alex Baranosky    schedule 25.01.2010

Сохраните его как абстрактный класс, если это отношение «является» и должно выполнять подмножество/все функции. Сохраняйте его как интерфейс, если это отношение «Должен делать».

person Youness Houdass    schedule 19.09.2016