Почему вы должны стремиться к более чем одному члену интерфейса когда бы ни было возможно?
В общем, почему вы должны стремиться к трех-пяти членов на интерфейс?
А потом, что не так с чем-то вроде этого?
interface IRetrieveClient
{
Client Execute(string clientId);
}
interface ISaveClient
{
bool Execute(Client client);
}
interface IDeleteClient
{
bool Execute(string clientId);
}
Когда я вижу это, он кричит "Антипаттерн!" потому что интерфейс ничего не выполняет, особенно когда разработчик приложения намерен, чтобы каждый интерфейс имел отношение один к одному с классом, который его реализует.
Читайте: после того, как интерфейс реализован, он никогда не будет повторно реализован. Теперь я не проектировал эту систему, и мне кажется, что они хотели реализовать некоторую версию шаблона команд, но когда они обращаются к разработчикам, они, похоже, не понимают этого.
4 ответа
Одна из областей, где я довольно широко использовал шаблон "один метод для интерфейса", - это универсальные шаблоны вместе с некоторой универсальной инфраструктурой диспетчеризации.
Например:
public interface IValidateEntities<T>
{
bool Validate(T entity);
}
Затем, когда необходимо сделать что-то с сущностью некоторого типа, мы можем использовать отражение, чтобы выяснить, какую реализацию вызывать (результаты отражения обычно кэшируются заранее).
Некоторое время назад я провел презентацию по этому шаблону, и он доступен для просмотра здесь:
http://www.infoq.com/presentations/Making-Roles-Explicit-Udi-Dahan
Это выглядит вполне разумно для меня. Я очень рад иметь небольшое количество методов (или даже один метод) для интерфейса.
Обратите внимание, что преимущество комбинирования интерфейсов состоит в том, что вы можете (скажем) выборочно представлять различные представления класса путем соответствующего приведения. например, вы можете создать / изменить класс, а затем представить его (сузить) через более ограниченный интерфейс (например, имея интерфейс только для чтения)
например
interface Readable {
Entity get();
}
interface Writeable {
void set(Entity e);
}
Класс может реализовать оба интерфейса, так что вы можете изменить его, а затем вы можете представить его клиентам просто как Readable
объект, такой, что они не могут мутировать его. Это возможно благодаря разделению интерфейсов.
Главное в дизайне - придерживаться того, что Роберт Мартин называет принципом единой ответственности. В вашем случае, я думаю, то, что предложил L-Three, вполне разумно, так как клиент будет нести одну ответственность - общаться с базой данных (или службой и т. Д.). Поэтому, если вы видите, что методы в IClient по какой-то причине станут совершенно разными и нарушают SRP, вы можете разделить его на множество интерфейсов, и я не думаю, что если у интерфейса есть только один метод, это проблема. Например, хорошим примером является интерфейс под названием IKeyGenerator
это генерирует ключи потокобезопасным способом. Этот интерфейс имеет только GetNextKey()
метод, который вполне достаточно.
Вы должны быть осторожны, чтобы использовать общие правила и применять их слишком строго. Нет ничего плохого в вашем подходе как таковом, если это то, что вам нужно.
Но вы можете подумать о следующей альтернативе:
interface IClient
{
Client Retrieve(string clientId);
bool Save(Client client);
bool Delete(string clientId);
}
Преимущество этого подхода состоит в том, что когда вы используете инъекцию, вам нужно зарегистрировать только один экземпляр, и у вас есть только один интерфейс в конструкторе.
Так что, если он логически принадлежит друг другу, я бы держал его в одном интерфейсе, потому что он уменьшает беспорядок и менее сложен.