При чтении статей об ISP, кажется, есть два противоречивых определения ISP:
Согласно первому определению (см. 1 , 2 , 3 ), провайдер заявляет, что классы, реализующие интерфейс, не должны принуждаться к реализации функций, которые им не нужны. Таким образом, толстый интерфейсIFat
interface IFat
{
void A();
void B();
void C();
void D();
}
class MyClass: IFat
{ ... }
следует разделить на более мелкие интерфейсы ISmall_1иISmall_2
interface ISmall_1
{
void A();
void B();
}
interface ISmall_2
{
void C();
void D();
}
class MyClass:ISmall_2
{ ... }
так как таким образом мой MyClassспособен реализовать только те методы, которые необходимы ( D()и C()), не будучи вынужден также обеспечить фиктивные реализации для A(), B()и C():
Но согласно второму определению (см. 1 , 2 , ответ Назар Мерза ), провайдер заявляет, что MyClientвызывающие методы MyServiceне должны знать о тех методах, MyServiceкоторые ему не нужны. Другими словами, если MyClientтребуется только функциональность C()и D(), то вместо
class MyService
{
public void A();
public void B();
public void C();
public void D();
}
/*client code*/
MyService service = ...;
service.C();
service.D();
мы должны разделить MyService'sметоды на клиентские интерфейсы:
public interface ISmall_1
{
void A();
void B();
}
public interface ISmall_2
{
void C();
void D();
}
class MyService:ISmall_1, ISmall_2
{ ... }
/*client code*/
ISmall_2 service = ...;
service.C();
service.D();
Таким образом, в первом определении цель ISP состоит в том, чтобы « облегчить жизнь классам, реализующим интерфейс IFat », а в последнем случае цель ISP - « облегчить жизнь клиентам, вызывающим методы MyService ».
Какое из двух разных определений провайдера действительно правильно?
@MARJAN VENEMA
1.
Поэтому, когда вы собираетесь разделить IFat на более мелкий интерфейс, какие методы в конечном итоге будут определять ISmallinterface в зависимости от того, насколько сплочены члены.
Хотя имеет смысл поместить связные методы в один и тот же интерфейс, я подумал, что с помощью шаблона ISP потребности клиента имеют приоритет перед «связностью» интерфейса. Другими словами, я думал, что с провайдером мы должны объединить в одном и том же интерфейсе те методы, которые нужны конкретным клиентам, даже если это означает, что нужно исключить из этого интерфейса те методы, которые, ради целостности, также должны быть помещены в тот же интерфейс?
Таким образом, если было много клиентов, которым когда-либо нужно было только звонить CutGreens, но не также GrillMeat, то для того, чтобы придерживаться шаблона ISP, мы должны только помещать его CutGreensвнутрь ICook, но не также GrillMeat, даже если эти два метода очень взаимосвязаны ?!
2.
Я думаю, что ваша путаница проистекает из скрытого предположения в первом определении: что реализующие классы уже следуют принципу единой ответственности.
Под "реализацией классов, не следующих за SRP", вы имеете в виду те классы, которые реализуют, IFatили классы, которые реализуют ISmall_1/ ISmall_2? Я полагаю, вы имеете в виду классы, которые реализуют IFat? Если так, почему вы предполагаете, что они еще не следуют SRP?
Благодарность