Принцип разделения интерфейса (англ. 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.