Pendant des décennies, les interfaces ont été uniquement (uniquement) utilisées pour spécifier les signatures de méthode. On nous a dit que c'était la "bonne façon de faire les choses ™".
Ensuite, Java 8 est sorti et a dit:
Eh bien, euh, maintenant vous pouvez définir des méthodes par défaut. Je dois courir, au revoir.
Je suis curieux de savoir comment cela est digéré par les développeurs Java expérimentés et ceux qui ont commencé récemment (ces dernières années) à le développer. Je me demande également comment cela s'inscrit dans l'orthodoxie et la pratique Java.
Je construis du code expérimental et pendant que je faisais du refactoring, je me suis retrouvé avec une interface qui étend simplement une interface standard (Iterable) et ajoute deux méthodes par défaut. Et je vais être honnête, je me sens très bien à ce sujet.
Je sais que c'est un peu ouvert mais maintenant qu'il y a un certain temps pour que Java 8 soit utilisé dans de vrais projets, y a-t-il encore une orthodoxie autour de l'utilisation des méthodes par défaut? Ce que je vois surtout quand ils sont discutés, c'est comment ajouter de nouvelles méthodes à une interface sans casser les consommateurs existants. Mais qu'en est-il d'utiliser dès le départ comme l'exemple que j'ai donné ci-dessus. Quelqu'un at-il rencontré des problèmes avec la fourniture d'implémentations dans ses interfaces?
la source
java.util.function.Function
pour l'utilisation des méthodes par défaut dans une toute nouvelle interface.Réponses:
Un excellent cas d'utilisation est ce que j'appelle des interfaces «à levier»: des interfaces qui n'ont qu'un petit nombre de méthodes abstraites (idéalement 1), mais qui fournissent beaucoup de «levier» en ce qu'elles vous offrent beaucoup de fonctionnalités: vous seulement besoin d'implémenter 1 méthode dans votre classe mais obtenez beaucoup d'autres méthodes "gratuitement". Pensez à une interface de collecte, par exemple, avec une seule abstraite
foreach
méthode et desdefault
méthodes commemap
,fold
,reduce
,filter
,partition
,groupBy
,sort
,sortBy
, etc.Voici quelques exemples. Commençons par
java.util.function.Function<T, R>
. Il a une seule méthode abstraiteR apply<T>
. Et il a deux méthodes par défaut qui vous permettent de composer la fonction avec une autre fonction de deux manières différentes, avant ou après. Ces deux méthodes de composition sont implémentées en utilisant simplementapply
:Vous pouvez également créer une interface pour des objets comparables, quelque chose comme ceci:
Ou un framework de collections extrêmement simplifié, où toutes les opérations de collections retournent
Collection
, quel que soit le type d'origine:Cela devient très intéressant en combinaison avec lambdas, car une telle interface "levier" peut être implémentée par un lambda (c'est une interface SAM).
C'est le même cas d'utilisation que les méthodes d'extension ont été ajoutées en C♯, mais les méthodes par défaut ont un avantage distinct: ce sont des méthodes d'instance "correctes", ce qui signifie qu'elles ont accès aux détails d'implémentation privée de l'interface (
private
les méthodes d'interface arrivent en Java 9), alors que les méthodes d'extension ne sont que du sucre syntaxique pour les méthodes statiques.Si Java obtenait une injection d'interface, il permettrait également une correction de singe modulaire sécurisée et de portée. Cela serait très intéressant pour les implémenteurs de langage sur la JVM: pour le moment, par exemple, JRuby hérite ou encapsule des classes Java pour leur fournir une sémantique Ruby supplémentaire, mais idéalement, ils veulent utiliser les mêmes classes. Avec l'Injection d'Interface et les Méthodes par Défaut, ils pourraient injecter par exemple une
RubyObject
interface dansjava.lang.Object
, de sorte qu'un JavaObject
et un RubyObject
sont exactement la même chose .la source
Comparable
interface avec un résumécompareTo
méthode, et par défautlessThan
,lessThanOrEqual
,greaterThan
,greaterThanOrEqual
,isBetween
et lesclamp
méthodes, tous mis en œuvre en termes decompareTo
. Ou, regardezjava.util.function.Function
: il a uneapply
méthode abstraite et deux méthodes de composition par défaut, toutes deux implémentées en termes deapply
. J'ai essayé de donner un exemple d'Collection
interface, mais il est difficile et trop long de faire en sorte que tout soit sûr pour cette réponse - je vais essayer de donner une version non sécurisée, sans préservation de type. Restez à l'écoute.