Каждый интерфейс явно реализован? (Участвует МОК)
Я хорошо осведомлен о том, что такой вопрос, вероятно, уже был опубликован. Тем не менее, благодаря участию IoC в этом случае и большому количеству кода, который я видел у коллеги в компании, в которой я новичок, возник этот вопрос.
Сценарий:
В кодовой базе одного продукта коллеги собирают каждый интерфейс явно. Все приложение построено через карту структуры, но в некоторых местах конкретные типы используются и отливаются следующим образом.
((IInterface)concreteClass).SomeMethod()
Фон:
Этот коллега объяснил мне, спросив, что это за явная реализация всех интерфейсов, что они недавно представили StructureMap, и многие люди все еще будут просто использовать конкретные типы. Так что по сути это средство для "обучения" людей в компании.
Мои центы по этому вопросу:
Прежде всего, переключение на StructureMap было сделано несколько лет назад, и хотя это как бы вынуждает использовать интерфейсы чаще, на мой взгляд, это неправильный путь. На мой взгляд, люди, которые знают о конкретном типе, могут видеть реализацию и легко понять то, что я показал выше... просто приведите ее. Четкие соглашения по кодированию и общению сделают это намного лучше. Если используется IoC, а не конкретный класс, то явное внедрение интерфейса совершенно бесполезно.
Я также слышал, что это может действительно испортить наследство, но я не знаю примера. Я также видел, как Джон Скит отговаривает от его использования способом, упомянутым выше, а скорее способом, которым он был предназначен для использования, как с IEnumerable<> и другими конфликтами имен.
Может кто-нибудь пролить свет на этот вопрос для меня. Плюсы и минусы (хотя я очень предвзято отношусь к тому, чтобы этого не делать, поэтому мой пост здесь) и особенно причины того или иного.
Спасибо!
Изменить: Я очень хорошо знаю, что это не вопрос правильного или неправильного, и нет реального ответа. Это больше вопрос, чтобы научиться узнавать недостатки каждого подхода. Зачем мне использовать в одном сценарии один над другим подход?
2 ответа
Хорошей отправной точкой могла бы стать эта статья: Почему я использую явную реализацию интерфейса в качестве метода реализации по умолчанию
Первоначально я не был склонен к явной реализации интерфейсов, но я должен признать, что автор делает некоторые очень хорошие замечания.
ОБНОВЛЕНИЕ: в комментариях ниже OP указывает, что явная реализация испортила наследование, поскольку вы не можете переопределить реализацию интерфейса в производном типе. Я не уверен, правильно ли я понимаю проблему:
public interface IFooable
{
void Foo();
void FooAgain();
}
public class Blah: IFooable
{
void IFooable.Foo()
{
Console.WriteLine("Hi from 'Blah'!");
}
void IFooable.FooAgain() {}
}
public class Bar: Blah, IFooable
{
void IFooable.Foo()
{
Console.WriteLine("Hi from 'Bar'!");
}
}
public static void Main()
{
var fooList = new List<IFooable>();
fooList.Add(new Blah());
fooList.Add(new Bar());
foreach (var fooable in fooList) //Outputs "Hi from 'Blah'!" / "Hi from 'Bar'!"
fooable.Foo();
Console.ReadLine();
}
У явных реализаций интерфейса есть два основных потенциальных преимущества:
- Один класс может реализовывать два интерфейса, которые имеют конфликтующие сигнатуры методов, и слегка разные реализации для каждого. Это случается редко, и, как правило, это не проблема по требованию, а не по умолчанию.
- Вы можете "скрыть" определенные методы, которые, как вы ожидаете, люди не будут использовать, за исключением определенных случаев. Принцип сегрегации интерфейса побуждает нас не показывать потребителям методы, которые им вряд ли понадобятся.
Один хороший пример использования #2 - это способ, которым контексты Entity Framework избегают разоблачения их основных ObjectContext
напрямую (потому что большинство людей не должны использовать его в своем коде), но все же делают это свойство доступным, если вы приведете контекст к IObjectContextAdapter
,
В случае вашей компании, похоже, что они пытаются использовать #2, но по неправильным причинам. Они хотят скрыть реализации методов не потому, что этот метод не предполагается использовать, а потому, что они ожидают его использования - и надеются, что когда это произойдет, разработчики отделят свой код от конкретного типы. В вашем примере кода показано, что в нем отсутствует отметка - разработчики все еще создают конкретные типы и затем приводят их в соответствие, чтобы получить доступ к интерфейсным методам.