No es necesario adherirse estrictamente a estos principios y no existen sanciones religiosas por violarlos. Pero deberíamos considerar estos principios como señales de alarma. Si se viola uno de ellos, sonará la alarma.
(1) Todos los datos deben estar ocultos dentro de la clase donde se encuentran.
(2) Los usuarios de una clase deben confiar en la interfaz compartida de la clase, pero una clase no puede confiar en sus usuarios.
(3) Minimizar los mensajes en el protocolo de clase.
(4) Implementar la interfaz pública más básica que todas las clases comprendan [por ejemplo, operaciones de copia (copia profunda y copia superficial), juicio de igualdad, contenido de salida correcto, análisis a partir de descripciones ASCII, etc.].
(5) No coloque detalles de implementación (como funciones privadas que colocan código compartido) en la interfaz pública de la clase. Si dos métodos de una clase tienen un código común, puede crear una función privada que evite ese código común.
(6) No perturbar la interfaz pública de la clase con cosas que los usuarios no pueden usar o que no les interesan.
(7) Debe haber acoplamiento cero entre clases, o solo relaciones de acoplamiento derivadas. Es decir, una clase no tiene nada que ver con otra clase o solo utiliza operaciones en la interfaz pública de otra clase.
(8) Una clase debe representar solo una abstracción clave. Todas las clases del paquete deben cerrarse conjuntamente para cambios en el mismo tipo de propiedades. Si un cambio afecta a un paquete, afectará a todas las clases del paquete, pero no tendrá ningún impacto en otros paquetes
(9) Centralice los datos y comportamientos relacionados. Los diseñadores deben tener en cuenta los objetos que obtienen datos de otros objetos mediante operaciones como get. Este tipo de comportamiento implica que se viola este principio empírico.
(10) Poner la información irrelevante en otra categoría (es decir, el comportamiento de no comunicarse entre sí). Haga dependencias hacia la estabilidad
(11) Asegúrese de que los conceptos abstractos que modele sean clases, no solo los roles desempeñados por los objetos.
(12) Distribuya las funciones del sistema de la manera más uniforme posible en la dirección horizontal, es decir: según el diseño, las clases de nivel superior deben compartir el trabajo de manera uniforme.
(13) No cree clases/objetos omnipotentes en su sistema. Tenga especial cuidado con las clases cuyos nombres incluyen Driver, Manager, System y Susystem. Planifique una interfaz en lugar de implementar una interfaz.
(14) Tenga cuidado con las clases que definen una gran cantidad de métodos de acceso en la interfaz pública. Debido a la gran cantidad de métodos de acceso, los datos y comportamientos relevantes no se almacenan de forma centralizada.
(15) Tenga cuidado con las clases que contienen demasiados comportamientos que no se comunican entre sí. Otra manifestación de este problema es la creación de muchas funciones get y set en la interfaz pública de las clases de su aplicación.
(16) En una aplicación que consta de un modelo orientado a objetos que interactúa con la interfaz de usuario, el modelo no debería depender de la interfaz, pero la interfaz debería depender del modelo.
(17) Modele de acuerdo con el mundo real tanto como sea posible (a menudo violamos este principio para cumplir con el principio de distribución de funciones del sistema, evitar el principio de clase de uso múltiple y colocar centralmente datos y comportamientos relevantes).
(18) Elimine las clases innecesarias de su diseño. Generalmente, degradaríamos esta clase a una propiedad.
(19) Eliminar clases fuera del sistema. La característica de las clases fuera del sistema es que, en términos abstractos, solo envían mensajes al dominio del sistema pero no aceptan mensajes de otras clases en el dominio del sistema.
(20) No convierta las operaciones en clases. Cuestione cualquier clase cuyo nombre sea un verbo o se derive de un verbo, especialmente una clase con una sola acción significativa. Considere si ese comportamiento significativo debería trasladarse a una clase que ya existe o que aún no se ha descubierto.
(21) A menudo introducimos clases de proxy al crear modelos de análisis de aplicaciones. Durante la fase de diseño, a menudo nos encontramos con que muchos agentes son inútiles y deberían eliminarse.
(22) Minimizar el número de colaboradores de una clase. El número de otras clases utilizadas por una clase debe mantenerse al mínimo.
(23) Minimizar la cantidad de mensajes pasados entre clases y colaboradores.
(24) Minimizar la cantidad de colaboración entre clases y colaboradores, es decir: reducir la cantidad de mensajes diferentes pasados entre clases y colaboradores.
(25) Minimizar la distribución de la clase, es decir, reducir el producto de la cantidad de mensajes definidos por la clase y la cantidad de mensajes enviados.
(26) Si una clase contiene un objeto de otra clase, la clase contenedora debe enviar un mensaje al objeto contenido. Es decir: una relación de inclusión siempre implica una relación de uso.
(27) La mayoría de los métodos definidos en una clase deberían utilizar la mayoría de los miembros de datos la mayor parte del tiempo.
(28) El número de objetos contenidos en una clase no debe exceder la capacidad de la memoria a corto plazo del desarrollador. Este número suele ser 6. Cuando una clase contiene más de 6 miembros de datos, puede dividir los miembros de datos relacionados lógicamente en un grupo y luego usar una nueva clase contenedora para contener este grupo de miembros.
(29) Dejemos que las funciones del sistema se distribuyan verticalmente en un sistema de herencia estrecho y profundo.
(30) Al implementar restricciones semánticas, es mejor implementarlas de acuerdo con la definición de clase. Esto a menudo conduce a un desbordamiento de la clase, en cuyo caso las restricciones deben implementarse en el comportamiento de la clase, generalmente, pero no necesariamente, en el constructor.
(31) Al implementar restricciones semánticas en el constructor de una clase, coloque la prueba de restricción en el nivel de inclusión más profundo permitido por el dominio del constructor.
(32) Si la información semántica en la que se basan las restricciones cambia con frecuencia, es mejor colocarla en un objeto centralizado de terceros.
(33) Si la información semántica en la que se basan las restricciones rara vez cambia, es mejor distribuirla entre las clases involucradas en las restricciones.
(34) Una clase debe saber qué contiene, pero no puede saber quién lo contiene.
(35) Los objetos que comparten alcance literal (es decir, que están contenidos en la misma clase) no deben tener una relación de uso entre sí.
(36)La herencia sólo debe utilizarse para modelar jerarquías de especialización.
(37) Las clases derivadas deben conocer las clases base, y las clases base no deben conocer ninguna información sobre sus clases derivadas.
(38) Todos los datos de la clase base deben ser privados, no utilice datos protegidos. Los diseñadores de clases nunca deben poner cosas en una interfaz pública que no sean necesarias para los usuarios de la clase.
(39) En teoría, la jerarquía de herencia debería ser más profunda, cuanto más profunda, mejor.
(40) En la práctica, la profundidad de la jerarquía hereditaria no debe exceder la capacidad de memoria a corto plazo de una persona media. Un valor de profundidad ampliamente aceptado es 6.
(41) Todas las clases abstractas deben ser clases base.
(42) Todas las clases base deben ser clases abstractas.
(43) Poner los datos, el comportamiento y/o la interfaz en común lo más alto posible en la jerarquía de herencia.
(44) Si dos o más clases comparten datos comunes (pero ningún comportamiento común), entonces los datos comunes deben colocarse en una clase que esté incluida en cada clase que comparte estos datos.
(45) Si dos o más clases tienen datos y comportamiento comunes (es decir, métodos), entonces cada una de estas clases debe heredar de una clase base común que represente estos datos y métodos.
(46) Si dos o más clases comparten una interfaz común (que se refiere a mensajes, no a métodos), entonces deberían heredar de una clase base común sólo si necesitan usarse polimórficamente.
(47) El análisis caso por caso de la visualización de los tipos de objetos suele ser erróneo. En la mayoría de estos casos, los diseñadores deberían utilizar polimorfismo.
(48) El análisis caso por caso de la visualización de valores de atributos suele ser incorrecto. Las clases deben desacoplarse en una jerarquía de herencia, transformando cada valor de atributo en una clase derivada.
(49) No modele la semántica dinámica de una clase mediante relaciones de herencia. Intentar modelar la semántica dinámica con relaciones semánticas estáticas da como resultado cambios de tipos en tiempo de ejecución.
(50) No convierta objetos de clase en clases derivadas. Tenga cuidado con cualquier clase derivada que tenga una sola instancia.
(51) Si cree que necesita crear una nueva clase en tiempo de ejecución, dé un paso atrás y comprenda que está creando objetos. Ahora, generaliza estos objetos en una clase.
(52) Debería ser ilegal utilizar un método vacío (es decir, un método que no hace nada) en una clase derivada para anular un método en la clase base.
(53) No confunda la inclusión facultativa con la necesidad de herencia. Modelar la inclusión opcional como herencia conduce a una proliferación de clases.
(54) Al crear jerarquías de herencia, intente crear marcos reutilizables en lugar de componentes reutilizables.
(55) Si utiliza la herencia múltiple en su diseño, asuma que ha cometido un error. Si no cometió un error, debe intentar demostrarlo.
(56) Siempre que se utilice la herencia en el diseño orientado a objetos, hágase dos preguntas: (1) ¿Es la clase derivada un tipo especial de lo que hereda? (2) ¿La clase base es parte de la clase derivada?
(57) Si encuentra herencia múltiple en un diseño orientado a objetos, asegúrese de que ninguna clase base sea en realidad una clase derivada de otra clase base.
(58) En el diseño orientado a objetos, si necesita elegir entre inclusión y asociación, elija inclusión.
(59) No utilice datos globales o funciones globales para la contabilidad de objetos de una clase. Se deben utilizar variables de clase o métodos de clase.
(60) Los diseñadores orientados a objetos no deberían permitir que los principios del diseño físico socaven sus diseños lógicos. Sin embargo, a menudo utilizamos criterios de diseño físico al tomar decisiones sobre el diseño lógico.
(61) No omita la interfaz pública para modificar el estado del objeto.