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