Non c'è niente di male in questo. In realtà, è un modello abbastanza potente e ampiamente utilizzato. L'ho sentito chiamare "leva API", perché implementando solo un metodo (di solito piuttosto semplice), si ottiene in cambio una grande quantità di funzionalità. In altre parole, proprio come con una leva, puoi trasformare un piccolo sforzo in un sacco di risultati.
Alcuni esempi di dove è utilizzato in natura sono:
- API
Enumerable di Ruby: a partire da Ruby 2.3, Enumerable ha 48 metodi concreti ( map , flat_map , find , reduce , ... tutti i metodi che ci si aspetterebbe da un oggetto iterabile ), tutti implementati in termini di un unico metodo astratto: each . Sottoclassi, come Array , Hash , Set , Enumerator , ecc, devono solo implementare un modo per iterare su se stessi (cioè each ) e ottenere gratuitamente tutti gli altri metodi. Praticamente qualsiasi cosa che sia anche lontanamente simile alla collezione eredita da Enumerable .
-
Comparable API di Ruby: le sottoclassi devono solo implementare <=> (l'operatore di confronto combinato) e guadagnare < , <= , > , >= e between? gratuitamente. Praticamente qualsiasi cosa eredita da Comparable .
- L'API
FunctionN di Scala: devi solo implementare apply e il tuo oggetto può essere trattato come una funzione. Molte cose ereditano da FunctionN , ad esempio Set eredita da Function1[T, Boolean] e Array eredita da Function1[Int, T] . FunctionN fornisce una serie di metodi concreti per la composizione e la trasformazione di funzioni, tutte basate su apply .
- L'API
Traversable di Scala: simile a Enumerable di Ruby, devi solo implementare foreach e ottenere gratuitamente quasi 100 metodi concreti. Praticamente tutte le raccolte implementano Traversable .
- Lo stesso vale per
Iterable : implementa iterator e ottieni tutto il resto gratuitamente. (Infatti: Iterable eredita da Traversable e implementa foreach anche in termini di iterator .)
E, naturalmente, in generale, una classe con un singolo metodo astratto è isomorfo a un tipo di funzione, ed è spesso usata in questo modo. Per es.
- in Python, ogni oggetto con un metodo
__call__ è considerato un "callable" (cioè simile a una funzione) e il metodo __call__ può essere chiamato con lo zucchero della sintassi come foo() ,
- in Ruby, ogni oggetto con un metodo
call è considerato come funzione e il metodo call può essere chiamato con lo zucchero della sintassi come foo.() ,
- in Scala, ogni oggetto con un metodo
apply è considerato come funzione e il metodo apply può essere chiamato con lo zucchero della sintassi come foo() , e
- in Java, ogni tipo con un singolo metodo astratto è considerato un tipo di funzione e le istanze di quel tipo possono essere costruite utilizzando la sintassi letterale lambda