Conceptos básicos del diseño orientado a objetos

Conceptos básicos del diseño orientado a objetos.

Los conceptos básicos del diseño orientado a objetos (DOO) son los pilares fundamentales sobre los que se construyen sistemas de software robustos, flexibles y mantenibles. Estos principios permiten modelar el mundo real de manera natural y eficiente dentro de un programa, traduciendo las entidades y sus comportamientos en elementos de software cohesivos.


1. Objetos


Los objetos son la unidad básica del DOO. Representan entidades del mundo real, encapsulando tanto sus datos (atributos) como las acciones que pueden realizar (métodos). Cada objeto posee un estado interno, definido por sus atributos, y un comportamiento, determinado por sus métodos. 

Un objeto es una entidad física o conceptual del mundo real que proporciona una comprensión del mundo real y, por tanto, forma la base de una solución de software. Un objeto del mundo real puede tener propiedades físicas (se pueden ver o tocar); Algunos ejemplos son una puerta, un motor o una lámpara. Un objeto conceptual es un concepto más abstracto, como una cuenta o transacción.

Las aplicaciones orientadas a objetos constan de objetos. Desde una perspectiva de diseño, un objeto agrupa tanto datos como procedimientos que operan sobre los datos. Los procedimientos suelen denominarse operaciones o métodos. Algunos enfoques, incluida la notación UML, se refieren a la operación como la especificación de una función realizada por un objeto y el método como implementación de la función.

La firma de una operación especifica el nombre de la operación, los parámetros de la operación y el valor de retorno de la operación. La interfaz de un objeto es el conjunto de operaciones que proporciona, según lo definido por las firmas de las operaciones. El tipo de un objeto está definido por su interfaz. La implementación de un objeto está definida por su clase. Por lo tanto, una clase es la implementación de un tipo de datos abstracto.


2. Clases


Una clase es la implementación del objeto real o abstracto. Las clases actúan como plantillas o moldes para crear objetos. Definen las características comunes que comparten un grupo de objetos, estableciendo sus atributos, métodos y relaciones. Una clase funciona como un modelo genérico que se instancia en objetos específicos.

Las clases implementan los métodos y los atributos del objeto. 

Atributo.

Un atributo es una propiedad o característica que define el estado de un objeto. Los atributos son como las variables de una clase, pero con la particularidad de que cada objeto de la clase puede tener valores diferentes para esos atributos.

En otras palabras, los atributos representan las características individuales que diferencian un objeto de otro de la misma clase.

Ejemplo:

Imagina una clase que modela un libro. Los atributos de esta clase podrían ser:

  • Título: El nombre del libro.
  • Autor: La persona que escribió el libro.
  • Número de páginas: La cantidad de páginas que tiene el libro.
  • ISBN: El identificador único del libro.
Cada libro que se cree a partir de esta clase tendrá valores diferentes para estos atributos. Por ejemplo, un libro podría tener como título "Cien años de soledad", como autor a Gabriel García Márquez, 472 páginas y un ISBN 978-84-292-6368-1. Otro libro podría tener un título, un autor, un número de páginas y un ISBN diferentes.

Los atributos se declaran dentro de la definición de la clase. Para acceder a los atributos de un objeto, se utilizan métodos de la clase.

Importancia de los atributos:

  • Los atributos son fundamentales para representar el estado de los objetos en la POO.
  • Permiten diferenciar entre objetos de la misma clase.
  • Se utilizan para almacenar información relevante sobre los objetos.
  • Son esenciales para el funcionamiento de los métodos de la clase.
En resumen, los atributos son un componente clave de la POO que permite modelar objetos del mundo real de manera efectiva y organizada.

Métodos.


Un método es un bloque de código que define el comportamiento de un objeto. Los métodos son como las funciones de un lenguaje de programación, pero con la particularidad de que solo pueden ser invocados desde objetos de la clase a la que pertenecen.

En otras palabras, los métodos representan las acciones que un objeto puede realizar. Se utilizan para manipular los atributos del objeto, interactuar con otros objetos y ejecutar tareas específicas.

Ejemplo:

Siguiendo con el ejemplo de la clase "Libro", podemos definir algunos métodos como:

  • ObtenerTítulo(): Devuelve el título del libro.
  • EstablecerAutor(autor): Establece el autor del libro como el valor especificado en el parámetro "autor".
  • AgregarPagina(): Incrementa el número de páginas del libro en 1.
  • MostrarResumen(): Imprime en pantalla un resumen del libro, incluyendo título, autor, número de páginas e ISBN.

Cada uno de estos métodos realiza una acción específica relacionada con el comportamiento de un libro. Por ejemplo, el método `ObtenerTítulo()` devuelve el valor del atributo "titulo", mientras que el método `AgregarPagina()` modifica el valor del atributo "numeroDePaginas".

Características de los métodos:

  • Pertenecen a una clase: Los métodos se definen dentro de la definición de la clase a la que pertenecen.
  • Reciben y devuelven valores: Los métodos pueden recibir parámetros de entrada y devolver valores de salida.
  • Se invocan desde objetos: Los métodos se invocan utilizando la notación de punto (objeto.metodo()).
  • Pueden ser públicos, privados o protegidos: La accesibilidad de un método define quién puede invocarlo.

Importancia de los métodos:

  • Los métodos son fundamentales para implementar el comportamiento de los objetos en la POO.
  • Permiten encapsular la lógica de las acciones que un objeto puede realizar.
  • Promueven la reutilización de código al permitir crear métodos que pueden ser utilizados por diferentes objetos.
  • Facilitan la organización y mantenibilidad del código.

En resumen, los métodos son una herramienta esencial en la POO que permite definir el comportamiento de los objetos y modular el código de manera efectiva.

Representación.

Las clases se representan en rectángulos.
En la siguiente figura se ilustra tres clases: FiguraGeometrica, Rectangulo y Triangulo.

Note que el nombre de la clase, se encuentra en la parte superior (letras negras), los atributos debajo del nombre (letras rojas) y los métodos, en la última sección (letras verdes).

Es así que la clase Triangulo se conforma de 3 atributos:

  • Lado1: Longitud de un lado.
  • Lado2: Longitud de un lado.
  • Lado3: Longitud de un lado.
 Y un método.
  • GetAltura(): Regresa el valor de la altura del triangulo.

Instancias de una clase.

Una instancia de una clase es la representación concreta de esa clase en la memoria del ordenador. En otras palabras, es un objeto individual creado a partir de una plantilla o molde definido por la clase.

Las instancias son como las copias o materializaciones de la clase, pero con la particularidad de tener valores específicos para sus atributos. Esto significa que cada instancia de la misma clase puede tener un estado diferente, dependiendo de los valores asignados a sus atributos.

Por ejemplo, para la clase triangulo:

  • Lado1 = 3; Lado2 = 4; Lado3 = 6
  • Lado1 = 4; Lado2 = 4; Lado3 = 4
  • Lado1 = 8; Lado2 = 2; Lado3 = 5
Un objeto es una instancia de una clase. Se crean instancias de objetos individuales según sea necesario en el momento de la ejecución. Cada objeto tiene una identidad única, que es la característica que lo distingue de otros objetos. En algunos casos, esta identidad puede ser un atributo (por ejemplo, un número de cuenta o un nombre de cliente), pero no es necesario que sea un atributo. Consideremos dos bolas azules: son idénticas en todos los aspectos; sin embargo, tienen identidades diferentes.

3. Encapsulamiento


El encapsulamiento es el mecanismo que oculta la implementación interna de un objeto, exponiendo solo una interfaz pública para interactuar con él. Esto protege los datos y métodos del objeto de accesos o modificaciones no deseados, promoviendo la modularidad y seguridad del código.

El encapsulamiento de información es un concepto fundamental de diseño de software relevante para el diseño de todos los sistemas de software. Los primeros sistemas eran frecuentemente propensos a errores y difíciles de modificar porque hacían un uso generalizado de datos globales. Se ha demostrado que al ocultar información, los desarrolladores podían diseñar sistemas de software para que fueran sustancialmente más modificables al reducir en gran medida o, idealmente, eliminar los datos globales. Cada módulo de ocultación de información debe ocultar una decisión de diseño que se considera probable que cambie. Cada decisión modificable se llama secreto del módulo. Con este enfoque, se podría lograr el objetivo del diseño para el cambio.


La imagen muestra la clase Triangulo y su código con encapsulamiento es:

package Geometry;

public class Triangulo {

    private double lado1;
    private double lado2;
    private double lado3;

    public Triangulo(double lado1, double lado2, double lado3) throws IllegalArgumentException {
        if (!isValidTriangle(lado1, lado2, lado3)) {
            throw new IllegalArgumentException("Sides must form a valid triangle.");
        }
        this.lado1 = lado1;
        this.lado2 = lado2;
        this.lado3 = lado3;
    }

    private boolean isValidTriangle(double lado1, double lado2, double lado3) {
        // Implement triangle inequality validation (sum of any two sides > third side)
        return (lado1 + lado2 > lado3) && (lado1 + lado3 > lado2) && (lado2 + lado3 > lado1);
    }

    public double getLado1() {
        return lado1;
    }

    public double getLado2() {
        return lado2;
    }

    public double getLado3() {
        return lado3;
    }

    // Implement method to calculate height based on triangle type (optional)
    public double getAltura() {
        // ... (implementation to calculate height based on sides)
    }
}

Note que la función isValidTriangle es privada y tiene como objetivo validar que las longitudes de los lados sean válidas.

Por lo tanto, el diseño de un objeto (o clase) es un proceso de dos pasos: primero diseñar la interfaz, que es la vista externa, y luego diseñar las partes internas. El primer paso es parte del diseño de alto nivel y el segundo paso es parte del diseño detallado. Es probable que este sea un proceso iterativo porque generalmente hay que considerar compensaciones al decidir qué debería ser visible externamente y qué no. Generalmente no es una buena idea revelar todas las variables encapsuladas en un objeto (por ejemplo, mediante operaciones get y set) porque eso significa que se oculta poca información.

4. Herencia

La herencia permite a las clases heredar atributos y métodos de otras clases, creando una jerarquía de clases. Las clases hijas pueden especializar el comportamiento heredado de sus clases padre, añadiendo o redefiniendo métodos, para crear objetos más específicos.

Mas información aquí.


5. Polimorfismo


El polimorfismo permite que objetos de diferentes clases respondan al mismo mensaje de manera distinta. Esto se logra gracias a la sobre escritura de métodos, donde las clases hijas redefinen la implementación de métodos heredados de sus clases padre. El polimorfismo brinda flexibilidad y abstracción al código.

Mas información aquí.


6. Abstracción


La abstracción es el proceso de enfocarse en las características esenciales de un objeto, ignorando detalles de implementación irrelevantes. Permite crear modelos conceptuales que representan el comportamiento fundamental de los objetos sin entrar en complejidades innecesarias.


7. Principios S.O.L.I.D:


Los principios S.O.L.I.D. (Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation, Dependency Inversion) son un conjunto de buenas prácticas para el diseño orientado a objetos que promueven la creación de código más flexible, mantenible y reutilizable.


Beneficios del DOO:


  1. Modularidad: El código se divide en módulos independientes y cohesivos, facilitando su comprensión, modificación y reutilización.
  2. Reutilización: Los componentes de software pueden ser utilizados en diferentes partes del programa o incluso en otros proyectos.
  3. Mantenimiento: Los cambios en el código son más fáciles de realizar y menos propensos a errores, gracias a la encapsulación y la modularidad.
  4. Flexibilidad: El software es más adaptable a nuevos requerimientos y cambios en el entorno.
  5. Claridad: El código es más legible y comprensible, reflejando mejor el problema que se está resolviendo.


El diseño orientado a objetos ha revolucionado la forma en que se desarrolla software, convirtiéndose en un paradigma fundamental para la creación de sistemas complejos, escalables y mantenibles. Al comprender y aplicar los conceptos básicos del DOO, los desarrolladores pueden crear software más robusto, eficiente y adaptable a las necesidades cambiantes del mundo actual.


Bibliografía

Hassan Gomaa. (2011). Software Modeling and Design : UML, Use Cases, Patterns, and Software Architectures. Cambridge University Press.

Comentarios

Entradas más populares de este blog

Principios SOLID

Descomposición arquitectónica de software

Gráficas de Pareto