Я хотел бы указать на кое-что, что укусило меня за спину, от C ++, где вы также можете легко унаследовать много реализаций.
Наличие «широкого» интерфейса со многими методами означает, что вам придется реализовать множество методов в ваших конкретных классах, и вы не сможете легко делиться этими между реализациями.
Например:
interface Herbivore {
void munch(Vegetable v);
};
interface Carnivore {
void devour(Prey p);
}
interface AllEater : public Herbivore, Carnivore { };
class Fox implements AllEater {
...
};
class Bear implements AllEater {
...
};
В этом примере Fox и Bear не могут совместно использовать общую базовую реализацию для своих методов интерфейса munch
и devour
.
Если базовые реализации выглядят так, мы, возможно, захотим использовать их для Fox
и Bear
:
class ForestHerbivore implements Herbivore
void munch(Vegetable v) { ... }
};
class ForestCarnivore implements Carnivore
void devour(Prey p) { ... }
};
Но мы не можем наследовать оба из них. Базовые реализации должны быть переменными-членами в классе, и определенные методы могут пересылать к этому. То есть:
class Fox implements AllEater {
private ForestHerbivore m_herbivore;
private ForestCarnivore m_carnivore;
void munch(Vegetable v) { m_herbivore.munch(v); }
void devour(Prey p) { m_carnivore.devour(p); }
}
Это становится громоздким, если интерфейсы растут (то есть более 5-10 методов ...)
Лучший подход - определить интерфейс как совокупность интерфейсов:
interface AllEater {
Herbivore asHerbivore();
Carnivore asCarnivore();
}
Это означает, что Fox
и Bear
должны реализовывать только эти два метода, и интерфейсы и базовые классы могут расти независимо от совокупного интерфейса AllEater
, который касается классов реализации.
Меньше связывания таким образом, если это работает для вашего приложения.