Descargar como pdf o txt
Descargar como pdf o txt
Está en la página 1de 23

FICHA DE IDENTIFICACIÓN DE TRABAJO DE INVESTIGACIÓN

Título Principios del paradigma OO


Nombres y Apellidos Código de estudiantes
Josue Coro Orellana 104245
Autor/es Herbert Yosef Luna Ojeda 105270
Javier Gil Banzer 98817
Francesco Amaya Cardona 105596
Fecha 17/03/2024

Carrera Ingenieria de Sistemas


Asignatura Programacion 3
Grupo A
Docente Ing. Waldo Magne Ortega
Periodo Académico 1/2024
Subsede Santa Cruz
Copyright © (2024) por (Josue Coro, Herbert Yosef Luna, Javier Gil Banzer, Francesco Amaya ). Todos los derechos
reservados.

1
Contenido
1. Introducción ...............................................................................................................................3
1.1 Definición de Programación Orientada a Objetos (OOP) ...................................................3
1.2 Programación Orientada a Objetos (OOP) en Python .........................................................3
1.3 Antecedentes y Breve historia y evolución del paradigma OOP.........................................4
1.4 Importancia en el desarrollo de software moderno .............................................................4
1.5 Ventajas y desventajas de la POO ......................................................................................5
2. Fundamentos de la Programación Orientada a Objetos ..............................................................6
2.1 Clases y Objetos .................................................................................................................6
2.2 Clases y Objetos en Python ................................................................................................7
2.3 Principios de diseño de clases.............................................................................................9
2.4 Encapsulamiento .............................................................................................................. 10
2.5 Herencia ........................................................................................................................... 12
2.6 La abstracción .................................................................................................................. 14
2.7 Polimorfismo .................................................................................................................... 16
3. Principios SOLID en la Programación Orientada a Objetos ..................................................... 17
4. Relaciones entre Objetos .......................................................................................................... 19
4.1 Asociación ........................................................................................................................ 19
4.2 Agregación ....................................................................................................................... 20
4.3 Composición .................................................................................................................... 22

2
1. Introducción
La Programación Orientada a Objetos (OOP) se erige como un paradigma esencial en la ingeniería
de software al proporcionar una metodología estructural que organiza el código de manera eficiente.
Este enfoque se fundamenta en el concepto de "objetos", entidades virtuales que encapsulan tanto
datos como comportamientos relacionados entre sí.

En la Programación Orientada a Objetos, cada objeto es una instancia única de una clase, que actúa
como un plano o prototipo para definir las propiedades y acciones que los objetos pueden llevar a
cabo. Este enfoque facilita la conceptualización y modelado de sistemas complejos, al emular de
manera más fiel la realidad y las relaciones entre distintas entidades.

1.1 Definición de Programación Orientada a Objetos (OOP)


La Programación Orientada a Objetos es un enfoque paradigmático que organiza el código en torno
a "objetos", entidades que combinan datos y funciones relacionadas. Estos objetos interactúan entre
sí, facilitando la creación de sistemas más flexibles y modulares.

1.2 Programación Orientada a Objetos (OOP) en Python


La Programación Orientada a Objetos (OOP) en Python es un enfoque de programación que se basa
en el concepto de "objetos", los cuales son instancias de clases que combinan datos y funciones
relacionadas. Python es un lenguaje que admite la OOP de manera integral, lo que significa que
permite la creación y manipulación de objetos, así como la implementación de conceptos
fundamentales de la OOP, como encapsulación, herencia, polimorfismo y abstracción.

En Python, las clases actúan como plantillas para la creación de objetos, definiendo sus atributos
(datos) y métodos (funciones). Los objetos interactúan entre sí mediante el intercambio de mensajes,
lo que permite una programación más modular y flexible.

La OOP en Python ofrece una serie de ventajas, como la reutilización de código, la modularidad, la
facilidad para mantener y actualizar el código, y la capacidad para modelar de manera eficiente
sistemas complejos. Esto la convierte en una opción popular para el desarrollo de una amplia gama
de aplicaciones, desde aplicaciones web hasta sistemas de inteligencia artificial.

3
1.3 Antecedentes y Breve historia y evolución del paradigma OOP
La Programación Orientada a Objetos (POO) surge a finales de la década de 1960 como una respuesta
a las limitaciones de la programación tradicional, como la dificultad para mantener y reutilizar código.

Los principales antecedentes de la POO son:

 Simula, un lenguaje de programación desarrollado en la década de 1960 para simulaciones


de sistemas. Simula introdujo los conceptos de clase y objeto, sentando las bases para la POO.
 Smalltalk, un lenguaje de programación desarrollado en la década de 1970 por el Laboratorio
de Investigación de Xerox Palo Alto. Smalltalk es considerado el primer lenguaje de
programación orientado a objetos puro.

Fue en la década de 1980 con la popularización de lenguajes como C++ y Java que OOP alcanzó su
prominencia. Desde entonces, ha evolucionado constantemente con contribuciones significativas de
la comunidad de desarrollo.

1.4 Importancia en el desarrollo de software moderno


La OOP desempeña un papel crucial en el desarrollo de software moderno debido a su capacidad para
modelar el mundo real de manera más efectiva. Facilita la reutilización de código, mejora la
mantenibilidad y promueve la colaboración en equipos de desarrollo. Además, el modularidad
inherente de la OOP permite la adaptación ágil a cambios en los requisitos del software, lo que lo
convierte en un paradigma fundamental en el desarrollo de sistemas robustos y escalables.

4
1.5 Ventajas y desventajas de la POO
Ventajas:

1. Facilidad de mantenimiento:

 La POO facilita la organización del código en módulos independientes, lo que hace que sea
más fácil de entender y mantener.

 Los cambios en una clase o un objeto solo afectan a esa clase o objeto, lo que reduce el riesgo
de errores y facilita la corrección de errores.

2. Reutilización del código:

 Las clases y objetos pueden ser reutilizados en diferentes proyectos, lo que ahorra tiempo y
esfuerzo.

 Las bibliotecas de clases predefinidas proporcionan una amplia gama de funcionalidades que
pueden ser utilizadas directamente en los proyectos.

3. Extensibilidad:

 La POO facilita la creación de nuevas clases que heredan de las clases existentes, lo que
permite ampliar la funcionalidad de las clases existentes.

 Esto facilita la adaptación del código a nuevas necesidades y requisitos.

4. Modularidad:

 La POO facilita la organización del código en módulos independientes, lo que hace que sea
más fácil de probar y depurar.

 Los módulos independientes pueden ser desarrollados y probados por separado, lo que reduce
el tiempo de desarrollo y mejora la calidad del código.

Desventajas:

1. Complejidad:

 La POO puede ser más compleja de aprender y entender que la programación tradicional.

 El uso de clases, objetos, herencia y polimorfismo puede ser un desafío para los principiantes.

2. Eficiencia:

5
 La POO puede ser menos eficiente que la programación tradicional en algunos casos.

 El uso de clases, objetos y herencia puede generar un código más grande y lento.

3. Curva de aprendizaje:

 La POO tiene una curva de aprendizaje más pronunciada que la programación tradicional.

 Se requiere tiempo y esfuerzo para dominar los conceptos de la POO y poder utilizarlos de
forma eficaz.

4. Curva de aprendizaje más pronunciada:

 Dominar la POO requiere un mayor tiempo de estudio y práctica que la programación


tradicional.

 Esto puede ser un obstáculo para los principiantes o para aquellos que no tienen mucho
tiempo para dedicarse a la programación.

2. Fundamentos de la Programación Orientada a Objetos


2.1 Clases y Objetos
a. Definición y Relación:

 Clase: En Programación Orientada a Objetos, una clase funciona como un plano o


plantilla que define las propiedades y comportamientos comunes a un grupo de
objetos. Se considera un concepto abstracto porque no representa una instancia
específica, sino más bien el conjunto de características compartidas por los objetos
pertenecientes a esa clase. Tomemos como ejemplo la clase "Automóvil": esta puede
contener propiedades como modelo, color y año, así como métodos para arrancar y
detener.

 Objeto: Un objeto, por otro lado, es una instancia particular de una clase. Es una
entidad concreta que posee características específicas y puede realizar acciones de
acuerdo con lo definido por la clase a la que pertenece. Volviendo al ejemplo, un
objeto específico podría ser un "Automóvil Toyota Rojo". Aquí, el objeto hereda las
propiedades y métodos definidos en la clase "Automóvil" y las adapta a sus
características únicas, como el modelo específico y el color.

6
b. Propiedades y Métodos:

 Propiedades: Las propiedades son atributos que describen las características del
objeto. En el contexto del automóvil, las propiedades pueden incluir detalles como
el modelo, el color, el año de fabricación, el número de puertas, etc. Estas
propiedades encapsulan la información esencial que define al objeto.

 Métodos: Los métodos son funciones o acciones que un objeto puede llevar a cabo.
En el caso del automóvil, los métodos pueden ser funciones como arrancar, detener,
acelerar, frenar, etc. Estos métodos definen el comportamiento del objeto y cómo
interactúa con su entorno. Pueden modificar las propiedades del objeto o realizar
acciones específicas asociadas con ese objeto en particular.

2.2 Clases y Objetos en Python


Clases:
En Python, una clase es una plantilla que define las propiedades y comportamientos de los objetos.
Se define mediante la palabra clave class, seguida del nombre de la clase y, opcionalmente, una lista
de clases base entre paréntesis. Dentro de una clase, se pueden definir atributos (variables) y métodos
(funciones) que describen el estado y el comportamiento de los objetos creados a partir de esa clase.

Objetos:

Un objeto es una instancia de una clase. Se crea mediante la invocación del constructor de la clase,
que se llama __init__() en Python. Los objetos tienen acceso a los atributos y métodos definidos en
su clase.

La Programación Orientada a Objetos en Python permite la creación de clases y objetos para modelar
entidades del mundo real de manera efectiva, lo que facilita la creación de sistemas más complejos y
modulares.

class Persona:
# Constructor
def _init_(self):
self.ci = None
self.nombre = None
self.ap_pat = None

7
self.ap_mat = None

# Metodos set
def set_ci(self, ci):
self.ci = ci

def set_nombre(self, nombre):


self.nombre = nombre

def set_ap_pat(self, ap_pat):


self.ap_pat = ap_pat

def set_ap_mat(self, ap_mat):


self.ap_mat = ap_mat

# Metodos get
def get_ci(self):
return self.ci

def get_nombre(self):
return self.nombre

def get_ap_pat(self):
return self.ap_pat

def get_ap_mat(self):
return self.ap_mat

# Otros Metodos
def saludar(self):
print(f"Hola, soy {self.nombre} y tengo {self.edad} años.")

8
def nombre_completo(self):
if self.nombre == None:
return "Introducir los datos de la persona"
else:
nombre_com = (
f"Carnet de identidad: {str(self.ci)}\n "
f"Nombre: {str(self.nombre)}\n"
f"Ap. Paterno: {str(self.ap_pat)}\n"
f"Ap. Materno: {str(self.ap_mat)}"
)
return nombre_com

people = Persona()
people.set_ci(123456)
people.set_nombre("Josue")
people.set_ap_pat("Coro")
people.set_ap_mat("Orellana")

print(
f"Carnet de identidad: {people.get_ci()} \n Nombre: {people.get_nombre()} \n ap_paterno:
{people.get_ap_pat()} \n ap_materno: {people.get_ap_mat()}")

En este ejemplo, Persona es una clase que tiene varios atributos (nombre, CI, Apellido paterno,
Apellido materno) y un método (saludar()).

2.3 Principios de diseño de clases


Reutilización

La reutilización es un principio fundamental del diseño de clases que busca crear clases que puedan
ser utilizadas en diferentes proyectos. Para lograr esto, las clases deben ser:

 Genéricas: No deben depender de detalles específicos de un solo proyecto.

9
 Modulares: Deben estar bien organizadas en módulos independientes.
 Extensibles: Deben ser fáciles de modificar y ampliar.
 Documentadas: Deben tener una documentación clara y completa
Técnicas para la reutilización:
 Herencia: Permite crear nuevas clases que heredan las características y el
comportamiento de clases existentes.
 Interfaces: Definen contratos que deben ser implementados por las clases.
 Composición: Permite crear objetos complejos a partir de objetos más simples.
 Patrones de diseño: Proporcionan soluciones reutilizables a problemas comunes de
diseño de software.

Cohesión (ampliado)
La cohesión es un principio fundamental del diseño de clases que se refiere a la fuerza con la que los
elementos (atributos y métodos) de una clase están relacionados entre sí. Una clase con alta cohesión
tiene un único propósito bien definido y todos sus elementos trabajan juntos para lograr ese propósito.

Niveles de cohesión:
 Alta cohesión: Todos los elementos de la clase están estrechamente relacionados y
trabajan juntos para lograr un único objetivo.
 Cohesión media: Algunos elementos de la clase no están directamente relacionados con
el propósito principal de la clase, pero aún pueden ser útiles.
 Baja cohesión: Los elementos de la clase no están relacionados entre sí y la clase tiene
múltiples responsabilidades.

Beneficios de la alta cohesión:

 Mayor facilidad de comprensión: Las clases con alta cohesión son más fáciles de entender
y mantener.
 Menor probabilidad de errores: Las clases con alta cohesión son menos propensas a tener
errores debido a la menor interacción entre diferentes funcionalidades.
 Mayor reusabilidad: Las clases con alta cohesión son más fáciles de reutilizar en
diferentes contextos.

2.4 Encapsulamiento
1. Concepto y Beneficios:

10
 Encapsulamiento: Es el principio de ocultar los detalles internos de un objeto y
exponer solo lo necesario para su interacción. Se logra mediante la definición de
propiedades y métodos como públicos, privados o protegidos. La encapsulación es
un principio fundamental de la POO que consiste en ocultar los detalles de
implementación de un objeto a los demás objetos.

2. Encapsulamiento en Python

El encapsulamiento es un concepto de la Programación Orientada a Objetos que consiste en ocultar


los detalles internos de un objeto y permitir el acceso a sus atributos y métodos solo a través de
interfaces controladas. En Python, el encapsulamiento se logra mediante el uso de modificadores de
acceso y convenciones de nomenclatura para indicar la visibilidad de los atributos y métodos de una
clase.

En Python, se utiliza una convención de nomenclatura para indicar la visibilidad de los atributos y
métodos de una clase:

Los atributos y métodos que comienzan con un guion bajo ( _ ) se consideran como miembros
protegidos y no deben ser accedidos directamente desde fuera de la clase.

Los atributos y métodos que comienzan con dos guiones bajos ( __ ) se consideran como miembros
privados y no deben ser accedidos directamente desde fuera de la clase. Sin embargo, Python cambia
el nombre de estos miembros en tiempo de ejecución agregando el nombre de la clase al principio, lo
que dificulta el acceso desde fuera de la clase.

class Persona:
def __init__(self, nombre, edad):
self._nombre = nombre # atributo protegido
self.__edad = edad # atributo privado

def saludar(self):
print(f"Hola, soy {self._nombre} y tengo {self.__edad} años.")

# Crear un objeto de la clase Persona

11
persona1 = Persona("Juan", 30)

# Acceder a atributos (encapsulamiento protegido)


print(persona1._nombre) # Output: Juan

3. Características:

 Ocultamiento de información: Los detalles internos de un objeto no son accesibles


para los demás objetos.

 Acceso controlado: Los objetos solo pueden acceder a los datos y métodos de otros
objetos a través de interfaces públicas.

 Modificación sin afectar a otros objetos: Los cambios en la implementación


interna de un objeto no afectan a los demás objetos que lo utilizan.

2.5 Herencia
La herencia es un concepto clave en la Programación Orientada a Objetos (POO) que permite a
una clase, denominada subclase o clase hija, heredar las propiedades y comportamientos de otra
clase, conocida como superclase o clase padre. Este mecanismo proporciona una forma de
reutilizar y extender el código, promoviendo la creación de jerarquías de clases más ricas y
especializadas.

En Python, la herencia se establece al definir una clase y especificar su superclase entre paréntesis
en la definición de la clase. La subclase hereda todos los atributos y métodos de la superclase y
puede agregar nuevos atributos y métodos, o incluso sobrescribir los métodos existentes para
modificar su comportamiento.

import Persona as per

class Estudiante(per.Persona):
def __init__(self):
# Llamar un metodo de la clase padre al constructor de la clase que herede
super().__init__()
self.codigo_estudiante = None
self.correo_institucional = None
self.seguro = None

def set_codigo_estudiante(self, codigo):

12
self.codigo_estudiante = codigo

def set_correo_institucional(self, correo_institucional):


self.correo_institucional = correo_institucional

def set_seguro(self, seguro):


self.seguro = seguro

def get_codigo_estudiante(self):
return self.codigo_estudiante

def get_correo_institucional(self):
return self.correo_institucional

def get_seguro(self):
return self.seguro

import Estudiante

from tkinter.messagebox import *

#crear la instancia estudiante

estudiante = Estudiante.Estudiante()
# es metodo de la clase persona que hereda a la clase estudiante

estudiante.set_ci(13540503)
estudiante.set_nombre("Josue")
estudiante.set_ap_pat("Coro")
estudiante.set_ap_mat("Orellana")
#los metodos de la clase estudiante

estudiante.set_codigo_estudiante(104245)
estudiante.set_correo_institucional("[email protected]")
estudiante.set_seguro(True)

# Cuadro de mensaje

showinfo("Datos del estudiante",


str(estudiante.nombre_completo()+"\n"+
"Codigo: "+str(estudiante.get_codigo_estudiante())+"\n"+
"Correo Institucional: "+str(estudiante.get_correo_institucional())))

1. Herencia Simple y Múltiple:

 Herencia Simple: En la herencia simple, una clase puede heredar atributos y


métodos de una única clase padre. Esto significa que la subclase tiene acceso a los
miembros de la superclase, pudiendo extenderlos o modificarlos según sea necesario.
Tomemos el ejemplo de una clase "Estudiante" que hereda de la clase "Persona". La
clase "Estudiante" heredaría las propiedades generales de una persona, como nombre

13
y edad, y también podría tener sus propias propiedades específicas de un estudiante,
como el número de estudiante y la especialidad.

 Herencia Múltiple: En contraste, la herencia múltiple permite que una clase herede
de más de una clase padre. En el ejemplo, una clase "Estudiante" podría heredar tanto
de la clase "Persona" como de la clase "Curso". Esto implica que la clase "Estudiante"
tendría acceso tanto a las propiedades generales de una persona como a las
específicas de un curso. La herencia múltiple puede ser poderosa, pero también puede
introducir complejidades en el diseño y la resolución de conflictos si varias clases
padre tienen métodos o propiedades con el mismo nombre.

2. Ventajas de la herencia

 Reutilización del código: La herencia facilita la reutilización del código al permitir


que las clases hereden de clases existentes.
 Extensibilidad: La herencia facilita la extensión del código al permitir que las clases
se especialicen a partir de clases generales.
 Mantenimiento: La herencia facilita el mantenimiento del código al permitir que los
cambios se realicen en un solo lugar.

2.6 La abstracción
La abstracción es un concepto fundamental en la Programación Orientada a Objetos que se refiere a
la capacidad de representar las características esenciales de un objeto, mientras se ocultan los detalles
complejos o irrelevantes de su implementación interna. En otras palabras, la abstracción permite
enfocarse en los aspectos relevantes de un objeto y sus interacciones, sin necesidad de conocer todos
los detalles de cómo se implementa.

En la práctica, la abstracción se logra mediante la creación de clases que definen un conjunto de


atributos y métodos que representan las propiedades y comportamientos esenciales de un objeto. Estas
clases actúan como modelos o plantillas que pueden ser utilizadas para crear instancias de objetos
específicos.

Abstracción en Python

La abstracción en Python se refiere a la capacidad de crear clases y objetos que representan entidades
del mundo real de manera simplificada, centrándose en sus aspectos esenciales y ocultando los
detalles complejos de su implementación interna. En la Programación Orientada a Objetos (OOP) en

14
Python, la abstracción se logra mediante la definición de clases que encapsulan datos (atributos) y
comportamientos (métodos) relevantes para el objeto, sin exponer la complejidad de cómo se
implementan esos datos y comportamientos.

Por ejemplo, supongamos que queremos representar un vehículo en Python. Podemos crear una clase
llamada Vehiculo que tenga atributos como marca, modelo y color, y métodos como acelerar y frenar.
Estos métodos encapsularían la lógica para mover el vehículo hacia adelante o detenerlo, pero los
detalles internos de cómo se logra esto (por ejemplo, mediante un motor de combustión interna o un
motor eléctrico) se ocultan dentro de la clase Vehiculo.

A través de la abstracción, podemos crear instancias de la clase Vehiculo y utilizarlas en nuestro


código sin necesidad de conocer los detalles internos de su implementación. Esto facilita el desarrollo
de software al permitirnos trabajar a un nivel más alto de abstracción, centrándonos en el
comportamiento y las interacciones de los objetos en lugar de preocuparnos por la complejidad de su
implementación subyacente.

class Vehiculo:
def __init__(self, marca, modelo, color):
self.marca = marca
self.modelo = modelo
self.color = color

def acelerar(self):
print(f"{self.marca} {self.modelo} acelerando...")

def frenar(self):
print(f"{self.marca} {self.modelo} frenando...")

# Crear una instancia de la clase Vehiculo


mi_vehiculo = Vehiculo("Toyota", "Corolla", "Rojo")

# Utilizar los métodos del objeto


mi_vehiculo.acelerar()
mi_vehiculo.frenar()

15
2.7 Polimorfismo
Definición y tipos de polimorfismo

El polimorfismo es un concepto central en la Programación Orientada a Objetos (POO) que aporta


flexibilidad y adaptabilidad al código. En su esencia, el polimorfismo permite que un objeto pueda
comportarse de varias maneras diferentes en distintos contextos, dependiendo de su tipo o de las
características del entorno en el que se encuentra.

En Python, el polimorfismo se logra mediante el uso de métodos con el mismo nombre en diferentes
clases. Cuando se llama a un método en un objeto, Python determina qué versión del método utilizar
según el tipo de objeto en tiempo de ejecución.

class Animal:
def hacer_sonido(self):
pass # Método abstracto

class Perro(Animal):
def hacer_sonido(self):
return "Guau!"

class Gato(Animal):
def hacer_sonido(self):
return "Miau!"

# Función que utiliza polimorfismo


def hacer_sonido_animal(animal):
return animal.hacer_sonido()

# Crear objetos de diferentes clases


mi_perro = Perro()
mi_gato = Gato()

# Utilizar la función con diferentes objetos


print(hacer_sonido_animal(mi_perro)) # Output: Guau!

16
print(hacer_sonido_animal(mi_gato)) # Output: Miau!
Tipos de polimorfismo:

 Polimorfismo de sobrecarga: El polimorfismo de sobrecarga se manifiesta cuando existen


dos o más métodos con el mismo nombre dentro de una clase, pero con diferentes parámetros.
Esto significa que la clase puede realizar acciones similares sobre diferentes tipos de datos o
con diversas configuraciones. La decisión sobre qué método utilizar se toma en tiempo de
compilación basándose en la cantidad y tipo de parámetros. Este tipo de polimorfismo se
conoce también como polimorfismo ad-hoc.

 Polimorfismo de subtipo: El polimorfismo de subtipo, también llamado herencia


polimórfica, se basa en la capacidad de una clase derivada para reemplazar el comportamiento
de un método heredado de su clase base. En otras palabras, una subclase puede proporcionar
una implementación específica de un método que ha heredado de su clase padre. Esto permite
una mayor flexibilidad y especialización en el código, ya que las clases derivadas pueden
adaptar o extender el comportamiento de los métodos heredados.

Ventajas del Polimorfismo:

 Flexibilidad: Permite que el código se adapte a diferentes situaciones sin necesidad de


modificaciones significativas.
 Reutilización del código: Facilita la creación de código modular y reutilizable al abstraer
el comportamiento en diferentes clases.
 Mantenimiento del código: Simplifica el mantenimiento del código al centralizar la
lógica en métodos específicos.
 Extensibilidad: Permite la creación de nuevas clases que heredan y extienden el
comportamiento de las clases existentes.

3. Principios SOLID en la Programación Orientada a Objetos

3.1 Single Responsibility Principle (SRP):

El Principio de Responsabilidad Única destaca la importancia de que una clase tenga una única razón
para cambiar, es decir, una única responsabilidad en el sistema. Esto se traduce en clases que se
centran exclusivamente en una tarea específica. Al seguir el SRP, se mejora la modularidad del código
y se facilita su mantenimiento. Una clase que se ocupa de la manipulación de archivos, por ejemplo,

17
debería estar enfocada solo en esa tarea y no asumir responsabilidades adicionales, como la
manipulación de datos.

3.2 Open/Closed Principle (OCP):

El Principio Abierto/Cerrado aboga por la extensibilidad del código sin modificar su código fuente
original. Para lograr esto, las clases y módulos se diseñan de manera que puedan extenderse para
agregar nuevas funcionalidades sin alterar el código existente. Esto promueve la adaptabilidad del
sistema a cambios y mejoras, reduciendo el riesgo de introducir errores en código previamente
funcional. La extensibilidad se logra mediante la creación de clases abiertas para la extensión, pero
cerradas para la modificación.

3.3 Liskov Substitution Principle (LSP):

El Principio de Sustitución de Liskov se centra en mantener la coherencia en las jerarquías de clases.


Establece que una instancia de una subclase debe poder sustituirse por una instancia de su superclase
sin afectar la lógica del programa. Esto asegura que las subclases cumplan con las expectativas
establecidas por sus superclases, garantizando la consistencia en el comportamiento de los objetos.
En otras palabras, las subclases deben ser verdaderas extensiones de sus superclases, sin cambiar la
semántica del programa.

3.4 . Interface Segregation Principle (ISP):

El Principio de Segregación de Interfaces aborda el diseño de interfaces para evitar que las clases se
vean obligadas a implementar métodos que no utilizan. En lugar de interfaces monolíticas, se favorece
la creación de interfaces más pequeñas y específicas para cada contexto. Esto evita que las clases
implementen funcionalidades innecesarias, promoviendo una mayor cohesión y evitando la violación
del SRP. Las interfaces deben ser client-specific y no contener métodos que el cliente no necesite.

3.5 Dependency Inversion Principle (DIP):

El Principio de Inversión de Dependencias propone que las dependencias se establezcan en


abstracciones en lugar de detalles concretos. Los módulos de alto nivel no deben depender
directamente de módulos de bajo nivel, sino de interfaces o abstracciones. Esto reduce el
acoplamiento y facilita la sustitución de implementaciones sin afectar el código de alto nivel. Además,
evita que cambios en los módulos de bajo nivel afecten a los de alto nivel. La inversión de
dependencias se logra a través de la introducción de interfaces y abstracciones que actúan como
contratos entre módulos.

18
4. Relaciones entre Objetos
4.1 Asociación
La asociación es una relación entre dos o más objetos donde cada uno puede existir de manera
independiente del otro. Esta relación puede ser temporal o permanente y es bidireccional. En la
asociación, los objetos interactúan entre sí, pero no están directamente vinculados en términos de
pertenencia. Pueden referirse entre sí para cumplir con ciertos objetivos, pero no comparten una
dependencia fuerte. Las asociaciones pueden ser de varios tipos, como uno a uno, uno a muchos o
muchos a muchos.

La asociación en Python es una relación entre dos o más objetos donde cada objeto puede existir de
manera independiente del otro, pero interactúan entre sí para lograr un objetivo común. En la
asociación, los objetos se relacionan de forma bidireccional, y pueden tener una relación temporal o
permanente. Esta relación se establece mediante el uso de referencias entre los objetos.

class Estudiante:
def __init__(self, nombre):
self.nombre = nombre

def estudiar(self):
return f"{self.nombre} está estudiando."

class Curso:
def __init__(self, nombre):
self.nombre = nombre

def agregar_estudiante(self, estudiante):


return f"Se ha agregado a {estudiante.nombre} al curso de {self.nombre}."

# Crear objetos de las clases


estudiante1 = Estudiante("Juan")
curso1 = Curso("Matemáticas")

# Establecer una asociación entre los objetos

19
print(curso1.agregar_estudiante(estudiante1)) # Output: Se ha agregado a Juan al curso de
Matemáticas.
print(estudiante1.estudiar()) # Output: Juan está estudiando.
Ejemplo de Asociación:

 En un sistema de gestión escolar, la relación entre las clases Estudiante y Curso puede
considerarse una asociación. Un estudiante puede estar asociado con varios cursos y, a
su vez, un curso puede tener múltiples estudiantes asociados.

 Uno a uno: Un Estudiante tiene un único Carnet.

Uno a muchos: Un Profesor tiene varios Estudiantes.

Muchos a muchos: Un Estudiante puede tomar varios Cursos, y un Curso puede tener
varios Estudiantes.

4.2 Agregación
La agregación es una relación más fuerte que la asociación. En una relación de agregación, un objeto
puede estar compuesto por varios sub objetos, pero esos sub objetos pueden existir de manera
independiente. La relación de agregación se representa a menudo mediante un diamante negro en los
diagramas UML. La destrucción del objeto principal no implica necesariamente la destrucción de los
objetos agregados.

La agregación en Python es una relación entre dos objetos donde un objeto contiene una referencia a
otro objeto, pero ambos pueden existir de forma independiente. En la agregación, un objeto puede
estar compuesto por varios subobjetos, pero esos subobjetos pueden existir fuera del objeto principal.
La agregación se utiliza para modelar relaciones del tipo "todo-parte", donde el objeto principal es el
"todo" y los objetos secundarios son las "partes".

class Rueda:
def __init__(self, modelo):
self.modelo = modelo

class Automovil:
def __init__(self, marca):
self.marca = marca
self.ruedas = [] # Lista para almacenar las ruedas del automóvil

20
def agregar_rueda(self, rueda):
self.ruedas.append(rueda)

# Crear objetos de las clases


rueda1 = Rueda("Michelin")
rueda2 = Rueda("Goodyear")
automovil = Automovil("Toyota")

# Establecer una relación de agregación


automovil.agregar_rueda(rueda1)
automovil.agregar_rueda(rueda2)

# Acceder a los atributos de los objetos agregados


for i, rueda in enumerate(automovil.ruedas, start=1):
print(f"Rueda {i}: Modelo {rueda.modelo} - Marca del automóvil: {automovil.marca}")

En este ejemplo, la clase Automovil representa el objeto principal que contiene una lista de objetos
Rueda. La relación de agregación se establece cuando se agregan las ruedas al automóvil mediante el
método agregar_rueda(). Aunque las ruedas están asociadas con el automóvil, pueden existir de forma
independiente. La agregación se utiliza comúnmente para modelar relaciones de composición, como
en este caso, donde un automóvil está compuesto por varias ruedas.

Ejemplo de Agregación:

 En el contexto de una biblioteca, la relación entre una clase Biblioteca y Libros puede ser
una agregación. La biblioteca puede contener varios libros, y estos libros pueden existir
fuera de la biblioteca.

 Un coche tiene un motor, ruedas, asientos y otras partes.

Un libro tiene capítulos, páginas, portada y contraportada.

21
4.3 Composición
La composición es la relación más fuerte entre objetos. En una relación de composición, un objeto
está formado por la combinación de varios subobjetos, y la existencia del objeto principal implica la
existencia de los subobjetos. La composición se representa a menudo mediante un diamante negro
lleno en los diagramas UML. La destrucción del objeto principal implica la destrucción de los objetos
compuestos.

La composición en Python es una relación entre dos objetos donde un objeto está formado por la
combinación de varios subobjetos y la existencia del objeto principal implica la existencia de los
subobjetos.

class Motor:
def __init__(self, tipo):
self.tipo = tipo

class Automovil:
def __init__(self, marca, modelo):
self.marca = marca
self.modelo = modelo
self.motor = Motor("Gasolina") # Objeto de la clase Motor como parte del automóvil

def descripcion(self):
return f"Automóvil {self.marca} {self.modelo} con motor {self.motor.tipo}"

# Crear un objeto de la clase Automovil


mi_automovil = Automovil("Toyota", "Corolla")

# Acceder a los atributos del automóvil y su motor


print(mi_automovil.descripcion()) # Output: Automóvil Toyota Corolla con motor Gasolina
En este ejemplo, la clase Automovil está compuesta por un objeto de la clase Motor, que representa
el motor del automóvil. La relación de composición se establece cuando se crea un objeto de la clase
Motor dentro del constructor de la clase Automovil. En este caso, el motor es una parte esencial del

22
automóvil y no puede existir independientemente de él. La composición se utiliza para modelar
relaciones más fuertes entre objetos, donde los subobjetos forman parte integral del objeto principal.

Ejemplo de Composición:

 Si consideramos un modelo de un automóvil, la relación entre Automovil y Motor puede


ser una composición. El motor es una parte esencial del automóvil, y la destrucción del
automóvil implica la destrucción del motor.

 Un cuerpo humano tiene órganos, células y tejidos.

 Un edificio tiene paredes, puertas, ventanas y techo.

23

También podría gustarte