При чтении статей об 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?
Благодарность