¿Se puede implementar la programación "orientada a objetos" sin la palabra clave de clase?

29

Digamos que queremos proporcionar una abstracción de una "cuenta" en un banco. Aquí hay un enfoque, usando un functionobjeto en Python:

def account():
    """Return a dispatch dictionary representing a bank account.

    >>> a = account()
    >>> a['deposit'](100)
    100
    >>> a['withdraw'](90)
    10
    >>> a['withdraw'](90)
    'Insufficient funds'
    >>> a['balance']
    10
    """
    def withdraw(amount):
        if amount > dispatch['balance']:
            return 'Insufficient funds'
        dispatch['balance'] -= amount
        return dispatch['balance']
    def deposit(amount):
        dispatch['balance'] += amount
        return dispatch['balance']
    dispatch = {'balance': 0,
                'withdraw': withdraw,
                'deposit': deposit}
    return dispatch

Aquí hay otro enfoque que usa abstracción de tipo (es decir, classpalabra clave en Python):

class Account(object):
    """A bank account has a balance and an account holder.

    >>> a = Account('John')
    >>> a.deposit(100)
    100
    >>> a.withdraw(90)
    10
    >>> a.withdraw(90)
    'Insufficient funds'
    >>> a.balance
    10
    """



    def __init__(self, account_holder):
        self.balance = 0
        self.holder = account_holder

    def deposit(self, amount):
        """Add amount to balance."""
        self.balance = self.balance + amount
        return self.balance

    def withdraw(self, amount):
        """Subtract amount from balance if funds are available."""
        if amount > self.balance:
            return 'Insufficient funds'
        self.balance = self.balance - amount
        return self.balance

Mi maestro comenzó el tema "Programación orientada a objetos" introduciendo la classpalabra clave y mostrándonos estos puntos:

Programación orientada a objetos

Un método para organizar programas modulares:

  • Barreras de abstracción
  • Paso de mensajes
  • Agrupando información y comportamiento relacionado

¿Crees que el primer enfoque sería suficiente para satisfacer la definición anterior? En caso afirmativo, ¿por qué necesitamos la classpalabra clave para hacer programación orientada a objetos?

cambio excesivo
fuente
2
Me alegra que estés de acuerdo. =) Aunque no conozco Python lo suficientemente bien como para dar una respuesta completa, es posible que le interese saber que en Javascript la forma típica de hacer OOP es similar al "objeto de función" que describe (aunque también tenemos una herencia prototípica que permite que los objetos "compartan" métodos en lugar de tener copias separadas de cada método en cada objeto; supongo que Python classhace una optimización similar).
Ixrec
Si desea una respuesta detallada, debe hacer otra pregunta o unirse a la sala de chat, pero la respuesta breve es (si ignora por completo la herencia de prototipos, matrices, etc.) eso es básicamente cierto; La mayoría de los objetos JS no son más que diccionarios de claves de cadena a valores arbitrarios. foo.bar()generalmente es idéntico y foo['bar'](), en raras ocasiones, la última sintaxis es realmente útil.
Ixrec
8
Esta es una pregunta realmente importante en su camino hacia una comprensión fundamental de la POO. Si está interesado, puede leer una publicación de blog mía donde creo un sistema de objetos simple en JavaScript sin depender de ninguna de las partes de OOP del lenguaje. Su primer ejemplo tiene una deficiencia importante: donde escribiría object['method'](args), los objetos de Python realmente hacen el equivalente de object['method'](object, args). Esto se vuelve relevante cuando una clase base llama a métodos en una clase secundaria, por ejemplo, en el Patrón de estrategia.
amon
13
Como otros han señalado, esta es una pregunta perceptiva sobre la POO. Sin embargo, aprovecharé esta oportunidad para señalar que no es así como los bancos reales representan las cuentas bancarias. Los bancos no tienen un objeto de "cuenta" mutable que cambie cuando lo debita y acredite; tienen una lista de transacciones de solo escritura y luego calculan el saldo de la lista de transacciones. Como buen ejercicio, intente implementar ese mecanismo en varios idiomas.
Eric Lippert

Respuestas:

66

¡Felicidades! Redescubrió el hecho bien conocido de que la orientación de los objetos se puede hacer sin un soporte de lenguaje de programación específico. Básicamente es la misma forma en que los objetos se introducen en Scheme en este libro de texto clásico . Tenga en cuenta que Scheme no tiene una classpalabra clave o algún tipo de equivalente, y los objetos se pueden crear sin tener incluso clases.

Sin embargo, el paradigma orientado a objetos fue tan exitoso que muchos lenguajes, y Python no es una excepción, le brindan soporte integrado. Esto es simplemente para facilitar a los desarrolladores el uso del paradigma y proporcionar una forma estándar de orientación a objetos para ese lenguaje. Es esencialmente la misma razón por la que muchos idiomas proporcionan un forbucle, aunque podría emularse usando un whilebucle con solo una o dos líneas de código adicionales, simplemente facilidad de uso .

Doc Brown
fuente
"para proporcionar una forma estándar de orientación a objetos para ese lenguaje" ¿Escucho una crítica de JavaScript allí? ;)
jpmc26
1
@ jpmc26: no intencionalmente. Y parece que hay algunos estándares ampliamente aceptados sobre cómo se crean los objetos en JavaScript.
Doc Brown
@overexchange: ¿tienes alguna pregunta que hacer?
Doc Brown
1
@overexchange: Bueno, lo que significa OOP es discutible, hay diferentes escuelas de pensamiento, pero la definición de SICP es más o menos la de los 3 puntos en su pregunta. Definitivamente se trata de construir abstracciones, pero no olvide los puntos 2 y 3. Sí, el concepto OOP incluye "cambio de estado", pero también permite el concepto de "objetos inmutables" (como la clase de cadena en Java o C #, Python tiene algunos tipos de datos mutables y algunos inmutables también). Y su primer ejemplo en su pregunta confirma esa definición, así como su segundo ejemplo.
Doc Brown
2
@overexchange: esto se remonta a la definición de orientación de objeto de Alain Kay (el inventor del lenguaje de conversación pequeño) Encontrará una respuesta integral en este stackoverflow.com/questions/2347973/… anterior artículo de SO. En mi humilde opinión, el "mensaje que pasa entre objetos" en el sentido de SICP solo significa no acceder a los datos internos de un objeto directamente, solo a través de un "protocolo de comunicación definido". En lenguajes OO como Python esto puede significar simplemente "llamar al método de un objeto".
Doc Brown,
13

Estoy de acuerdo en que la primera definición satisface los tres puntos que su maestro hizo. No creo que necesitemos la palabra clave de clase para nada. Debajo de las cubiertas, ¿qué más es un objeto sino una estructura de datos con diferentes tipos de datos y funciones para trabajar con los datos? Por supuesto, las funciones también son datos.

Iría aún más lejos y diría que hacer programación orientada a objetos no depende tanto de las palabras clave que proporciona su lenguaje, ¡puede hacer programación orientada a objetos en C si así lo desea! De hecho, el kernel de Linux emplea tales técnicas.

Lo que puede inferir de la palabra clave de clase aquí es que el lenguaje proporciona soporte para este tipo de construcción de forma inmediata, y no necesita pasar por todos los aros para volver a implementar la funcionalidad usted mismo (lo cual es una tarea bastante divertida en ¡sí mismo!). Sin mencionar todo el azúcar sintáctico que podrías obtener también.

Comportamiento
fuente
¿Qué pasa con la herencia? ¿Somos cruciales sobre los subtipos / supertipos en tiempo real? ¡Mi primer acercamiento puede no entretener esto!
intercambio excesivo
55
La herencia no se requiere de ninguna manera para OOP. También podría implementar la herencia en su primer ejemplo. No debe ser muy "limpio" pero posible de todos modos.
Zavior
3
@Zavior ese comentario me hace pensar en VB6. De hecho, la orientación a objetos sin herencia hace que el código sea menos limpio, por decirlo suavemente.
RubberDuck
1
@overexchange Cuando lo piensas, la herencia se trata de compartir código / comportamiento común entre clases. Nada te impide repetir todo ese código todo el tiempo. Sin embargo, sería súper horrible de mantener. Hay una razón por la cual existe la herencia :)
Zavior
1
@Zavior En su forma más básica, "subclases" es una abstracción que dice "antes de devolver la función de envío de datos de orden superior que estoy definiendo aquí (que haremos como una" clase ", ja, ja ha), crear una instancia de la función de envío y datos que tiene la 'superclase' mencionada por ThisParentFoo ". Eso es realmente todo lo que es. Cuando se trata de la herencia múltiple ingenua, en realidad todavía es todo, pero con la advertencia de que introduces el "problema del diamante", es por eso que la herencia múltiple apesta.
zxq9
9

¡Por supuesto que puede!

El lenguaje de programación automática es un lenguaje dinámico orientado a objetos basado en prototipos en el que todo es un objeto y no tiene sentido de clases ni de ningún tipo. Se centra en la idea de objetos prototípicos y la idea de clonarlos en lugar de tener clases como plantillas de cómo crear objetos.

Debe consultar http://www.selflanguage.org/ para obtener más información. Creo que es muy interesante y si te gusta OOP es una buena idea verificar algo que no es tan común.

DraQ
fuente
0

No siempre: depende del idioma. Ha demostrado la capacidad de hacer esto en Python pero (si su pregunta pretende ser independiente del idioma a pesar de la etiqueta de Python) no todos los idiomas pueden hacer esto. Java, por ejemplo, en su mayoría no puede. Ignorando la clase que contiene main, no hay forma de definir métodos / campos arbitrarios en un objeto definido dentro de main sin la palabra clave class. Aunque existen clases anónimas, requieren una interfaz y no pueden tener ningún miembro público, excepto los definidos en la interfaz. Si bien es posible definir interfaces personalizadas y luego crear clases anónimas para ellos, esto es efectivamente lo mismo (pero menos conveniente) que simplemente usar una clase.

Doc Brown tiene una gran respuesta, pero lo que estoy tratando de decir es que estoy seguro de que hay al menos un idioma que no permitirá su solución en absoluto.

SkySpiral7
fuente
Como principiante, para aprender el concepto de "Programación orientada a objetos", sí, estoy tratando de ser independiente del lenguaje. Creo que "Doc Brown" ha respondido en las mismas líneas, me dijo que leyera sicp text-chap3, que no tiene nada que ver con ninguna sintaxis de lenguaje.
intercambio excesivo
Desearía nombrar un idioma que requiera absolutamente el uso de clases para validar mi respuesta. Pero solo conozco algunos idiomas y, por desgracia, Java permite una solución alternativa. C ++ tiene estructuras y Javascript plano permite lo que demostró. Sospecho que Smalltalk y Eiffel podrían requerir clase ya que escuché que están estrictamente estructurados.
SkySpiral7
Como Doc Brown, si hubiera aprendido a usar el esquema, no habría hecho esta pregunta. Desafortunadamente, la versión del curso SICP que estoy aprendiendo usa Python.
intercambio excesivo
1
Todo programa Java válido debe contener la classpalabra clave, por lo que no es una gran sorpresa. Pero absolutamente podría implementar su propio sistema de objetos sobre el sistema de objetos de Java, aunque no sé por qué quiere hacer tal cosa.
Brian Gordon
1. Java es realmente especial a este respecto, ya que simplemente ha desechado todas las otras palabras clave que podrían usarse para crear estructuras de datos personalizadas. Casi todos los otros idiomas que conozco tienen registros o cierres. 2. Incluso en Java, puede programar en una memoria construida a partir de una matriz. Y puede implementar la orientación a objetos dentro de eso, usando la classpalabra clave solo porque el lenguaje requiere que ponga sus funciones en clases. Por supuesto, esto es extremadamente teórico, ¡pero incluso en Java puedes hacer Orientación de Objetos sin las clases integradas!
cmaster
0

La definición de tu profesor pierde por completo el punto más importante de la programación orientada a objetos, lo único que lo hace útil y único. "Transmitir mensajes" es un montón de tonterías soñadas por la gente de Smalltalk, y ha sido un fracaso en todas partes donde se ha intentado. El verdadero poder de OOP es algo conocido como sustitución de Liskov , y si bien el concepto es bastante simple de describir y comprender, la implementación subyacente es lo suficientemente compleja como para que sea esencialmente imposible hacer lo correcto sin el soporte de nivel de lenguaje.

La idea de la sustitución de Liskov es que en cualquier lugar donde su código esté esperando una variable de cierto tipo, debería ser capaz de aceptar cualquier tipo derivado de ese tipo y seguir funcionando correctamente sin tener que tener conocimiento de los detalles del tipo derivado.

Por ejemplo, los marcos de GUI utilizan la sustitución de Liskov en todo el lugar. Tienden a tener una Controlclase base que puede representar "cualquier control", que define una interfaz que conoce acciones básicas como dibujar, redimensionar y responder a las entradas del usuario. Si hace clic en un control, el marco de la IU llamará a un Clickmétodo en el control sin tener que preocuparse de qué tipo de control es, y luego dejará que el control maneje el clic de la manera apropiada para su propia clase. Un Buttoncontrol debe hacer algo completamente diferente al hacer clic en él TextBox, para dar solo un ejemplo.

Entonces, sí, puede crear algo similar a los objetos utilizando el truco de funciones anidadas descrito anteriormente, pero como no puede obtener la herencia y la sustitución de Liskov de esa manera, es un sustituto extremadamente limitado para la verdadera POO.

Mason Wheeler
fuente
En lenguaje C, ¿no puedo decir 'struct parent {}' y luego 'struct child {struct parent * ptr;}'? ¿No es esto herencia en la sintaxis del lenguaje no oop?
intercambio excesivo
@overexchange: Ese es un intento de no-OO de fingirlo, pero el compilador no le permitirá sustituirlo por el otro. (No puede pasar un child*a una función que toma un parent*como argumento, al menos no sin una conversión tipográfica). Y lo que es peor, las estructuras C no pueden tener métodos vinculados a ellas, y no hay soporte para métodos virtuales , que son lo que hace que la magia de la sustitución de Liskov funcione, por lo que debe construir VMT a mano, que es un proceso complicado que es fácil de arruinar.
Mason Wheeler
1
El kernel de Linux utiliza una emulación de varias técnicas de OO, que deben codificarse manualmente sin soporte de idiomas. Esto conduce a muchas oportunidades para errores, que, al ser Linux, se ven contrarrestados por una aplicación liberal de la Ley de Linus. Sí, es posible hacerlo, la equivalencia de Turing lo demuestra, pero mi punto de vista de que es extremadamente difícil hacerlo bien sin el soporte del idioma sigue en pie. Además, ¿por qué todas estas preguntas sobre C cuando la pregunta era sobre Python? En C no es posible hacer el truco de las funciones anidadas en primer lugar.
Mason Wheeler
1
@overexchange ¿Desde cuándo Java es un "paraíso de programadores"?
Brandin
1
La transmisión de mensajes no ha sido una falla en Smalltalk, Erlang, o incluso en los sistemas OOP de estilo Java, donde "mensaje" significa algo diferente a "llamada de función" (señales y ranuras de Qt con una cola segura frente al antiguo marketing de Java usando el término "mensaje" cuando significa "llamada al método"). Mensajes! = Llamadas a funciones. La mensajería genuina no solo es exitosa, sino que parece ser la única forma en que sabemos escribir sistemas masivamente concurrentes y robustos. Esto es ortogonal para implementar OOP de estilo Java sin la palabra clave 'class'. Se puede hacer. Es no siempre son útiles. La mensajería no viene al caso.
zxq9
-1

Respuesta corta rápida

Sí, los programadores pueden aplicar la programación orientada a objetos sin "clases".

Respuesta descriptiva extensa y aburrida

Hay varias variaciones de "Orientación a objetos", aunque el primer concepto que les viene a la mente a muchos programadores es "Clases".

Sí, los programadores pueden aplicar la programación orientada a objetos sin "clases", pero se limita a las características y limitaciones de cada lenguaje de programación.

Su publicación está etiquetada como Python , por lo tanto, el título de su pregunta puede ser más como "Cómo implementar la programación orientada a objetos sin clases en Python".

Actualmente utilizo la frase "Programación orientada a objetos y clases", para identificar otras variaciones como "Prototipos" de Javascript, o "Basados" en Visual Basic, o emulación en "Pure C" usando "functores".

umlcat
fuente