Хотя это общий вопрос, он также специфичен для проблемы, с которой я сейчас сталкиваюсь. В настоящее время у меня есть интерфейс, указанный в моем решении под названием
public interface IContextProvider
{
IDataContext { get; set; }
IAreaContext { get; set; }
}
Этот интерфейс часто используется во всей программе, и поэтому у меня есть легкий доступ к нужным объектам. Однако на довольно низком уровне части моей программы мне нужен доступ к другому классу, который будет использовать IAreaContext и выполнять над ним некоторые операции. Поэтому я создал еще один фабричный интерфейс для этого создания, который называется:
public interface IEventContextFactory
{
IEventContext CreateEventContext(int eventId);
}
У меня есть класс, который реализует IContextProvider и вводится с помощью NinJect. У меня проблема в том, что область, где мне нужно использовать этот IEventContextFactory, имеет доступ только к IContextProvider и сама использует другой класс, который будет нуждаться в этом новом интерфейсе. Я не хочу создавать экземпляр этой реализации IEventContextFactory на низком уровне и предпочел бы работать с интерфейсом IEventContextFactory повсюду. Однако я также не хочу вводить другой параметр через конструкторы, просто чтобы передать его классу, который нуждается в этом, т.е.
// example of problem
public class MyClass
{
public MyClass(IContextProvider context, IEventContextFactory event)
{
_context = context;
_event = event;
}
public void DoSomething()
{
// the only place _event is used in the class is to pass it through
var myClass = new MyChildClass(_event);
myClass.PerformCalculation();
}
}
Поэтому мой главный вопрос: приемлемо ли это, или это обычное дело или хорошая практика сделать что-то вроде этого (интерфейс расширяет другой интерфейс):
public interface IContextProvider : IEventContextFactory
или я должен рассмотреть лучшие альтернативы достижению того, что мне нужно. Если я не предоставил достаточно информации, чтобы дать предложения, дайте мне знать, и я могу предоставить больше.
источник
Ответы:
Хотя интерфейсы описывают только поведение без какой-либо реализации, они все же могут участвовать в иерархиях наследования. В качестве примера представьте, что у вас есть, скажем, общая идея о
Collection
. Этот интерфейс предоставит несколько общих для всех коллекций вещей, например, метод для перебора членов. Затем вы можете подумать о некоторых более конкретных коллекциях объектов, таких как aList
или aSet
. Каждый из них наследует все требования поведения aCollection
, но добавляет дополнительные требования, специфичные для этого конкретного типа коллекции.В любое время имеет смысл создать иерархию наследования для интерфейсов, тогда вам следует это сделать. Если два интерфейса всегда будут найдены вместе, то их, вероятно, следует объединить.
источник
Да, но только если это имеет смысл. Задайте себе следующие вопросы, и если один или несколько из них применимы, то приемлемо наследовать интерфейс от другого.
В вашем примере, я не думаю, что это отвечает да ни на один из них. Возможно, вам лучше добавить его в качестве другого свойства:
источник
IContextProvider
extensionIEventContextFactory
, тоContextProvider
реализация должна будет реализовать и этот метод. Если вы добавляете его как свойство, вы говорите, что онContextProvider
имеет,IEventContextFactory
но на самом деле не знает деталей реализации.Да, это нормально, чтобы расширить один интерфейс из другого.
Вопрос о том, правильно ли это делать в конкретном случае, зависит от того, существуют ли истинные отношения «есть» между ними.
Что требуется для правильных отношений "is-a"?
Во-первых, между двумя интерфейсами должна быть реальная разница, т. Е. Должны быть экземпляры, которые реализуют родительский интерфейс, но не дочерний интерфейс. Если нет и никогда не будет экземпляров, которые не реализуют оба интерфейса, то вместо этого эти два интерфейса должны быть объединены.
Во-вторых, должен быть случай, когда каждый экземпляр дочернего интерфейса обязательно должен быть экземпляром родительского: нет (разумной) логики, при которой вы бы создали экземпляр дочернего интерфейса, который не имел бы смысла в качестве экземпляра родительский интерфейс.
Если оба из них верны, то наследование является правильным отношением для двух интерфейсов.
источник
IReadOnlyList
может быть полезен, даже если все классы моего списка реализуютIList
(который получен изIReadOnlyList
).Если один интерфейс всегда хочет запрашивать / предоставлять другой, тогда продолжайте. Я видел это в нескольких случаях,
IDisposible
которые имели смысл. В общем, вы должны убедиться, что хотя бы один из интерфейсов ведет себя скорее как черта, а не ответственность.Для вашего примера это не понятно. Если они оба всегда вместе, просто создайте один интерфейс. Если один всегда нуждается в другом, меня беспокоит наследование типа «X и 1», которое очень часто приводит к множественным обязанностям и / или другим проблемам с утечкой абстракции.
источник