oop - programming - programacion orientada a objetos
¿Puedes escribir algún algoritmo sin una instrucción if? (18)
Este sitio hizo cosquillas en mi sentido del humor: http://www.antiifcampaign.com/ pero ¿puede el polimorfismo funcionar en todos los casos en los que usaría una declaración if?
Aunque no está relacionado con la POO: en Prolog, la única forma de escribir la aplicación completa es sin las declaraciones.
Bueno, si estás escribiendo en Perl, ¡es fácil!
En lugar de
if (x) {
# ...
}
puedes usar
unless (!x){
# ...
}
;-)
Depende del idioma.
Los idiomas tipificados estáticamente deberían poder manejar toda la verificación de tipos compartiendo interfaces comunes y sobrecargando funciones / métodos.
Es posible que los idiomas escritos de forma dinámica deban abordar el problema de manera diferente, ya que el tipo no se verifica cuando se pasa un mensaje, solo cuando se accede a un objeto (más o menos). El uso de interfaces comunes sigue siendo una buena práctica y puede eliminar muchos de los tipos de verificación if.
Si bien algunas construcciones suelen ser un signo de olor de código, no me atrevo a eliminar ningún enfoque de un problema a priori. Puede haber ocasiones en las que la verificación de tipos sea la solución conveniente.
Nota: otros han sugerido usar switch en su lugar, pero esa es solo una forma inteligente de escribir más declaraciones en formato legible.
El razonamiento detrás de la campaña "anti-if" es similar a lo que dijo Kent Beck:
El buen código invariablemente tiene pequeños métodos y pequeños objetos. Solo al tener en cuenta el sistema en muchos estados pequeños y funciones, puede esperar satisfacer la regla de "una vez y solo una vez". Tengo mucha resistencia a esta idea, especialmente por parte de desarrolladores experimentados, pero nada de lo que hago con los sistemas proporciona tanta ayuda como romperla en más partes.
Si no sabe cómo factorizar un programa con composición y herencia, sus clases y métodos tenderán a crecer con el tiempo. Cuando necesite hacer un cambio, lo más fácil será agregar un IF en algún lugar. Agregue demasiados IF, y su programa será cada vez menos mantenible, y aún así lo más fácil será agregar más IF.
No tienes que convertir cada FI en un objeto de colaboración; pero es algo muy bueno cuando sabes cómo :-)
En respuesta a la pregunta, y como lo sugirió el último encuestado, necesita algunas instrucciones if para detectar el estado en una fábrica. En ese momento, creará un conjunto de clases colaborativas que resuelven el problema específico del estado. Por supuesto, se requerirían otros condicionales según sea necesario, pero se minimizarían.
Lo que se eliminaría, por supuesto, sería la verificación interminable del estado procesal que abunda en tanto código basado en servicios.
Se menciona una pequeña conversación interesante, ya que ese es el lenguaje que usé antes de ser arrastrado a Java. No llego a casa tan pronto como solía hacerlo.
Este es en realidad un juego de codificación que me gusta jugar con lenguajes de programación. Se llama "si no tuviéramos si", que tiene sus orígenes en: http://wiki.tcl.tk/4821
Básicamente, si no permitimos el uso de construcciones condicionales en el lenguaje: no if, no while, no for, no menos, no switch, etc. podemos recrear nuestra propia función IF. La respuesta depende del idioma y de las características del lenguaje que podamos explotar (¡recuerde que usar construcciones condicionales regulares es hacer trampa a los operadores primarios!)
Por ejemplo, en tcl, el nombre de una función es solo una cadena y cualquier cadena (incluida la cadena vacía) está permitida para cualquier cosa (nombres de funciones, nombres de variables, etc.). Entonces, aprovechando esto podemos hacer:
proc 0 {true false} {uplevel 1 $false; # execute false code block, ignore true}
proc 1 {true false} {uplevel 1 $true; # execute true code block, ignore flase}
proc _IF {boolean true false} {
$boolean $true $false
}
#usage:
_IF [expr {1<2}] {
puts "this is true"
} {
#else:
puts "this is false"
}
o en javascript podemos abusar de la escritura suelta y el hecho de que casi cualquier cosa se puede convertir en una cadena y combinarla con su naturaleza funcional:
function fail (discard,execute) {execute()}
function pass (execute,discard) {execute()}
var truth_table = {
''false'' : fail,
''true'' : pass
}
function _IF (expr) {
return truth_table[!!expr];
}
//usage:
_IF(3==2)(
function(){alert(''this is true'')},
//else
function(){alert(''this is false'')}
);
No todos los idiomas pueden hacer este tipo de cosas. Pero los idiomas que me gustan tienden a ser capaces de hacerlo.
Haskell ni siquiera tiene sentencias, siendo puramente funcional. ;RE
La idea del polimorfismo es llamar a un objeto sin verificar primero la clase de ese objeto.
Eso no significa que la sentencia if no deba usarse en absoluto; deberías evitar escribir
if (object.isArray()) {
// Code to execute when the object is an array.
} else if (object.inString()) {
// Code to execute if the object is a string.
}
Pensé en agregar mis dos centavos: puede optimizar el ifs en muchos idiomas donde la segunda parte de una expresión booleana no se evalúa cuando no afectará el resultado.
Con el operador and
, si el primer operando se evalúa como false
, no es necesario evaluar el segundo. Con el operador or
, es lo contrario: no hay necesidad de evaluar el segundo operando si el primero es true
. Algunos idiomas siempre se comportan así, otros ofrecen una sintaxis alternativa.
Aquí hay un código if - elseif - else hecho en JavaScript usando solo operadores y funciones anónimas.
document.getElementById("myinput").addEventListener("change", function(e) {
(e.target.value == 1 && !function() {
alert(''if 1'');
}()) || (e.target.value == 2 && !function() {
alert(''else if 2'');
}()) || (e.target.value == 3 && !function() {
alert(''else if 3'');
}()) || (function() {
alert(''else'');
}());
});
<input type="text" id="myinput" />
Esto me da ganas de intentar definir un lenguaje esotérico en el que los bloques se comporten implícitamente como funciones anónimas autoejecutables y devuelvan verdadero, de modo que lo escribirías así:
(condition && {
action
}) || (condition && {
action
}) || {
action
}
Puede definir Verdadero y Falso con objetos (en un pseudo-python):
class True:
def if(then,else):
return then
def or(a):
return True()
def and(a):
return a
def not():
return False()
class False:
def if(then,else):
return false
def or(a):
return a
def and(a):
return False()
def not():
return True()
Creo que es una forma elegante de construir booleanos, y demuestra que puedes reemplazar cada if por el polimorfismo, pero ese no es el punto de la campaña anti-if. El objetivo es evitar escribir cosas como (en un algoritmo de búsqueda de rutas):
if type == Block or type == Player:
# You can''t pass through this
else:
# You can
Pero más bien llamar a un método is_traversable en cada objeto. En cierto sentido, eso es exactamente lo inverso de la coincidencia de patrones. "if" es útil, pero en algunos casos, no es la mejor solución.
Puede evitar los errores en su código de lógica de negocios si los mantiene en su código de construcción (fábricas, constructores, proveedores, etc.). Su código de lógica de negocios sería mucho más legible, más fácil de entender o más fácil de mantener o ampliar. Consulte: http://www.youtube.com/watch?v=4F72VULWFvc
Puede hacerlo sin per se, pero no puede hacerlo sin un mecanismo que le permita tomar una decisión basándose en alguna condición.
En montaje, no hay sentencia if
. Hay saltos condicionales.
En Haskell, por ejemplo, no hay explícito if
, en cambio, define una función varias veces, olvidé la sintaxis exacta, pero es algo como esto:
pseudo-haskell
def posNeg(x < 0):
return "negative"
def posNeg(x == 0):
return "zero"
def posNeg(x):
return "positive"
Cuando llama a posNeg(a)
, el intérprete mirará el valor de a
, si es < 0
entonces elegirá la primera definición, si es == 0
entonces elegirá la segunda definición, de lo contrario, se establecerá de manera predeterminada a la tercera definición.
Entonces, mientras que los lenguajes como Haskell y SmallTalk no tienen el típico estilo de letra C de if
, tienen otros medios para permitirle tomar decisiones.
Sí, en realidad, puede tener un lenguaje completo que no tenga declaraciones "if" per se y solo permite "while":
http://cseweb.ucsd.edu/classes/fa08/cse200/while.html
En cuanto al diseño de OO, tiene sentido usar un patrón de herencia en lugar de interruptores basados en un campo de tipo en ciertos casos ... Sin embargo, esto no siempre es factible o necesariamente deseable.
@ennuikiller: los condicionales serían solo una cuestión de azúcar sintáctica:
if (test) body; is equivalent to x=test; while (x) {x=nil; body;}
if-then-else es un poco más detallado:
if (test) ifBody; else elseBody;
is equivalent to
x = test; y = true;
while (x) {x = nil; y = nil; ifBody;}
while (y) {y = nil; elseBody;}
La estructura de datos primitiva es una lista de listas. se podría decir que 2 escalares son iguales si son listas de la misma longitud. Usted podría hacer un bucle sobre ellos simultáneamente usando los operadores de cabeza / cola y ver si se detienen en el mismo punto.
por supuesto que todo podría estar envuelto en macros.
El lenguaje completo más simple es probablemente iota . Contiene solo 2 símbolos (''i'' y ''*'').
Sí. if
declaraciones implican ramas, esto puede ser muy costoso para muchos procesadores modernos, especialmente PowerPC. Muchas PC modernas hacen una gran cantidad de pedidos en tramitación y, por lo tanto, las predicciones erróneas de las sucursales pueden costar una orden de> 30 ciclos por falta de sucursal.
En la programación de la consola, a veces es más rápido ejecutar el código e ignorarlo que comprobar si debe ejecutarlo.
Evitación de rama simple en C:
if (++i >= 15)
{
i = 0;
)
puede ser reescrito como
i = (i + 1) & 15;
Sin embargo, si quieres ver algo real anti-if fu entonces lee this
Ah, y en la pregunta OOP: ¿reemplazaré una predicción errónea de rama por una llamada de función virtual? No, gracias....
Smalltalk, que se considera como un lenguaje "verdaderamente" orientado a objetos, no tiene una declaración "if", y no tiene una declaración "for", no "while". Hay otros ejemplos (como Haskell) pero este es uno bueno.
Citar Smalltalk no tiene una declaración de "si" :
Algunas personas pueden estar pensando que esto es evidencia que confirma sus sospechas de que Smalltalk es raro, pero lo que les voy a decir es esto:
Una declaración "si" es una abominación en un lenguaje orientado a objetos.
¿Por qué? Bueno, un lenguaje OO está compuesto de clases, objetos y métodos, y una declaración "si" es inevitablemente ninguna de esas. No puedes escribir "si" de una manera OO. No debería existir. La ejecución condicional, como todo lo demás, debe ser un método. ¿Un método de qué? Booleano
Ahora, curiosamente, en Smalltalk, Boolean tiene un método llamado ifTrue: ifFalse: (ese nombre se verá bastante extraño ahora, pero se pasa por alto por ahora). Es abstracto en Booleano, pero Booleano tiene dos subclases: Verdadero y Falso. El método se pasa dos bloques de código. En Verdadero, el método simplemente ejecuta el código para el caso verdadero. En Falso, ejecuta el código para el caso falso. Aquí hay un ejemplo que espero que explique:
(x >= 0) ifTrue: [ ''Positive'' ] ifFalse: [ ''Negative'' ]
Debería poder ver ifTrue: y ifFalse: allí. No te preocupes que no estén juntos.
La expresión (x> = 0) se evalúa como verdadera o falsa. Digamos que es verdad, entonces tenemos:
true ifTrue: [ ''Positive'' ] ifFalse: [ ''Negative'' ]
Espero que sea bastante obvio que eso producirá ''Positivo''.
Si fuera falso, tendríamos:
false ifTrue: [ ''Positive'' ] ifFalse: [ ''Negative'' ]
Eso produce ''Negativo''.
OK, así es como se hace. ¿Qué tiene de genial? Bueno, ¿en qué otro idioma puedes hacer esto? Más seriamente, la respuesta es que no hay casos especiales en este idioma. Todo se puede hacer de una manera OO, y todo se hace de una manera OO.
Definitivamente recomiendo leer la publicación completa y el Código es un objeto del mismo autor también.
Solía escribir mucho el código como recomendación en la campaña anti-if , usando devoluciones de llamadas en un diccionario de delegado o polimorfismo.
Es un argumento bastante engañoso, especialmente si se trata de bases de código desordenadas, pero para ser honesto, aunque es genial para un modelo de plugin o para simplificar grandes declaraciones if anidadas, hace que la navegación y la legibilidad sean un poco molestas.
Por ejemplo, F12 (Ir a la definición) en Visual Studio lo llevará a una clase abstracta (o, en mi caso, a una definición de interfaz).
También hace que el escaneo visual rápido de una clase sea muy engorroso, y agrega una sobrecarga en la configuración de los delegados y hashes de búsqueda.
El uso de las recomendaciones presentadas en la campaña anti-if tanto como parecen recomendar a mí me parece una programación como ''ooh, algo nuevo y brillante''.
En cuanto a las otras construcciones presentadas en este hilo, aunque se ha hecho con el espíritu de un desafío divertido, son solo sustitutos de una afirmación if, y no abordan realmente cuáles son las creencias subyacentes de la campaña anti-if.
Supongo que en realidad está preguntando acerca de reemplazar las declaraciones if que verifican los tipos, en lugar de reemplazar todas las declaraciones if.
Para reemplazar un if con polimorfismo se requiere un método en un supertipo común que pueda usar para el envío, ya sea anulando directamente o reutilizando métodos anulados como en el patrón de visitantes.
Pero, ¿qué sucede si no existe un método de este tipo y no puede agregar uno a un supertipo común porque usted no mantiene los supertipos? ¿Realmente se tomaría la medida de introducir un nuevo supertipo junto con subtipos solo para deshacerse de uno solo? Eso sería llevar la pureza un poco lejos en mi opinión.
Además, ambos enfoques (la anulación directa y el patrón de visitante) tienen sus desventajas: anular el método directamente requiere que implemente su método en las clases que desea activar, lo que podría no ayudar a la cohesión. Por otro lado, el patrón de visitante es incómodo si varios casos comparten el mismo código. Con un si puedes hacer:
if (o instanceof OneType || o instanceof AnotherType) {
// complicated logic goes here
}
¿Cómo compartirías el código con el patrón de visitante? Llama a un método común? ¿Dónde pondrías ese método?
Así que no, no creo que reemplazar esas afirmaciones siempre es una mejora. A menudo lo es, pero no siempre.
conteste: ** Ese sitio web está en contra de usar declaraciones if para ** verificar si un objeto tiene un tipo específico. Esto es completamente diferente de if (foo == 5)
. Es malo usar if is like if (foo instanceof pickle)
La alternativa, al usar polimorfismo en su lugar, promueve la encapsulación, haciendo que el código sea infinitamente más fácil de depurar, mantener y extender.
Estar en contra de if
está en general (hacer una cierta cosa basada en una condición) no le ganará nada. Observe cómo todas las otras respuestas aquí todavía toman decisiones, entonces, ¿cuál es realmente la diferencia?
explicación del por qué detrás de polymorhishm:
Toma esta situación:
void draw(Shape s) {
if (s instanceof Rectangle)
//treat s as rectangle
if (s instanceof Circle)
//treat s as circle
}
Es mucho mejor si no tiene que preocuparse por el tipo específico de un objeto, generalizando cómo los objetos son procesos.
void draw(Shape s) {
s.draw();
}
Esto mueve la lógica de cómo dibujar una forma en la propia clase de forma, por lo que ahora podemos tratar todas las formas de la misma forma. De esta manera, si queremos agregar un nuevo tipo de forma, todo lo que tenemos que hacer es escribir la clase y darle un método de dibujo en lugar de modificar cada lista condicional en todo el programa.
Esta idea está en todas partes en la programación de hoy, todo el concepto de interfaces tiene que ver con el polimorfismo. (Shape es una interfaz que define un determinado comportamiento, lo que nos permite procesar cualquier tipo que implemente la interfaz Shape en nuestro método). Los lenguajes de programación dinámica llevan esto aún más lejos, lo que nos permite pasar cualquier tipo que admita las acciones necesarias en un método. Lo que te parece mejor: (pseudocódigo de estilo Python)
def multiply(a,b):
if (a is string and b is int):
//repeat a b times.
if (a is int and b is int):
//multiply a and b
o utilizando polimorfismo:
def multiply(a,b):
return a*b
Ahora puede usar cualquiera de los 2 tipos que admiten el operador *, lo que le permite usar el método con tipos que aún no se han creado eventos.
Ver polymorphism , ¿qué es el polimorfismo en el flujo de apilamiento?