Quello che vuoi sono Interfacce.
Ogni interfaccia può richiedere una caratteristica. Una classe può implementare più interfacce a piacimento:
interface Foo {
boolean doFoo();
}
interface Bar {
boolean doBar();
}
class fooImpl implements Foo {
boolean doFoo(){
. . .
}
}
class barImpl implements Bar {
boolean doBar(){
. . .
}
}
class fooBarImpl implements Foo, Bar {
boolean doFoo(){
. . .
}
boolean doBar(){
. . .
}
}
Aggiorna
In alternativa, implementa il modello di stato . Uno stato sarebbe HasABar e fornirebbe il comportamento desiderato per quando il tuo Foo ha una barra. Un altro stato potrebbe essere HasABat, che fornisce un comportamento diverso. Il tuo oggetto Foo può iniziare con HasNothing, finché non gli dai una barra, che cambierebbe lo stato in HasABar.
interface FooState {
Drink getDrink() throws InvalidStateException;
}
class HasNothing implements FooState {
Foo foo;
HasNothing(Foo foo) {
this.foo = foo;
}
Drink getDrink() throws InvalidStateException {
throw new InvalidStateException("There's no Bar");
}
}
class HasABar implements FooState {
Foo foo;
HasABar(Foo foo) {
this.foo = foo;
}
Drink getDrink() throws InvalidStateException{
Foo foo.getBar().getDrink();
}
}
class Foo {
FooState state;
Bar bar;
public Foo() {
state = new HasNothing(this);
}
Bar getBar() {
return bar;
}
void setBar(Bar bar) {
this.Bar = bar;
if (null != bar) {
state = new HasABar(this);
}
else {
state = new HasNothing(this);
}
}
Drink getDrink() throws InvalidStateException{
return state.getDrink();
}
}
A questo punto non ti occupi veramente di sottotipi, hai un tipo che si comporta in modo diverso a seconda dello stato durante il runtime.