Considere si será común tener colecciones de objetos con diferentes combinaciones de habilidades, y si el código podría querer realizar una acción sobre esos elementos, dentro de una colección, que lo respalden . Si es así, y si hubiera un "comportamiento predeterminado" razonable para los objetos que no tienen un soporte útil para alguna acción, puede ser útil tener interfaces implementadas por una amplia gama de clases, no solo aquellas que pueden comportarse de manera útil.
Por ejemplo, supongamos que solo algunos tipos de criaturas pueden tener Woozles, y uno quiere que dichas criaturas tengan una propiedad NumerOfWoozles
. Si tal propiedad estuviera en una interfaz que solo fuera implementada por criaturas que pueden tener Woozles, entonces el código que deseaba encontrar el número total de Woozles en poder de una colección de criaturas de tipos mixtos tendría que decir algo como:
int total = 0;
foreach (object it in creatures)
{
IWoozleCountable w = trycast(it, IWoozleCountable);
if (w != null) total += w.WoozleCount;
}
Sin embargo, si WoozleCount fuera un miembro de Creature / ICreature, aunque pocos subtipos anularían la implementación predeterminada de WoozleCount de Creature que siempre devuelve cero, el código podría simplificarse a:
int total = 0;
foreach (ICreature it in creatures)
total += it.WoozleCount;
Si bien algunas personas pueden molestarse con la idea de que cada Creature implemente una propiedad WoozleCount que solo es realmente útil para algunos subtipos, la propiedad sería significativa para todos los tipos, sea o no útil con elementos que se sabe son de esos tipos, y yo consideraría que la interfaz del "fregadero de la cocina" tiene menos olor a código que el operador de trycast.