Sé que esto parece una pregunta extraña, ya que el punto de dos o más objetos que comparten la misma clase es que su comportamiento es el mismo, es decir, sus métodos son idénticos.
Sin embargo, tengo curiosidad por saber si hay algún lenguaje OOP que le permita redefinir los métodos de los objetos de la misma manera que puede asignar diferentes valores para sus campos. El resultado serían objetos construidos a partir de la misma clase que ya no exhiben exactamente el mismo comportamiento.
Si no me equivoco, ¿puedes hacer este JavaScript? Junto con esta pregunta, pregunto, ¿por qué alguien querría hacer esto?
object-oriented
programming-languages
Niko Bellic
fuente
fuente
setClickHandler()
método y hacer que diferentes instancias de la misma clase hagan cosas muy diferentes. En los idiomas que no tienen expresiones lambda convenientes, es más fácil crear una nueva subclase anónima solo para un nuevo controlador. Tradicionalmente, los métodos primordiales se consideraban el sello distintivo de una nueva clase, mientras que establecer los valores de los atributos no lo era, pero especialmente con las funciones del controlador, los dos tienen efectos muy similares, por lo que la distinción se convierte en una guerra sobre las palabras.Respuestas:
Los métodos en la mayoría de los lenguajes OOP (basados en clases) se fijan por tipo.
JavaScript está basado en prototipos, no en clases, por lo que puede anular los métodos en una base por instancia porque no existe una distinción clara entre "clase" y objeto; en realidad, una "clase" en JavaScript es un objeto que es como una plantilla de cómo deberían funcionar las instancias.
Cualquier lenguaje que permita funciones de primera clase, Scala, Java 8, C # (a través de delegados), etc., puede actuar como si tuviera anulaciones de método por instancia; tendría que definir un campo con un tipo de función y luego anularlo en cada instancia.
Scala tiene otra posibilidad; En Scala, puede crear objetos únicos (usando la palabra clave del objeto en lugar de la palabra clave de la clase), para que pueda extender su clase y anular los métodos, lo que resulta en una nueva instancia de esa clase base con anulaciones.
¿Por que alguien haria esto? Podría haber docenas de razones. Puede ser que el comportamiento necesite estar más estrictamente definido de lo que permitiría usar varias combinaciones de campo. También podría mantener el código desacoplado y organizado mejor. Sin embargo, en general, creo que estos casos son más raros y, a menudo, hay una solución más sencilla utilizando valores de campo.
fuente
Es difícil adivinar la motivación de su pregunta, por lo que algunas respuestas posibles podrían abordar su interés real o no.
Incluso en algunos lenguajes no prototipo es posible aproximar este efecto.
En Java, por ejemplo, una clase interna anónima está bastante cerca de lo que está describiendo: puede crear e instanciar una subclase del original, anulando solo el método o métodos que desee. La clase resultante será
instanceof
la clase original, pero no será la misma clase.¿Por qué querrías hacer esto? Con las expresiones lambda de Java 8, creo que muchos de los mejores casos de uso desaparecen. Con versiones anteriores de Java, al menos, esto puede evitar una proliferación de clases triviales de uso restringido. Es decir, cuando tiene una gran cantidad de casos de uso relacionados, que difieren solo en una pequeña forma funcional, puede crearlos casi sobre la marcha (casi), con la diferencia de comportamiento inyectada en el momento en que la necesita.
Dicho esto, incluso antes de J8, esto a menudo se puede refactorizar para cambiar la diferencia en un campo o tres, e inyectarlos en el constructor. Con J8, por supuesto, el método en sí se puede inyectar en la clase, aunque puede haber una tentación de hacerlo cuando otra refactorización puede ser más limpia (si no tan genial).
fuente
Solicitó cualquier idioma que proporcione métodos por instancia. Ya hay una respuesta para Javascript, así que veamos cómo se hace en Common Lisp, donde puede usar los especialistas en EQL:
¿Por qué?
EQL-specializers es útil cuando se supone que el argumento sujeto a despacho tiene un tipo para el que
eql
tiene sentido: un número, un símbolo, etc. En términos generales, no lo necesita, y simplemente tiene que definir tantas subclases como desee. Necesitado por su problema. Pero a veces, solo necesita despachar de acuerdo con un parámetro que es, por ejemplo, un símbolo: unacase
expresión se limitaría a los casos conocidos en la función de despacho, mientras que los métodos se pueden agregar y eliminar en cualquier momento.Además, la especialización en instancias es útil para fines de depuración, cuando desea inspeccionar temporalmente lo que sucede con un objeto específico en su aplicación en ejecución.
fuente
También puedes hacer esto en Ruby usando objetos singleton:
Produce:
En cuanto a los usos, así es como Ruby hace los métodos de clase y módulo. Por ejemplo:
En realidad está definiendo un método singleton
hello
en elClass
objetoSomeClass
.fuente
extend
realidad solo crea la clase singleton para el objeto y luego importa el módulo a la clase singleton.Puede pensar que los métodos por instancia le permiten ensamblar su propia clase en tiempo de ejecución. Esto puede eliminar una gran cantidad de código de pegamento, ese código que no tiene otro propósito que juntar dos clases para hablar entre sí. Los mixins son una solución algo más estructurada para el mismo tipo de problemas.
Estás sufriendo un poco por la paradoja del blub , esencialmente porque es difícil ver el valor de una función del lenguaje hasta que la hayas utilizado en un programa real. Así que busca oportunidades donde creas que podría funcionar, pruébalo y mira qué sucede.
Busque en su código grupos de clases que difieran solo por un método. Busque clases cuyo único propósito sea combinar otras dos clases en diferentes combinaciones. Busque métodos que no hagan nada más que pasar una llamada a otro objeto. Busque clases que se instancian utilizando patrones de creación complejos . Esos son todos los posibles candidatos para ser reemplazados por métodos por instancia.
fuente
Otras respuestas han mostrado cómo esta es una característica común de los lenguajes dinámicos orientados a objetos, y cómo se puede emular trivialmente en un lenguaje estático que tiene objetos de función de primera clase (por ejemplo, delegados en c #, objetos que anulan el operador () en c ++) . En lenguajes estáticos que carecen de dicha función, es más difícil, pero aún se puede lograr mediante el uso de una combinación del patrón de Estrategia y un método que simplemente delegue su implementación a la estrategia. Esto es, de hecho, lo mismo que haría en C # con los delegados, pero la sintaxis es un poco más complicada.
fuente
Puede hacer algo así en C # y en la mayoría de los lenguajes similares.
fuente
Conceptualmente, aunque en un lenguaje como Java todas las instancias de una clase deben tener los mismos métodos, es posible hacer que parezca que no lo hacen agregando una capa adicional de indirección, posiblemente en combinación con clases anidadas.
Por ejemplo, si una clase
Foo
puede definir una clase anidada abstracta estáticaQuackerBase
que contiene un métodoquack(Foo)
, así como varias otras clases anidadas estáticas derivadasQuackerBase
, cada una con su propia definición dequack(Foo)
, entonces si la clase externa tiene un campoquacker
de tipoQuackerBase
, entonces puede configura ese campo para identificar una instancia (posiblemente única) de cualquiera de sus clases anidadas. Después de hacerlo, la invocaciónquacker.quack(this)
ejecutará elquack
método de la clase cuya instancia ha sido asignada a ese campo.Debido a que este es un patrón bastante común, Java incluye mecanismos para declarar automáticamente los tipos apropiados. Dichos mecanismos realmente no están haciendo nada que no se pueda hacer simplemente usando métodos virtuales y clases estáticas anidadas opcionalmente, pero reducen en gran medida la cantidad de repeticiones necesarias para producir una clase cuyo único propósito es ejecutar un método único en nombre de otra clase.
fuente
Creo que esa es la definición de un lenguaje "dinámico" como ruby, groovy & Javascript (y muchos, muchos otros). Dinámico se refiere (al menos en parte) a la capacidad de redifinar dinámicamente cómo podría comportarse una instancia de clase sobre la marcha.
No es una gran práctica de OO en general, pero para muchos programadores de lenguaje dinámico, los principios de OO no son su máxima prioridad.
Simplifica algunas operaciones difíciles, como Monkey-Patching, donde puede ajustar una instancia de clase para permitirle interactuar con una biblioteca cerrada de una manera que no previeron.
fuente
No digo que sea algo bueno, pero esto es trivialmente posible en Python. No puedo pensar en un buen caso de uso en la parte superior de mi cabeza, pero estoy seguro de que existen.
fuente