Я был виновен в наличии отношения 1 к 1 между моими интерфейсами и конкретными классами при использовании инъекции зависимостей. Когда мне нужно добавить метод к интерфейсу, я в конечном итоге сломаю все классы, реализующие интерфейс.Взаимодействие с интерфейсами или классами
Это простой пример, но предположим, что мне нужно ввести ILogger
в один из моих классов.
public interface ILogger
{
void Info(string message);
}
public class Logger : ILogger
{
public void Info(string message) { }
}
Имея отношение 1 к 1, похожее на запах кода. Поскольку у меня только одна реализация, есть ли потенциальные проблемы, если я создаю класс и помечаю метод Info
как виртуальный для переопределения в моих тестах вместо того, чтобы создавать интерфейс только для одного класса?
public class Logger
{
public virtual void Info(string message)
{
// Log to file
}
}
Если мне нужно другой вариант осуществление, я могу переопределить Info
метод:
public class SqlLogger : Logger
{
public override void Info(string message)
{
// Log to SQL
}
}
Если каждый из этих классов имеет специфические свойства и методы, которые создают вытекающую абстракцию, я мог бы извлечь из базы класс:
public class Logger
{
public virtual void Info(string message)
{
throw new NotImplementedException();
}
}
public class SqlLogger : Logger
{
public override void Info(string message) { }
}
public class FileLogger : Logger
{
public override void Info(string message) { }
}
причина, почему я не маркировать базовый класс как реферат, потому что если я когда-либо хотел, чтобы добавить еще один метод, я бы не б повторяют существующие реализации. Например, если моему FileLogger
нужен метод Debug
, я могу обновить базовый класс Logger
, не нарушая существующие SqlLogger
.
public class Logger
{
public virtual void Info(string message)
{
throw new NotImplementedException();
}
public virtual void Debug(string message)
{
throw new NotImplementedException();
}
}
public class SqlLogger : Logger
{
public override void Info(string message) { }
}
public class FileLogger : Logger
{
public override void Info(string message) { }
public override void Debug(string message) { }
}
Опять же, это простой пример, но когда я должен использовать интерфейс?
Причина, по которой я не отмечал базовый класс как абстрактный, потому что, если я когда-либо хотел добавить другой метод_Hm, абстрактный класс может содержать реализацию. Вы можете добавить метод отладки в свой абстрактный класс Logger. –
Нарушение существующих реализаций - это только проблема, если вы пишете библиотеку многократного использования. Ты? Или вы просто пишете бизнес-приложение? – Steven
Это не вопрос, но наследование переоценено. «SqlLogger» - это всего лишь конкретный «Logger» с 'SqlLogPersistenceStrategy'. В большинстве случаев композиция намного лучше, чем наследование. Также для вашей проблемы, как насчет провайдера? 'ILogInfo',' ILogError' и т. Д. – plalx