Абстрактный базовый класс по сравнению с реальным классом как SuperType

После чтения самой превосходной книги "Возглавляют Первые Шаблоны разработки", я начал обращать в веру своим коллегам преимущества шаблонов и принципов разработки. При расхваливании достоинств моего любимого шаблона - Стратегической модели - меня задали вопрос, который дал мне паузу. Стратегия, конечно, использует наследование и состав, и я был на одной из моих тирад о "программе к интерфейсу (или супертип) не реализация", когда коллега спросил "почему использование абстрактный базовый класс вместо реального класса?".
Я мог только придумать, "хорошо Вы вынуждаете свои подклассы реализовать абстрактные методы и препятствовать тому, чтобы они инстанцировали ABC". Но быть честным вопрос поймал меня от защиты. Это единственные преимущества использования абстрактного базового класса по реальному классу наверху моей иерархии?

12
задан Ravindra babu 9 June 2016 в 19:40
поделиться

7 ответов

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

22
ответ дан 2 December 2019 в 05:03
поделиться

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

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

1
ответ дан 2 December 2019 в 05:03
поделиться

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

Что касается абстрактного базового класса по сравнению с конкретным классом, ответ в Java всегда: «Что лучше работает в этой ситуации?» Если ваши стратегии могут делиться кодом, то пусть они это делают.

Шаблоны проектирования - это не инструкции о том, как что-то делать. Это способы категоризации того, что мы уже сделали.

1
ответ дан 2 December 2019 в 05:03
поделиться

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

public abstract class Animal{

public void digest(){

}

public abstract void sound(){

}
}

public class Dog extends Animal{
public void sound(){
    System.out.println("bark");
}
}

Шаблон Stratergy предлагает дизайнерам использовать поведение композиции в случаях, когда для поведения существуют семейства алогирм.

1
ответ дан 2 December 2019 в 05:03
поделиться

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

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

0
ответ дан 2 December 2019 в 05:03
поделиться

Программа для взаимодействия, а не для реализации имеет мало общего с абстрактными и конкретными классами. Помните шаблон метода шаблон ? Классы, абстрактные или конкретные, являются деталями реализации.

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

Программирование интерфейса - это другое дело - оно определяет , что ваш API делает, а не , как он это делает. И это обозначается интерфейсами.

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

5
ответ дан 2 December 2019 в 05:03
поделиться

Вопрос о том, должен ли базовый класс быть абстрактным или конкретным, зависит, IMHO, в основном от того, будет ли полезен объект базового класса, реализующий только поведение, общее для всех объектов класса. Рассмотрим WaitHandle. Вызов "wait" на нем приведет к блокировке кода до выполнения некоторого условия, но не существует общего способа сообщить объекту WaitHandle, что его условие выполнено. Если бы можно было инстанцировать "WaitHandle", а не только инстанцировать экземпляры производных типов, то такой объект должен был бы либо никогда не ждать, либо ждать вечно. Последнее поведение было бы довольно бесполезным; первое могло бы быть полезным, но может быть достигнуто почти так же хорошо с помощью статически выделенного ManualResetEvent (я думаю, что последний тратит несколько ресурсов, но если он статически выделен, общая потеря ресурсов должна быть тривиальной).

Во многих случаях, я думаю, я бы предпочел использовать ссылки на интерфейс, а не на абстрактный базовый класс, но предоставлять вместе с интерфейсом базовый класс, который обеспечивает "реализацию модели". Таким образом, в любом месте, где можно было бы использовать ссылку на MyThing, можно было бы поставить ссылку на "iMyThing". Вполне возможно, что 99% (или даже 100%) объектов iMyThing на самом деле являются MyThing, но если кому-то когда-нибудь понадобится иметь объект iMyThing, который наследуется от чего-то другого, это можно сделать.

0
ответ дан 2 December 2019 в 05:03
поделиться