

System.out.println? ¡Puede descohesionar!La ortogonalidad es aplicable a:
A nivel de diseño, los patrones de diseño y las arquitecturas como MVC facilitan la construcción de componentes ortogonales.
Técnicas de implementación para fomentar la ortogonalidad:
Al pedir un servicio a un objeto, el servicio debe ser realizado de parte nuestra, no que nos devuelva un tercero con el que tratar para realizarlo
public boolean canWrite(User user) {
if (user.isAnonymous())
return false;
else {
return user.getGroup().hasPermission(Permission.WRITE);
}
}
Refactorización: definir un método User.hasPermission()
Los métodos de un objeto solo deben hacer llamadas a métodos...
class Demeter {
private A a;
private int func();
public void example (B b);
void example(B b) {
C c;
int f = func(); // (caso 1)
b.invert(); // (caso 2)
a = new A();
a.setActive(); // (caso 3)
c.print(); // (caso 4)
}
Hay una excepción notable a la prohibición de encadenar llamadas a funciones de la ley de Demeter. Esta regla no aplica si es muy poco probable que haya cambios en las cosas que se encadenan.
En la práctica, cualquier parte de tu aplicación debe considerarse como algo que es probable que cambie; cualquier elemento de una biblioteca de un tercero debe considerarse volátil, en particular si quienes mantienen dicha biblioteca suelen cambiar su API de una versión a otra.
Ejemplos de código como el siguiente son aceptables como excepción a esta interpretación de la ley de Demeter.
¿Por qué?
java.util.List<String> myList =
Arrays.asList("a1", "a2", "b1", "c2", "c1");
myList
.stream()
.filter(s -> s.startsWith("c"))
.map(String::toUpperCase)
.sorted()
.forEach(System.out::println);
Los métodos stream, filter, map, sorted y forEach son parte de las nuevas interfaces funcionales de Java para manejar streams, incorporadas a las colecciones (v.g. List) desde la versión Java 8.
Este tipo de interfaces como la del API de streams de Java se conoce como fluent interfaces.
La ley de Demeter, ¿realmente ayuda a crear código más mantenible?
Pintar un gráfico con los datos registrados por una serie de grabadoras (Recorder) dispersas por el mundo.
Cada grabadora está en una ubicación (Location), que tiene una zona horaria (TimeZone).
Los usuarios seleccionan (Selection) una grabadora y pintan sus datos etiquetados con la zona horaria correcta...
public void plotDate(Date aDate, Selection aSelection) {
TimeZone tz = aSelection.getRecorder().getLocation().getZone();
}
plotDate ⟶ Selection, Recorder, Location, TimeZone.Location de forma que ya no incluye directamente una TimeZone, hay que cambiar plotDategetTimeZone a Selection. Así plotDate no se entera de si la TimeZone le llega desde Recorder o desde un objeto contenido en Recorder.public void plotDate(Date aDate, TimeZone tz) {
/* ... */
}
plotDate(someDate, someSelection.getTimeZone());
Ahora plotDate ⟶ Selection, TimeZone, pero se han eliminado las restantes dependencias.
Muchas bibliotecas actuales implementan la ortogonalidad a través de metadatos, o atributos o etiquetas (@tag), también llamados anotaciones en Java y decoradores en TypeScript.
Los metadatos se emplean para proporcionar propósitos específicos, como v.g. persistencia de objetos, transacciones, etc. Por ejemplo, Spring o EJB utilizan anotaciones @ declarativas para expresar la transaccionalidad de una operación o la persistencia de una propiedad de una clase fuera del método que debe ejecutar dichas funcionalidades.
Otro método para implementar la ortogonalidad es usar Aspectos y Aspect-Oriented Programming (AOP). Este método es empleado por el framework Spring.