Non proprio, no. In un linguaggio che supporta le interfacce (esplicitamente o sotto forma di ereditarietà multipla con classi virtuali pure, come C ++), puoi sempre utilizzare il seguente modello:
interface Fooable {
void foo();
}
abstract class BaseBaz {
public abstract Fooable asFooable();
}
class BazOne extends BaseBaz {
public Fooable asFooable() { return null; } // not a Fooable!
}
class BazTwo extends BaseBaz implements Fooable {
public void foo() { Console.print("I am teh foobar!"); }
public Fooable asFooable() { return this; }
}
// --- snip ---
void runFooOnBaz(Baz baz) {
Fooable fooable = baz.asFooable();
if (fooable == null)
throw new NotFooableException();
fooable.foo();
}
Cioè, ti avvicini ad ogni oggetto tramite l'interfaccia, e dai alla classe base un metodo per restituirti l'oggetto tramite l'interfaccia, se possibile. (Probabilmente esiste un nome per questo pattern, ma non lo so, se qualcuno lo sa, sentiti libero di modificarlo.)
In un linguaggio di dattilografia come Python, dovresti seguire una strada diversa: piuttosto che chiedere se l'oggetto eredita da una determinata classe, devi solo fingere di farlo e prepararti per il fallimento:
class BazOne(object):
pass
class BazTwo(object):
def foo():
print "I am teh foobar!"
def runFoo(baz):
try:
baz.foo()
except AttributeError:
raise NotFooableError()
Tuttavia, quest'ultimo non è sempre possibile; motivi per cui non includere:
- Si può fare affidamento su più di un metodo e la prima chiamata ha effetti collaterali che non è possibile consentire a meno che non esista anche il secondo metodo. Ispezionare l'oggetto anziché eseguirlo nell'eccezione in genere può risolverlo, ma non è necessariamente molto carino.
- Potrebbe essere necessario decidere come trattare l'oggetto in un modo che non dipende da un particolare metodo; ad esempio, potresti voler trattare
unicode
e string
oggetti in modo diverso.
- Gli oggetti potrebbero implementare un metodo con lo stesso nome, ma con significati diversi -
hero.save(hostage)
e file.save(filename)
sono cose completamente indipendenti, ma i nomi dei metodi si scontrano, quindi basta controllare se esiste un metodo chiamato save
può dare falsi positivi.
E poi c'è la situazione in cui devi decidere un percorso di codice basato su più di un oggetto; puoi senz'altro lavorare usando l'approccio del metodo auto-descrittivo, o testando gli attributi rilevanti di tutti gli oggetti, ma a volte, instanceof
è solo più facile da scrivere, più leggibile e più conciso, in altre parole, il pragmatico scelta.