La pro­gra­ma­ción orientada a objetos (OOP) se utiliza en todas partes. Las te­c­no­lo­gías orie­n­ta­das a objetos se emplean para escribir sistemas ope­ra­ti­vos, software comercial y de código abierto. Sin embargo, las ventajas de la pro­gra­ma­ción orientada a objetos solo se ponen de ma­ni­fie­s­to cuando el proyecto alcanza un cierto nivel de co­m­ple­ji­dad. El estilo de pro­gra­ma­ción orientado a objetos sigue siendo uno de los pa­ra­di­g­mas de pro­gra­ma­ción pre­do­mi­na­n­tes.

¿Qué es la pro­gra­ma­ción orientada a objetos y para qué es necesaria?

El término “pro­gra­ma­ción orientada a objetos” se acuñó a finales de los años sesenta por la leyenda de la pro­gra­ma­ción Alan Kay, co­de­sa­rro­lla­dor del pionero lenguaje de pro­gra­ma­ción orientado a objetos Smalltalk. Este lenguaje, a su vez, había recibido la in­flue­n­cia­do de Simula, el primer lenguaje con ca­ra­c­te­rí­s­ti­cas OOP. Las ideas fu­n­da­me­n­ta­les de Smalltalk siguen in­flu­ye­n­do en las ca­ra­c­te­rí­s­ti­cas de OOP en los lenguajes de pro­gra­ma­ción modernos como Ruby, Python, Go y Swift.

La pro­gra­ma­ción orientada a objetos se sitúa junto a la popular pro­gra­ma­ción funcional entre los pa­ra­di­g­mas de pro­gra­ma­ción pre­do­mi­na­n­tes. Los enfoques de pro­gra­ma­ción pueden cla­si­fi­car­se en dos grandes co­rrie­n­tes: “im­pe­ra­ti­va” y “de­cla­ra­ti­va”. La OOP es una variante del estilo de pro­gra­ma­ción im­pe­ra­ti­vo y, co­n­cre­ta­me­n­te, un de­sa­rro­llo posterior de la pro­gra­ma­ción pro­ce­di­me­n­tal:

  1. Pro­gra­ma­ción im­pe­ra­ti­va: describe en pasos in­di­vi­dua­les cómo resolver un problema. Ejemplo: Algoritmo
  • Pro­gra­ma­ción es­tru­c­tu­ra­da
    • Pro­gra­ma­ción pro­ce­di­me­n­tal
      • Pro­gra­ma­ción orientada a objetos
  1. Pro­gra­ma­ción de­cla­ra­ti­va: genera re­su­l­ta­dos según de­te­r­mi­na­das reglas - Ejemplo: consulta SQL
  • Pro­gra­ma­ción funcional
  • Pro­gra­ma­ción es­pe­cí­fi­ca del dominio
Nota

Los términos “pro­ce­di­me­n­tal” y “funcional” se utilizan a menudo como sinónimos. Los dos son bloques de código eje­cu­ta­bles que pueden recibir ar­gu­me­n­tos. La di­fe­re­n­cia es que las funciones devuelven un valor, mientras que los pro­ce­di­mie­n­tos no. No todos los lenguajes pro­po­r­cio­nan soporte explícito para los pro­ce­di­mie­n­tos.

En principio, es posible resolver cualquier problema de pro­gra­ma­ción con cua­l­quie­ra de los pa­ra­di­g­mas, ya que todos los pa­ra­di­g­mas son “Turing completos”. Por tanto, el elemento limitador no es la máquina, sino el ser humano. Los pro­gra­ma­do­res o sus equipos solo pueden co­m­pre­n­der cierta co­m­ple­ji­dad. Por este motivo, para poder dominarla, recurren a ab­s­tra­c­cio­nes. De­pe­n­die­n­do del ámbito de apli­ca­ción y del problema, será más re­co­me­n­da­ble usar uno u otro estilo de pro­gra­ma­ción.

La mayoría de los lenguajes modernos son los llamados lenguajes mu­l­ti­pa­ra­di­g­ma, que permiten programar en varios estilos de pro­gra­ma­ción. En cambio, hay lenguajes que solo admiten un único estilo de pro­gra­ma­ción; lo que se aplica en el caso de los lenguajes es­tri­c­ta­me­n­te fu­n­cio­na­les, como Haskell:

Paradigma Ca­ra­c­te­rí­s­ti­cas Es­pe­cia­l­me­n­te adecuado para Idiomas
Im­pe­ra­ti­vo OOP Objetos, clases, métodos, herencia, po­li­mo­r­fi­s­mo Mo­de­li­za­ción, diseño de sistemas Smalltalk, Java, Ruby, Python, Swift
Im­pe­ra­ti­vo Pro­ce­di­me­n­tal Flujo de control, iteración, pro­ce­di­mie­n­tos / funciones C, Pascal, Basic
De­cla­ra­ti­vo Funcional In­mu­ta­bi­li­dad, funciones puras, cálculo lambda, recursión, sistemas de tipos Pro­ce­sa­mie­n­to paralelo de datos, apli­ca­cio­nes ma­te­má­ti­cas y cie­n­tí­fi­cas, ana­li­za­do­res si­n­tá­c­ti­cos y co­m­pi­la­do­res Lisp, Haskell, Clojure
De­cla­ra­ti­vo Lenguaje es­pe­cí­fi­co del dominio (DSL) Expresivo, amplia gama de lenguaje Apli­ca­cio­nes es­pe­cí­fi­cas del sector SQL, CSS
Nota

So­r­pre­n­de­n­te­me­n­te, incluso CSS es un lenguaje Turing completo. Es decir, cualquier cálculo escrito en otros lenguajes también podría re­so­l­ve­r­se en CSS.

La pro­gra­ma­ción orientada a objetos forma parte de la pro­gra­ma­ción im­pe­ra­ti­va y evo­lu­cio­nó a partir de la pro­gra­ma­ción pro­ce­di­me­n­tal. Esta última trabaja con datos inertes que son pro­ce­sa­dos por un código eje­cu­ta­ble:

  1. Datos: valores, es­tru­c­tu­ras de datos, variables
  2. Código: ex­pre­sio­nes, es­tru­c­tu­ras de control, funciones

Esta es pre­ci­sa­me­n­te la di­fe­re­n­cia entre la pro­gra­ma­ción orientada a objetos y la pro­ce­di­me­n­tal: la OOP combina datos y funciones en objetos. Un objeto es una es­tru­c­tu­ra de datos viva, porque los objetos no son inertes, sino que tienen un co­m­po­r­ta­mie­n­to. Así, los objetos son co­m­pa­ra­bles a las máquinas o a los or­ga­ni­s­mos uni­ce­lu­la­res. Mientras que con los datos solo se opera, con los objetos es posible in­ter­ac­tuar (o los objetos in­ter­ac­túan entre sí).

Descubre la di­fe­re­n­cia con un ejemplo. Una variable entera en Java o C++ solo contiene un valor. No es una es­tru­c­tu­ra de datos, sino una “Primitive”:

int number = 42;
Java

Las ope­ra­cio­nes sobre las Primitive se realizan a través de ope­ra­do­res o funciones que se definen fuera. Aquí, el ejemplo de la función successor, que devuelve el número que sigue a un entero:

int successor(int number) {
    return number + 1;
}
// returns `43`
successor(42)
Java

En cambio, en lenguajes como Python y Ruby, “todo es un objeto”. Incluso un simple número incluye el valor real, así como un conjunto de métodos que definen las ope­ra­cio­nes sobre el valor. Aquí, el ejemplo de la función succ in­co­r­po­ra­da en Ruby:

# returns `43`
42.succ
Ruby

En primer lugar, esto resulta práctico pues la fu­n­cio­na­li­dad de un tipo de datos está agrupada. No es posible llamar a un método que no coincida con el tipo. No obstante, los métodos pueden hacer aún más. En Ruby, incluso el bucle For se realiza como un método de un número. Como ejemplo, emitimos los números del 51 al 42:

51.downto(42) { |n| print n, ".. " }
Ruby

Entonces, ¿de dónde vienen los métodos? Los objetos se definen a través de clases en la mayoría de los lenguajes. Se dice que los objetos “se in­s­ta­n­cian” a partir de las clases y, por tanto, los objetos también se llaman in­s­ta­n­cias. Una clase es una plantilla para crear objetos similares que tienen los mismos métodos. Por lo tanto, en los lenguajes OOP puros, las clases funcionan como tipos. Esto queda claro en pro­gra­ma­ción orientada a objetos en Python; la función type devuelve una clase como tipo de un valor:

type(42) # <class 'int'>
type('Walter White') # <class 'str'>
Python

¿Cómo funciona la pro­gra­ma­ción orientada a objetos?

Si le preguntas a una persona con poca ex­pe­rie­n­cia en pro­gra­ma­ción en qué consiste la pro­gra­ma­ción orientada a objetos (OOP), la respuesta pro­ba­ble­me­n­te sea “algo sobre las clases”. Sin embargo, las clases no son el centro de la cuestión. Las ideas básicas de la pro­gra­ma­ción orientada a objetos de Alan Kay son más sencillas y pueden resumirse como sigue:

  1. Los objetos en­ca­p­su­lan su estado interno.
  2. Los objetos reciben mensajes a través de sus métodos.
  3. Los métodos se asignan di­ná­mi­ca­me­n­te en tiempo de ejecución.

A co­n­ti­nua­ción, se analizan estos tres puntos críticos.

Los objetos en­ca­p­su­lan su estado interno

Para entender lo que significa la en­ca­p­su­la­ción, te pre­se­n­ta­mos el ejemplo de un coche. Un coche tiene un estado de­te­r­mi­na­do, por ejemplo, la carga de la batería, el nivel de carga del depósito, si el motor está en marcha o no. Si se re­pre­se­n­ta un coche de este tipo como un objeto, las pro­pie­da­des internas solo deberían poder cambiarse a través de in­te­r­fa­ces definidas.

Aquí algunos ejemplos. Hay un objeto car que re­pre­se­n­ta un coche. Dentro del objeto, el estado se almacena en variables. El objeto gestiona los valores de las variables; por ejemplo, es posible ase­gu­rar­se de que la energía se utiliza para arrancar el motor. El motor del coche se arranca enviando un mensaje de start:

car.start()
Python

En este punto, el objeto decide lo que sucede a co­n­ti­nua­ción: si el motor ya está en marcha, el mensaje se ignora o se emite un mensaje co­rre­s­po­n­die­n­te. Si no hay su­fi­cie­n­te carga en la batería o el depósito está vacío, el motor permanece apagado. Si se cumplen todas las co­n­di­cio­nes, el motor se pone en marcha y se ajusta el estado interno. Por ejemplo, una variable booleana motor_running se establece en “True” y la carga de la batería se reduce en la carga necesaria para el arranque. A co­n­ti­nua­ción, se muestra de forma es­que­má­ti­ca cómo podría ser el código dentro del objeto:

# starting car
motor_running = True
battery_charge -= start_charge
Python

Es im­po­r­ta­n­te que el estado interno no pueda ser mo­di­fi­ca­do di­re­c­ta­me­n­te desde el exterior. De lo contrario, sería posible es­ta­ble­cer motor_running como “True” incluso si la batería estuviera vacía, lo que no re­fle­ja­ría las co­n­di­cio­nes reales.

Envío de mensajes / métodos de llamada

Como se ha visto, los objetos reac­cio­nan a los mensajes y pueden cambiar su estado interno como respuesta. Estos mensajes reciben el nombre de métodos; esto es, son funciones que están vi­n­cu­la­das a un objeto. El mensaje consiste en el nombre del método y po­si­ble­me­n­te otros ar­gu­me­n­tos. El objeto receptor se llama receptor. A co­n­ti­nua­ción, se muestra el esquema general de recepción de mensajes por parte de los objetos de la siguiente manera:

# call a method
receiver.method(args)
Python

Otro ejemplo: imagina que estás pro­gra­ma­n­do un sma­r­t­pho­ne. Los di­fe­re­n­tes objetos re­pre­se­n­tan fu­n­cio­na­li­da­des, por ejemplo, las llamadas, la linterna, la libreta de di­re­c­cio­nes, un mensaje de texto, etc. Por norma general, los su­b­co­m­po­ne­n­tes in­di­vi­dua­les se modelan a su vez como objetos. Por lo tanto, la libreta de di­re­c­cio­nes es un objeto, al igual que cada contacto que contiene y también el número de teléfono de un contacto. Esto facilita la mo­de­li­za­ción de los procesos a partir de la realidad:

# find a person in our address book
person = contacts.find('Walter White')
# let's call that person's work number
call = phone.call(person.phoneNumber('Work'))
...
# after some time, hang up the phone
call.hangUp()
Python

Asi­g­na­ción dinámica de los métodos

El tercer criterio esencial en la de­fi­ni­ción original de Alan Kay de la OOP es la asi­g­na­ción dinámica de métodos en tiempo de ejecución. Esto significa que la decisión sobre qué código se ejecuta cuando se llama a un método solo tiene lugar cuando se ejecuta el programa. En co­n­se­cue­n­cia, puedes modificar el co­m­po­r­ta­mie­n­to de un objeto en tiempo de ejecución.

La asi­g­na­ción dinámica de métodos tiene im­po­r­ta­n­tes im­pli­ca­cio­nes para la im­ple­me­n­ta­ción técnica de la fu­n­cio­na­li­dad OOP en los lenguajes de pro­gra­ma­ción, aunque en la práctica no se suele tener mucho que ver con ello. No obstante, aquí se presenta un ejemplo. Se modela la linterna del sma­r­t­pho­ne como un objeto fla­sh­li­ght que reacciona a los mensajes de on, off e intensity:

// turn on flashlight
flashlight.on()
// set flashlight intensity to 50%
flashlight.intensity(50)
// turn off flashlight
flashlight.off()
Ja­va­S­cri­pt

Imagina que la linterna se rompe y decides emitir una ad­ve­r­te­n­cia adecuada en caso de que se quiera acceder a ella. Un enfoque es sustituir todos los métodos por uno nuevo, lo que resulta muy sencillo, por ejemplo, en Ja­va­S­cri­pt. Se define la nueva función de “Fuera de servicio” con el nombre *out_of_order+ y se so­bre­s­cri­ben los métodos exi­s­te­n­tes con ella:

function out_of_order() {
    console.log('Flashlight out of order. Please service phone.')
    return false;
}
flashlight.on = out_of_order;
flashlight.off = out_of_order;
flashlight.intensity = out_of_order;
Ja­va­S­cri­pt

Si más tarde se intenta in­ter­ac­tuar con la linterna, recibirás el aviso de out_of_order:

// calls `out_of_order()`
flashlight.on()
// calls `out_of_order()`
flashlight.intensity(50)
// calls `out_of_order()`
flashlight.off()
Ja­va­S­cri­pt

¿De dónde vienen los objetos? In­s­ta­n­cia­ción e ini­cia­li­za­ción

Hasta ahora has visto cómo los objetos reciben mensajes y reac­cio­nan ante ellos. Pero ¿de dónde vienen los objetos? Aquí se presenta la in­s­ta­n­cia­ción, un concepto central. La in­s­ta­n­cia­ción es el proceso por el que un objeto pasa a existir. En los di­fe­re­n­tes lenguajes de pro­gra­ma­ción orientada a objetos existen di­fe­re­n­tes me­ca­ni­s­mos de in­s­ta­n­cia­ción. No­r­ma­l­me­n­te se utilizan uno o varios de los si­guie­n­tes me­ca­ni­s­mos:

  1. De­fi­ni­ción por objeto literal
  2. In­s­ta­n­cia­ción con función co­n­s­tru­c­to­ra
  3. In­s­ta­n­cia­ción desde una clase

Ja­va­S­cri­pt destaca en este punto dado que los objetos como los números o las cadenas pueden definirse di­re­c­ta­me­n­te como literales. Un ejemplo sencillo: se instancia un objeto vacío person y luego se le asigna un nombre, name, y un saludo, greet. Después, el objeto es capaz de saludar a otra persona y decir su propio nombre:

// instantiate empty object
let person = {};
// assign object property
person.name = "Jack";
// assign method
person.greet = function(other) {
    return `"Hi ${other}, I'm ${this.name}"`
};
// let's test
person.greet("Jim")
Ja­va­S­cri­pt

Se ha in­s­ta­n­cia­do un objeto único. Sin embargo, a menudo se quiere repetir la in­s­ta­n­cia­ción para crear una serie de objetos similares. Para este caso, también se puede usar Ja­va­S­cri­pt. Se crea una función llamada co­n­s­tru­c­tor que ensambla un objeto cuando se llama. Al hacerlo, la función co­n­s­tru­c­to­ra llamada Person toma un nombre y una edad y crea un nuevo objeto:

function Person(name, age) {
    this.name = name;
    this.age = age;
    
    this.introduce_self = function() {
        return `"I'm ${this.name}, ${this.age} years old."`
    }
}
// instantiate person
person = new Person('Walter White', 42)
// let person introduce themselves
person.introduce_self()
Ja­va­S­cri­pt

Ten cuidado con el uso de la palabra clave “this”, que también se encuentra en otros lenguajes como Java, PHP y C++ y, a menudo, suele confundir a los menos ex­pe­ri­me­n­ta­dos en OOP. De forma resumida, se trata de un marcador de posición para un objeto in­s­ta­n­cia­do. Cuando se llama a un método, this hace re­fe­re­n­cia al receptor, apuntando a una instancia es­pe­cí­fi­ca del objeto. Otros lenguajes como Python y Ruby utilizan para el mismo propósito self en lugar de this.

Además, en Ja­va­S­cri­pt ne­ce­si­ta­mos la palabra clave “new” para crear la instancia del objeto co­rre­c­ta­me­n­te. Esto se encuentra es­pe­cia­l­me­n­te en Java y C++, que di­s­ti­n­guen entre “Stack” y “Heap” a la hora de almacenar valores en memoria. En ambos lenguajes, new se utiliza para asignar memoria en heap. Ja­va­S­cri­pt, al igual que Python, almacena todos los valores en heap, por lo que new es realmente in­ne­ce­sa­rio. Python demuestra que se puedes pre­s­ci­n­dir de él.

El tercer mecanismo, y el más extendido, para crear in­s­ta­n­cias de objetos hace uso de las clases. Una clase cumple un papel similar al de una función co­n­s­tru­c­to­ra en Ja­va­S­cri­pt: la dos sirven de modelo para poder in­s­ta­n­ciar objetos similares cuando sea necesario. Al mismo tiempo, en lenguajes como Python y Ruby, una clase funciona como sustituto de los tipos uti­li­za­dos en otros lenguajes. A co­n­ti­nua­ción, se muestra un ejemplo de clase.

¿Cuáles son las ventajas y de­s­ve­n­ta­jas de la OOP?

Desde los inicio del siglo XXI, la pro­gra­ma­ción orientada a objetos ha ido re­ci­bie­n­do cada vez más críticas. Los lenguajes modernos y fu­n­cio­na­les con in­mu­ta­bi­li­dad y sistemas de tipos fuertes se co­n­si­de­ran más estables, fiables y eficaces. Sin embargo, la OOP se sigue usando en gran medida y tiene claras ventajas. Es im­po­r­ta­n­te elegir la he­rra­mie­n­ta adecuada para cada problema en lugar de confiar en una sola me­to­do­lo­gía.

Ventaja: en­ca­p­su­la­ción

Una ventaja inmediata de la OOP es la agru­pa­ción de la fu­n­cio­na­li­dad. En lugar de agrupar múltiples variables y funciones en una colección abierta, se pueden combinar en unidades cohe­re­n­tes. Se presenta la di­fe­re­n­cia con un ejemplo: se modela un autobús y se utilizan dos variables y una función para ello. Los pasajeros, “pa­s­se­n­ge­rs”, pueden subir al autobús hasta que esté lleno:

# list to hold the passengers
bus_passengers = []
# maximum number of passengers
bus_capacity = 12
# add another passenger
def take_bus(passenger)
    if len(bus_passengers) < bus_capacity:
        bus_passengers.append(passenger)
    else:
        raise Exception("Bus is full")
Python

El código funciona, pero resulta pro­ble­má­ti­co. La función take_bus accede a las variables bus_pa­s­se­n­ge­rs y bus_capacity sin pasarlas como ar­gu­me­n­tos. Esto conduce a problemas con el código extenso, ya que las variables deben pro­po­r­cio­nar­se glo­ba­l­me­n­te o pasarse con cada llamada. Además, es posible “hacer trampa”; pues es posible seguir añadiendo pasajeros al autobús, aunque esté lleno:

# bus is full
assert len(bus_passengers) == bus_capacity
# will raise exception, won't add passenger
take_bus(passenger)
# we cheat, adding an additional passenger directly
bus_passengers.append(passenger)
# now bus is over capacity
assert len(bus_passengers) > bus_capacity
Python

Nada impide aumentar la capacidad del autobús. Sin embargo, esto viola las su­po­si­cio­nes sobre la realidad física, porque un autobús real tiene una capacidad limitada que no se puede cambiar a voluntad:

# can't do this in reality
bus_capacity += 1
Python

El en­ca­p­su­la­mie­n­to del estado interno de los objetos protege de los cambios absurdos o no deseados. Aquí está la misma fu­n­cio­na­li­dad en código orientado a objetos. Se define una clase de autobús y se instancia un autobús con capacidad limitada. Añadir pasajeros solo es posible a través del método co­rre­s­po­n­die­n­te:

class Bus():
    def __init__(self, capacity):
        self._passengers = []
        self._capacity = capacity
    
    def enter(self, passenger):
        if len(self._passengers) < self._capacity:
            self._passengers.append(passenger)
            print(f"{passenger} has entered the bus")
        else:
            raise Exception("Bus is full")
# instantiate bus with given capacity
bus = Bus(2)
bus.enter("Jack")
bus.enter("Jim")
# will fail, bus is full
bus.enter("John")
Python

Ventaja: sistemas modelo

La pro­gra­ma­ción orientada a objetos es es­pe­cia­l­me­n­te adecuada para modelar sistemas. La OOP es intuitiva para las personas, ya que el ser humano piensa en términos de objetos que pueden ser ca­te­go­ri­za­dos. Los objetos pueden ser tanto elementos físicos como conceptos ab­s­tra­c­tos.

La herencia a través de je­ra­r­quías de clases que se encuentra en muchos lenguajes OOP también refleja los patrones de pe­n­sa­mie­n­to humano. Por ejemplo: un animal es un concepto abstracto. Los animales que se producen realmente son siempre ex­pre­sio­nes concretas de una especie. De­pe­n­die­n­do de la especie, los animales tienen di­fe­re­n­tes ca­ra­c­te­rí­s­ti­cas. Un perro no puede escalar ni volar, por lo que sus mo­vi­mie­n­tos se limitan al espacio bi­di­me­n­sio­nal:

# abstract base class
class Animal():
    def move_to(self, coords):
        pass
# derived class
class Dog(Animal):
    def move_to(self, coords):
        match coords:
            # dogs can't fly nor climb
            case (x, y):
                self._walk_to(coords)
# derived class
class Bird(Animal):
    def move_to(self, coords):
        match coords:
            # birds can walk
            case (x, y):
                self._walk_to(coords)
            # birds can fly
            case (x, z, y):
                self._fly_to(coords)
Python

De­s­ve­n­ta­jas de la pro­gra­ma­ción orientada a objetos

Una de­s­ve­n­ta­ja inmediata de la OOP es la jerga, que resulta difícil de entender al principio. Te ves obligado a aprender conceptos co­m­ple­ta­me­n­te nuevos, cuyo si­g­ni­fi­ca­do y propósito no suelen quedar claros con ejemplos simples. Es fácil cometer errores. De hecho, modelar je­ra­r­quías de herencia requiere mucha habilidad y ex­pe­rie­n­cia.

Una de las críticas más fre­cue­n­tes a la OOP es el en­ca­p­su­la­mie­n­to del estado interno, que en realidad pretende ser una ventaja. Esto conlleva di­fi­cu­l­ta­des a la hora de pa­ra­le­li­zar el código OOP. Si un objeto se traslada a varias funciones paralelas, el estado interno podría cambiar entre las llamadas a las funciones. Además, a veces es necesario acceder a in­fo­r­ma­ción en­ca­p­su­la­da en otra parte de un programa.

La na­tu­ra­le­za dinámica de la pro­gra­ma­ción orientada a objetos suele producir pérdidas de re­n­di­mie­n­to, ya que se pueden realizar menos op­ti­mi­za­cio­nes estáticas. Los sistemas de tipos de los lenguajes OOP puros, que tienden a ser menos pro­nu­n­cia­dos, también hacen im­po­si­bles algunas co­m­pro­ba­cio­nes estáticas. Los errores solo se hacen visibles en tiempo de ejecución. Los nuevos de­sa­rro­llos, como el lenguaje Ja­va­S­cri­pt Ty­pe­S­cri­pt, co­n­tra­rre­s­tan esta situación.

¿Qué lenguajes de pro­gra­ma­ción admiten o son adecuados para la OOP?

Casi todos los lenguajes mu­l­ti­pa­ra­di­g­ma son adecuados para la pro­gra­ma­ción orientada a objetos. Entre ellos se en­cue­n­tran los conocidos lenguajes de pro­gra­ma­ción de Internet PHP, Ruby, Python y Ja­va­S­cri­pt. En cambio, los pri­n­ci­pios de la OOP son en gran medida in­co­m­pa­ti­bles con el álgebra re­la­cio­nal su­b­ya­ce­n­te a SQL. Para salvar el “desajuste de im­pe­da­n­cias”, se utilizan capas de tra­du­c­ción es­pe­cia­les conocidas como “ma­pea­do­res de objetos re­la­cio­na­les” (ORM).

Ni siquiera los lenguajes puramente fu­n­cio­na­les, como Haskell, suelen ofrecer soporte nativo para la OOP. Para im­ple­me­n­tar OOP en C, hay que hacer un pequeño esfuerzo. Cu­rio­sa­me­n­te, Rust es un lenguaje moderno que prescinde de las clases. En su lugar, se utilizan struct y enum como es­tru­c­tu­ras de datos cuyo co­m­po­r­ta­mie­n­to se define mediante una palabra clave precedida por impl. Con los llamados rasgos se pueden agrupar los co­m­po­r­ta­mie­n­tos; de esta manera también se re­pre­se­n­tan la herencia y el po­li­mo­r­fi­s­mo. El diseño del lenguaje refleja el mantra de la pro­gra­ma­ción orientada a objetos (OOP) “Co­m­po­si­ción antes que herencia”.

Ir al menú principal