Принцип разделения интерфейса (англ. Interface Segregation Principle, ISP) один из пяти принципов проектирования классов в объектно-ориентированном программировании. Следование этому принципу помогает системе оставаться гибкой при внесении изменений в логику работы и пригодной для рефакторинга.
Клиенты не должны зависеть от методов, которые они не используют.
Принцип разделения интерфейсов говорит о том, что слишком «толстые» интерфейсы необходимо разделять на более маленькие и специфические, чтобы клиенты маленьких интерфейсов знали только о методах, которые необходимы им в работе. В итоге, при изменении метода интерфейса не должны меняться клиенты, которые этот метод не используют.
Используем наш пример с фигурами. Например, у нас есть твердые фигуры и мы бы хотели иметь возможность вычислять их объем.
Для этого нам нужно добавить еще один контракт в интерфейс ShapeInterface:
interface ShapeInterface {
public function area();
public function volume();
}Любая фигура, которую мы создаем, должна содержать метод вычисления объема, но мы знаем, что квадраты являются плоскими фигурами и они не имеют объема. Поэтому новый интерфейс заставит реализовать пустой метод в классе Square, который не будет использоваться.
Следуя принципу ISP, мы можем создать второй интерфейс, который может называться SolidShapeInterface и иметь метод вычисления объема. Твердые фигуры, такие как кубы, могут использовать этот интерфейс:
interface ShapeInterface {
public function area();
}
interface SolidShapeInterface {
public function volume();
}
class Cuboid implements ShapeInterface, SolidShapeInterface {
public function area() {
// calculate the surface area of the cuboid
}
public function volume() {
// calculate the volume of the cuboid
}
}Это более лучшее решение, но есть ловушка с использованем проверки типа (type-hinting) этих интерфейсов вместо использования ShapeInterface или SolidShapeInterface.
Можно создать другой интерфейс, например ManageShapeInterface, и использовать его для всех типов фигур (плоских и объемных). Таким образом можно увидеть ,что он имеет единый API для управления всеми фигурами:
interface ManageShapeInterface {
public function calculate();
}
class Square implements ShapeInterface, ManageShapeInterface {
public function area() { /*Do stuff here*/ }
public function calculate() {
return $this->area();
}
}
class Cuboid implements ShapeInterface, SolidShapeInterface, ManageShapeInterface {
public function area() { /*Do stuff here*/ }
public function volume() { /*Do stuff here*/ }
public function calculate() {
return $this->area() + $this->volume();
}
}Теперь в классе AreaCalculator мы можем заменить вызов метода рассчета и проверки объекта на пренадлежность к интерфейсам ManageShapeInterface, но не ShapeInterface.