Подтвердить что ты не робот

Принцип разделения сечений - программа для интерфейса

Я читал о SOLID и других принципах дизайна. Я думал, что интернет-провайдер был таким же, как "Программа для интерфейса, а не реализация". Но похоже, что это разные принципы?

Есть ли разница?

4b9b3361

Ответ 1

ISP фокусируется на идее каждого интерфейса, представляющего одно дискретное и когезионное поведение.

То есть, каждая логическая группа вещей, которые должен выполнять объект, будет сопоставляться одному конкретному интерфейсу. Класс может захотеть сделать несколько вещей, но каждая вещь будет сопоставляться с определенным интерфейсом, представляющим это поведение. Идея заключается в том, что каждый интерфейс очень сфокусирован.

Ответ 2

Роберт Мартин очень хорошо объяснил принцип разделения интерфейса (ISP) в своей книге "UML для Java-программистов". Исходя из этого, я не думаю, что ISP - это интерфейс, "сфокусированный" на одной логической, связной группе вещей. Потому что это само собой разумеется; или, по крайней мере, это должно быть само собой разумеется. Каждый класс, интерфейс или абстрактный класс должны быть разработаны таким образом.

Итак, что такое провайдер? Позвольте мне объяснить это на примере. Скажем, у вас есть класс A и класс B, который является клиентом класса A. Предположим, у класса A есть десять методов, из которых только два используют B. Теперь нужно ли B знать обо всех десяти методах A? Наверное, нет - принцип скрытия информации. Чем больше вы выставляете, тем больше у вас шансов для связи. По этой причине вы можете вставить интерфейс, называемый С, между двумя классами (разделение). Этот интерфейс будет объявлять только два метода, которые используются B, и B будет зависеть от этого интерфейса, а не напрямую от A.

Итак,

class A {
  method1()
  method2()
  // more methods
  method10()
}

class B {
   A a = new A()
}

станет

interface C {
  method1()
  method2()
}

class A implements C{
  method1()
  method2()
  // more methods
  method10()
}

class B {
  C c = new A()      
}   

Это препятствует тому, чтобы B знал больше, чем должен.

Ответ 3

Предположим, что у вас есть один жирный интерфейс со многими способами, которые нужно реализовать.

Любой класс, реализующий этот жирный интерфейс, должен обеспечить реализацию для всех этих методов. Некоторые из методов могут быть неприменимы к этому конкретному классу. Но все же он должен обеспечить реализацию в отсутствие принципа разделения сегрегации.

Давайте рассмотрим пример кода в отсутствие сегрегации интерфейса.

interface Shape{
    public int getLength();
    public int getWidth();
    public int getRadius();
    public double getArea();
}

class Rectangle implements Shape{
    int length;
    int width;
    public Rectangle(int length, int width){
        this.length = length;
        this.width = width;
    }
    public int getLength(){
        return length;
    }
    public int getWidth(){
        return width;
    }
    public int getRadius(){
        // Not applicable
        return 0;
    }
    public double getArea(){
        return width * length;
    }
}
class Square implements Shape{
    int length;

    public Square(int length){
        this.length = length;
    }
    public int getLength(){
        return length;
    }
    public int getWidth(){
        // Not applicable
        return 0;
    }
    public int getRadius(){
        // Not applicable
        return 0;
    }
    public double getArea(){
        return length * length;
    }
}

class Circle implements Shape{
    int radius;
    public Circle(int radius){
        this.radius = radius;
    }
    public int getLength(){
        // Not applicable
        return 0;
    }
    public int getWidth(){
        // Not applicable
        return 0;
    }
    public int getRadius(){
        return radius;
    }
    public double getArea(){
        return 3.14* radius * radius;
    }
}

public class InterfaceNoSeggration{
    public static void main(String args[]){
        Rectangle r = new Rectangle(10,20);
        Square s = new Square(15);
        Circle c = new Circle(2);
        System.out.println("Rectangle area:"+r.getArea());
        System.out.println("Square area:"+s.getArea());
        System.out.println("Circle area:"+c.getArea());

    }
}

выход:

java InterfaceNoSeggration
Rectangle area:200.0
Square area:225.0
Circle area:12.56

Примечания:

  • Shape - это интерфейс общего назначения, содержащий методы, необходимые для всех реализаций Shape, таких как Rectangle, Circle и Square. Но в соответствующих дочерних элементах формы нужны только некоторые методы

     Rectangle : getLength(), getWidth(), getArea()
     Square    : getLength() and getArea()
     Circle    : getRadius() and getArea()
    
  • В отсутствие сегрегации все фигуры реализовали весь жирный интерфейс: Shape.

Мы можем достичь такого же результата с принципа разделения сегрегации, если мы изменим код следующим образом.

interface Length{
    public int getLength();
}
interface Width{
    public int getWidth();
}
interface Radius{
    public int getRadius();
}
interface Area {
    public double getArea();
}


class Rectangle implements Length,Width,Area{
    int length;
    int width;
    public Rectangle(int length, int width){
        this.length = length;
        this.width = width;
    }
    public int getLength(){
        return length;
    }
    public int getWidth(){
        return width;
    }
    public int getRadius(){
        // Not applicable
        return 0;
    }
    public double getArea(){
        return width * length;
    }
}
class Square implements Length,Area{
    int length;

    public Square(int length){
        this.length = length;
    }
    public int getLength(){
        return length;
    }
    public int getWidth(){
        // Not applicable
        return 0;
    }
    public int getRadius(){
        // Not applicable
        return 0;
    }
    public double getArea(){
        return length * length;
    }
}

class Circle implements Radius,Area{
    int radius;
    public Circle(int radius){
        this.radius = radius;
    }
    public int getLength(){
        // Not applicable
        return 0;
    }
    public int getWidth(){
        // Not applicable
        return 0;
    }
    public int getRadius(){
        return radius;
    }
    public double getArea(){
        return 3.14* radius * radius;
    }
}

public class InterfaceSeggration{
    public static void main(String args[]){
        Rectangle r = new Rectangle(10,20);
        Square s = new Square(15);
        Circle c = new Circle(2);
        System.out.println("Rectangle area:"+r.getArea());
        System.out.println("Square area:"+s.getArea());
        System.out.println("Circle area:"+c.getArea());

    }
}

Примечания:

Теперь отдельные фигуры, такие как Rectangle, Square и Circle, реализовали только необходимые интерфейсы и избавились от неиспользуемых методов.

Ответ 4

Согласитесь с обоими ответами выше. Чтобы привести пример запаха кода TrueWill выше, вы не должны этого делать:

@Override
public void foo() {
    //Not used: just needed to implement interface
}

Ответ 5

  • Интерфейс IWorker:

    public interface IWorker {
        public void work();
        public void eat();
    
    }
    
  • Класс разработчика:

    public class Developer implements IWorker {
    
         @Override
         public void work() {
               // TODO Auto-generated method stub
               System.out.println("Developer working");
    
         }
    
         @Override
         public void eat() {
               // TODO Auto-generated method stub
               System.out.println("developer eating");
    
         }
    
    }
    
  • Класс робота:

    public class Robot implements IWorker {
    
         @Override
         public void work() {
               // TODO Auto-generated method stub
               System.out.println("robot is working");
    
         }
    
         @Override
         public void eat() {
               // TODO Auto-generated method stub
               throw new UnsupportedOperationException("cannot eat");
    
         }
    
    }
    

Для более полного примера перейдите здесь.

Ответ 6

Вот пример реального мира этого принципа (в PHP)

Проблема:

Я хочу, чтобы различные формы контента имели комментарии/дискуссии, связанные с ними. Это содержание может быть чем угодно: от темы форума, от статьи новостей до профиля пользователя до личного сообщения в стиле беседы.

Архитектура

Нам понадобится повторно используемый DiscussionManager класс, который привязывает Discussion к данному объекту контента. Однако приведенные выше четыре примера (и многие другие) концептуально отличаются друг от друга. Если мы хотим, чтобы DiscussionManager использовал их, то все четыре + должны иметь один общий интерфейс, который все они разделяют. Для использования DiscussionManager нет другого способа использовать их, если вы не хотите, чтобы ваши аргументы были голыми (например, проверка типа не).

Решение: Discussable интерфейс с этими методами:

  • attachDiscussion($topic_id)
  • detachDiscussion()
  • getDiscussionID()

Тогда DiscussionManager может выглядеть так:

class DiscussionManager
{
    public function addDiscussionToContent(Discussable $Content)
    {
        $Discussion = $this->DiscussionFactory->make( ...some data...);
        $Discussion->save() // Or $this->DiscussionRepository->save($Discussion);
        $Content->attachDiscussion($Discussion->getID()); // Maybe saves itself, or you can save through a repository
    }

    public function deleteDiscussion(Discussable $Content)
    {
        $id = $Content->getDiscussionID();
        $Content->detatchDiscussion();
        $this->DiscussionRepository->delete($id);
    }

    public function closeDiscussion($discussion_id) { ... }
}

Таким образом, DiscussionManager не заботится ни о каком несвязанном поведении различных типов контента, которые он использует. Он ТОЛЬКО заботится о поведении, в котором он нуждается, независимо от того, с чем связаны эти поведения. Таким образом, предоставляя каждому типу контента, который вы хотите обсудить, интерфейс Discussable, вы используете принцип сегрегации интерфейса.

Это также хороший пример ситуации, когда абстрактный базовый класс не является хорошей идеей. Тема форума, профиль пользователя и новостная статья даже не являются концептуально одно и то же, поэтому, пытаясь заставить их унаследовать поведение, связанное с обсуждением, приводит к странной связи с неродственным родителем. Используя определенный интерфейс, который представляет обсуждения, вы можете убедиться, что объекты, которые хотите обсудить, совместимы с клиентским кодом, который будет управлять этими обсуждениями.

Этот пример также может быть хорошим кандидатом для использования Traits в PHP, для чего он стоит.