Principe de ségrégation de l'Interface-programme vers une interface

je lisais à propos de SOLID et d'autres principes de conception. Je pensais que ISP était la même chose que "programme à une interface, pas une implémentation". Mais il semble que ce sont des principes différents?

y a-t-il une différence?

19
demandé sur Dave Schweisguth 2012-02-12 19:09:37

6 réponses

ISP est axé sur l'idée de chaque interface représentant un comportement discret et cohérent.

C'est-à-dire que chaque groupe logique de choses qu'un objet devrait faire correspondrait à une interface spécifique unique. Une classe peut vouloir faire plusieurs choses, mais chaque chose correspond à une interface spécifique représentant ce comportement. L'idée est que chaque interface est très concentré.

28
répondu Pete Stensønes 2012-02-12 18:32:30

Robert Martin a une très bonne explication du principe de ségrégation des interfaces (ISP), dans son livre "UML for Java Programmers". Basé sur cela, je ne pense pas ISP est au sujet d'une interface étant "concentré" sur un groupe logique et cohérent de choses. Parce que, cela va de soi; ou, du moins, cela devrait aller de soi. Chaque classe, interface ou classe abstraite devrait être conçue de cette façon.

alors, QU'est-ce que ISP? Permettez-moi de l'expliquer par un exemple. Dites, vous avez une classe A et a Classe B, qui est le client de la classe A. supposons, Classe A a dix méthodes, dont seulement deux sont utilisées par B. Maintenant, est-ce que B a besoin de connaître les dix méthodes de A? Probablement pas-le principe de la dissimulation de L'Information. Plus vous exposez, plus vous créez la chance de l'accouplement. Pour cette raison, vous pouvez insérer une interface, C, entre les deux classes (ségrégation). Cette interface déclarera seulement les deux méthodes qui sont utilisées par B, et B dépendra de cette Interface, à la place directement sur A. 151930920"

donc maintenant,

class A {
   method1()
   method2()
   // more methods
   method10()
}
class B {
    A a = new A()

}

deviendra

interface C {
      method1()
       method2()
}



class A implements C{
      method1()
      method2()
      // more methods
      method10()
  }
  class B {
       C c = new A()

 }   

ceci, empêche B de savoir plus qu'il ne devrait.

35
répondu Nazar Merza 2012-12-26 17:41:57

supposer que vous avez une interface fat avec de nombreuses méthodes à mettre en œuvre.

toute classe, qui implémente cette interface fat doit fournir l'implémentation de toutes ces méthodes. Certaines des méthodes peuvent ne pas être applicables à cette classe de béton. Mais il doit tout de même fournir la mise en œuvre en l'absence de principe de ségrégation d'interface.

regardons le code d'exemple dans absence de ségrégation D'Interface .

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());

    }
}

sortie:

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

Notes:

  1. Shape est une interface fat à usage général, qui contient des méthodes requises pour toutes les implémentations Shape comme Rectangle , Circle et Square . Mais seulement quelques méthodes sont nécessaires dans les childs de forme respective

     Rectangle : getLength(), getWidth(), getArea()
     Square    : getLength() and getArea()
     Circle    : getRadius() and getArea()
    
  2. absence de ségrégation, toutes les formes ont mis en œuvre toute l'interface fat : Shape.

nous pouvons obtenir la même sortie avec le principe de ségrégation de l'interface si nous changeons le code comme suit.

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());

    }
}

Notes:

maintenant les formes individuelles comme Rectangle , Square et Circle ont mis en œuvre seulement les interfaces requises et se sont débarrassés des méthodes non utilisées.

8
répondu Ravindra babu 2016-08-20 08:54:49

d'Accord avec les deux réponses ci-dessus. Juste pour donner un exemple de TrueWill 's code smell ci-dessus, vous ne devriez pas vous trouver à faire cela:

@Override
public void foo() {
    //Not used: just needed to implement interface
}
1
répondu anotherdave 2013-05-06 09:14:57

voici un exemple réel de ce principe (en PHP)

Énoncé Du Problème:

je veux que diverses formes de contenu soient assorties de commentaires/discussions. Ce contenu pourrait être n'importe quoi d'un sujet de forum, à un article de nouvelles, au profil d'un utilisateur, à un message privé de style de conversation.

Architecture

nous allons vouloir une classe DiscussionManager réutilisable qui attache une Discussion à une entité de contenu donnée. Cependant, les quatre exemples ci-dessus (et bien d'autres) sont conceptuellement différentes. Si nous voulons que la DiscussionManager à les utiliser, puis tous les quatre ont besoin d'avoir une interface commune qu'ils partagent tous. Il n'y a pas d'autre moyen pour DiscussionManager de les utiliser à moins que vous ne vouliez à vos arguments d'aller nu (par exemple pas de vérification de type).

Solution: Discussable interface avec ces méthodes:

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

puis DiscussionManager pourrait ressembler à ceci:

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) { ... }
}

de cette façon, DiscussionManager ne se soucie pas de l'un des comportements indépendants des différents types de contenu qu'il utilise. Il ne se soucie que des comportements dont il a besoin, indépendamment de ce à quoi ces comportements sont associés. Donc, en donnant chaque type de contenu pour lequel vous voulez avoir des discussions, une interface Discussable , vous utilisez le principe de ségrégation de l'interface.

C'est aussi un bon exemple d'une situation où une classe de base abstraite n'est pas une bonne idée. Un sujet de forum, un profil d'utilisateur, et un article de nouvelles ne sont même pas de loin conceptuellement la même chose, donc essayer de leur faire hériter les comportements de discussion conduit à un couplage étrange à un parent non lié. En utilisant une interface spécifique qui représente les discussions, Vous pouvez vous assurer que les entités que vous voulez avoir des discussions, sont compatibles avec le code client qui gérera ces discussions.

cet exemple pourrait aussi être un bon candidat pour l'utilisation de Traits en PHP, pour ce que cela vaut.

0
répondu AgmLauncher 2014-03-18 16:49:47
  1. IWorker Interface:

    public interface IWorker {
        public void work();
        public void eat();
    
    }
    
  2. Développeur De La Classe :

    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");
    
         }
    
    }
    
  3. Classe De Robot:

    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");
    
         }
    
    }
    

pour un exemple plus complet, allez ici .

0
répondu Coder Programmer 2017-06-21 07:32:34