У меня есть класс с некоторыми функциями по умолчанию / общий доступ. Я использую abstract class
для этого:
public interface ITypeNameMapper
{
string Map(TypeDefinition typeDefinition);
}
public abstract class TypeNameMapper : ITypeNameMapper
{
public virtual string Map(TypeDefinition typeDefinition)
{
if (typeDefinition is ClassDefinition classDefinition)
{
return Map(classDefinition);
}
...
throw new ArgumentOutOfRangeException(nameof(typeDefinition));
}
protected abstract string Map(ClassDefinition classDefinition);
}
Как видите, у меня тоже есть интерфейс ITypeNameMapper
. Имеет ли смысл определять этот интерфейс, если у меня уже есть абстрактный класс TypeNameMapper
или abstract class
его достаточно?
TypeDefinition
в этом минимальном примере это тоже абстракция.
c#
interfaces
abstract-class
Konrad
источник
источник
Ответы:
Да, потому что C # не допускает множественного наследования, за исключением интерфейсов.
Поэтому, если у меня есть класс, который является одновременно TypeNameMapper и SomethingelseMapper, я могу сделать:
источник
ICanFly
,ICanRun
,ICanSwim
. Вам нужно создать 8 классов существ, по одному на каждую комбинацию черт (YYY, YYN, YNY, ..., NNY, NNN). SRP требует, чтобы вы реализовали каждое поведение (полет, бег, плавание) один раз, а затем повторно применили их на 8 существах. Композиция здесь была бы еще лучше, но, игнорируя композицию на секунду, вы уже должны увидеть необходимость наследования / реализации нескольких отдельных многократно используемых поведений из-за SRP.interface
злоупотребление служебным положением .. избыточные реализации, которые должны быть в основе - которые развиваются независимо! Мой любимый: классы с 1 методомinterface
, каждый из которых реализует свой собственный 1-метод , каждый с одним экземпляром. ... и т. д., и т. д.Интерфейсы и абстрактные классы служат разным целям:
В вашем примере
interface ITypeNameMapper
определяет потребности клиентов иabstract class TypeNameMapper
не добавляет никакой ценности.источник
public
принадлежит клиенту.TypeNameMapper
добавляет много значения, потому что это спасает разработчика от написания некоторой общей логики.interface
или не имеет значения только в том, что C # запрещает полное множественное наследование.Вся концепция интерфейсов была создана для поддержки семейства классов, имеющих общий API.
Это прямо говорит о том, что любое использование интерфейса подразумевает, что существует (или ожидается) несколько реализаций его спецификации.
Инфраструктуры DI запутали здесь воду тем, что многим из них требуется интерфейс, даже если когда-либо будет только одна реализация - для меня это неоправданная нагрузка, поскольку в большинстве случаев это просто более сложный и медленный способ вызова нового, но это это то, что это.
Ответ лежит в самом вопросе. Если у вас есть абстрактный класс, вы готовитесь к созданию более одного производного класса с общим API. Таким образом, использование интерфейса четко обозначено.
источник
find ... -exec perl -pi -e ...
и, возможно, исправление тривиальных ошибок компиляции. Моя точка зрения такова: преимущество отсутствия (в настоящее время) бесполезной вещи намного больше, чем возможная будущая экономия.interface
как код (вы говорите о C # -interface
, а не об абстрактном интерфейсе, как о любом наборе классов / функций / и т. Д.) И завершили его "... но все же запретили полное множественное наследование «. Там нет необходимости,interface
если у вас есть ми.Если мы хотим явно ответить на вопрос, автор говорит: «Имеет ли смысл определять этот интерфейс, если у меня уже есть абстрактный класс TypeNameMapper или достаточно абстрактного класса?»
Ответ - да и нет - да, вы должны создать интерфейс, даже если у вас уже есть абстрактный базовый класс (потому что вы не должны ссылаться на абстрактный базовый класс в любом клиентском коде), и нет, потому что вы не должны были создавать абстрактный базовый класс при отсутствии интерфейса.
То, что вы недостаточно продумали API, который пытаетесь создать, очевидно. Сначала придумайте API, а затем предоставьте частичную реализацию, если хотите. Тот факт, что ваш абстрактный базовый класс выполняет проверку типов в коде, достаточен, чтобы сказать вам, что это неправильная абстракция.
Как и в большинстве вещей в OOD, когда вы находитесь в канавке и хорошо справились со своей объектной моделью, ваш код сообщит вам, что будет дальше. Начните с интерфейса, реализуйте этот интерфейс в нужных вам классах. Если вы обнаружите, что пишете похожий код, извлеките его в абстрактный базовый класс - если важен интерфейс, абстрактный базовый класс - просто помощник, и их может быть несколько.
источник
Это довольно сложно ответить, не зная остальной части приложения.
Предполагая, что вы используете какую-то модель DI и разработали свой код так, чтобы он был максимально расширяемым (чтобы вы могли
TypeNameMapper
легко добавлять новые ), я бы сказал, да.Причины для:
interface
вам не нужно беспокоиться об этом в любых дочерних реализацияхinterface
s. Хотя многие из них работают с абстрактными классами, это не всегда само собой разумеющееся, и я твердо верю, что, по возможности, буду следовать тем же путем, что и остальные 99% пользователей библиотеки.Причины против:
class
/interface
изменяется, есть немного дополнительных накладных расходовУчитывая все это, я бы сказал, что вы должны создать
interface
. Причины этого весьма незначительны, но, хотя можно использовать тезисы при моделировании и IoC, часто с интерфейсами гораздо проще. В конечном счете, я бы не стал критиковать кодекс коллег, если бы они пошли другим путем.источник