2010-07-07 2 views
32

Je comprends les principes de Coding to Interfaces - découpler l'implémentation de l'interface, et permettre aux implémentations de l'interface d'être permutées.Doit-on toujours coder les interfaces en Java?

Est-ce que je devrais coder les interfaces pour chaque classe que j'écris ou est-ce que c'est trop? Je ne veux pas doubler le nombre de fichiers sources dans un projet à moins que cela ne le vaille vraiment.

Quels facteurs puis-je utiliser pour décider de coder par interface ou non?

+0

Voir aussi cette question: http://stackoverflow.com/questions/3036749/is -la-meilleure-pratique-pour-extraire-une-interface-pour-chaque-classe –

+0

Merci. C'est ce que j'étais après – Tarski

Répondre

28

En général, je suis d'accord avec les autres réponses: utilisez une interface lorsque vous connaissez ou anticipez un changement et/ou une implémentation différente, ou optez pour la testabilité.

Mais il n'est pas toujours facile de savoir à l'avance ce qui peut changer dans le futur, surtout si vous n'êtes pas si expérimenté. Je pense que la solution à ce problème est le refactoring: gardez-le simple (= pas d'interface) tant qu'il n'est pas nécessaire. Lorsque le besoin s'en fait sentir, faites simplement un refactoring "Introduire/Extraire l'interface" (supporté par presque tous les IDEs décents). Lorsque vous le faites, extrayez uniquement les méthodes réellement nécessaires aux appelants. N'ayez pas peur d'extraire plus d'une interface séparée (si toutes les méthodes extraites ne sont pas vraiment cohérentes).

Un des pilotes du refactoring pourrait être le test: si vous ne pouvez pas facilement tester quelque chose avec des classes, pensez seulement à introduire une/quelques interface (s). Cela vous permettra également d'utiliser des simulacres qui peuvent grandement simplifier les tests dans de nombreux cas.

Edit: basé sur le commentaire de Tarski je me suis rendu compte d'un scénario plus/ajustement important pour les déclarations antérieures:
Si vous fournissez une API externe (pour d'autres projets [sous], ou RELEASE vraiment « à la sauvage ") puis utiliser des interfaces dans l'API (sauf pour les classes de valeurs simples) est presque toujours une bonne idée.
Il vous permettra de changer l'impl si vous le souhaitez sans perturber le code client. Vous aurez un problème seulement si vous devez également changer l'interface. Ne pas casser la compatibilité sera très difficile (voire impossible).

+0

bonne réponse. J'ai rencontré exactement ceci - j'ai eu une classe utilisée par de multiples projets de client et ai maintenant besoin d'une interface pour offrir une implémentation alternative - je pourrais employer le dépassement mais ce n'est pas aussi propre. Le problème est que j'ai alors besoin de recompiler tous les clients existants pour utiliser l'interface. Comme vous le dites, je ne savais pas que j'avais besoin de l'interface quand j'ai commencé – Tarski

+1

Vous avez raison avec la recompilation, vous devez le faire après le refactoring, mais seulement une fois. Après cette mise en œuvre est bien découplé, vous êtes libre de le changer/ajouter de nouveaux sans avoir besoin de recompilation. –

+0

En ce qui concerne l'édition, vous pouvez lire à propos de: http://martinfowler.com/bliki/PublishedInterface.html – michaelsnowden

9

Non, chaque classe ne doit pas avoir d'interface. C'est trop carré.

Vous utilisez une interface lorsque vous avez besoin de faire abstraction de ce qui a été fait, et vous êtes certain que l'implémentation peut changer. Jetez un oeil à l'API Collections java.util pour un bon exemple. L'interface List est une belle abstraction pour l'idée générale d'une liste, mais vous pouvez voir qu'il existe plusieurs façons de l'implémenter: ArrayList, LinkedList, etc.

MISE À JOUR: Alors qu'en est-il de ce cas où vous concevez un béton classe, décidez après avoir des clients qu'une interface est nécessaire, puis vous cassez vos clients en ajoutant une interface? Yup, c'est ce qui arrive. Comment pouvez-vous savoir ce que vous ne savez pas? Aucun logiciel ou méthodologie ne peut résoudre ce problème. La bonne nouvelle pour vous est que l'extraction d'une interface à partir d'une classe concrète est un refactoring facile à faire pour vous et vos clients. Les IDE gèrent ce genre de choses régulièrement. Vous et vos clients devriez en profiter.

Je dirais que les couches, comme les services et la persistance, devraient toujours avoir des interfaces. Tout ce qui peut être mandaté devrait avoir une interface. Si vous faites Spring AOP, tout ce que vous voulez décorer avec un aspect devrait avoir une interface.

Les objets de modèle ou de valeur, tels que Personne ou Adresse ou Téléphone, ne doivent pas avoir d'interface. Un objet de valeur immutable ne doit pas avoir d'interface.

Le reste tombe dans les zones grises. Utilisez votre meilleur jugement.

+2

Mais que se passe-t-il si tu ne sais pas que tu vas avoir besoin de l'abstraction? PAR EXEMPLE. Vous codez une classe sans interface, vos clients dépendent de la classe, vous avez alors besoin d'une autre implémentation mais vous ne pouvez pas extraire une interface sans rompre la compatibilité binaire. – Tarski

+0

^ceci. Aussi, est-ce vraiment si difficile de créer une interface et de la mettre en œuvre par une classe? Cela prend-il vraiment beaucoup plus de temps pour le faire? – GreenieMeanie

11

Je l'utilise lorsqu'au moins une des conditions suivantes est remplie:

1) Je veux découpler modules/classes indépendantes les unes des autres, et je veux qu'il soit réfléchi par les dépendances de paquets Java.

2) Lorsque le découplage est important en termes de dépendances de construction

3) Lorsque la mise en œuvre peut changer par la configuration ou dynamiquement lors de l'exécution (généralement à cause d'un modèle de conception)

4) Quand je veux un classe pour être testable, je fais ses "points de liaison" vers des interfaces de ressources externes, de sorte que je peux utiliser des implémentations fictives.

5) Moins commun: lorsque je veux avoir une option pour restreindre l'accès à une classe. Dans ce cas, ma méthode renvoie une interface au lieu de la classe réelle, de sorte que l'appelant sait que je ne m'attends pas à ce qu'il fasse d'autres opérations sur la valeur retournée.

+0

+1 pour testabilité et restriction d'accès –

2

Longue histoire courte, non.Vous êtes le créateur de l'application, donc vous avez une bonne idée de ce que pourrait changer. Certains des modèles de modèles de design sont un peu fous à mon avis, car ils semblent toujours pousser la conception à des interfaces et non la mise en œuvre, peu importe quoi. Parfois, c'est juste trop. Pour ma dernière application (petite taille), j'ai une interface de base de données parce que je pense qu'il y a une chance que je puisse la porter plus tard sur le web et passer à MySQL. Bien sûr, en réalité, il serait facile de créer une interface de base de données à partir de ma classe existante et ajouter simplement "implémente myDbInterface" plus tard avec quelques petites modifications. Cela fonctionne parce que je suis le seul développeur cependant. Dans une équipe plus grande ou dans un type de produit différent, la réponse peut être différente. Utilisez votre meilleur jugement (après avoir lu toutes les bonnes réponses SO bien sûr).

1

J'aime à penser que l'on utilise des interfaces lorsque l'enfichage et le potentiel de comportement différent sont importants. Les services sont parfaits. On pourrait vouloir une implémentation par défaut, mais truquer (moquer) etc en est une autre. Cela signifie évidemment qu'il devrait y avoir un intf car il y aura toujours au moins 2 formes.

Les types de valeur, d'un autre côté, doivent être des classes finales. Ils ne devraient jamais être prolongés. Les types de valeur incluent quelque chose comme Suburb, MimeType. S'il y a des variations de ces compositions d'utilisation. Comme objectif, j'essaie de mettre un peu de comportement s'il y en a dans mes types de valeur. Valider le type simple qu'il encapsule est probablement la chose la plus complexe qu'il fait. Par exemple, une classe de couleur qui prend r/g/b devrait valider que chaque composant est entre 0 et 255 et c'est tout.

0

Oui, utilisez l'interface lorsque vous vous attendez à ce qu'un comportement change. . Dans le futur.

Ou votre classe qui peut gérer les changements de manière claire.

par ex.

public static void main(String s[]) 
{ 
Employee e1=new Employee(new Salesman()); 
Employee e2=new Employee(new Manager()); 

system.out.println(e1.performaction()); 
system.out.println(e1.performaction()); 
} 

Class Employee 
{ 

//which changes frequently 
Authority a; 

public Employee(Authority a) 
{ 
this.a=a; 
}  
public String performAction() 
{ 
a.action(); 
} 
} 

// ----------------------------------------- -------------------------

interface Authority 
{ 
public String action(); 
} 

class Manager implements Authority 
{ 
public String action() 
{ 
returns "I manages People"; 
} 

class SalesMan implements Authority 
{ 
    public String action() 
{ 
returns "I Sell things Company makes "; 
} 
}