Hola.
Veamos.
El objetivo es hacer que este programa funcione.
Programa que es lo primero que has de escribir, aunque no va a funcionar porque tenemos que completar antes todo lo que se nos pide.
Los números escritos como comentarios, son los resultados que deberíamos obtener en pantalla.
Si miramos este código, vemos que hay varios objetos
Function, pero no son todos iguales: hay un
LinearFunction, un
QuadraticFunction, un
SineFunction y varios
CompositeFunction
Si son clases distintas, ¿por qué todas pueden ser instanciadas como
Function?
Porque todas implementan la interfaz
Function
Si te fijas, una interface se parece a una clase, pero no es lo mismo. En una interface, no "hay código".
Ahí vemos que se declara (pero
no se define) un método llamado
evaluate()
Esto significa que cualquier clase que vaya a implementar esta interfaz, automáticamente tendrá ese método
evaluate(), pero dicha clase tendrá que decidir cómo quiere que funcione ese método. Es decir, tendrá que
definirlo.
Por eso, aunque este programa va a tener varias clases que van a compartir ese método
evaluate(), dicho método se comportará diferente en cada clase, porque cada clase lo va a definir a su manera.
No se si hasta aquí me vas siguiendo....
Bien, entonces, hay que crear las clases que van a implementar la interfaz
Function para que cumplan su cometido y hacer que funcione el programa principal.
El enunciado ya nos dice como sería la clase
QuadraticFunction
Que es una clase capaz de evaluar (
evaluate()) una función cuadrática de una variable.
Los atributos a, b, y c son los coeficientes, que se indican mediante el constructor de la clase.
Y la variable para completar el polinomio, es el argumento llamado x que recibe la función
evaluate() entre los paréntesis.
El enunciado también nos dice como es la clase
SineFunction, que básicamente lo que hace es calcular el seno de un valor.
Este valor lo recibe el método
evaluate()
La clase no tiene atributos, porque no los necesita, se trata de una función muy simple y sencilla:
Bien, hasta aquí, no hemos hecho nada por nosotros mismos, todo esto es código que ya nos proporciona el enunciado.
Ahora viene la parte en la que nos toca a nosotros trabajar.
Nos piden crear dos clases:
LinearFunction, que representará una función lineal -->
y = ax + b
CompositeFunction, que representará la composición de dos funciones. Es decir, debe poder recibir dos
Function cualesquiera para realizar una composición con ellas.
Empecemos por lo fácil, hemos dicho que:
Esto significa que tenemos que crear una clase con dos atributos:
a y
b
Estos atributos recibirán valores por constructor.
Al implementar la interfaz
Function, tendremos un método
evaluate() al que debemos decirle como debe operar con la variable x que recibe entre paréntesis.
Y lo que tiene que hacer es multiplicar a por x y sumarlo a b -->
a*x + b
Intenta escribir tú dicha clase. No importa si no lo consigues o te equivocas o lo que sea... Solo con intentarlo ya estás aprendiendo, lo creas o no.
Tras terminar tu intento, compáralo con el código que pongo a continuación:
Si tu código ha quedado igual o equivalente al mío, enhorabuena.
Si no, no pasa nada. Corrige lo que sea necesario y pregunta si no entiendes el por qué de algo.
Bueno, ahora toca lo difícil, la clase
Esta clase hemos dicho que es la "composición" de dos funciones.
O sea, que sus atributos serán dos objetos
Function (que en realidad pueden ser
LinearFunction,
SineFunction, etc...
Estos atributos recibirán las funciones correspondientes por constructor
Ha de implementar la interface
Function, así que también tendrá un método
evaluate()
Y ahora viene lo "difícil", ¿qué ha de evaluar esta función cuyos atributos son también funciones?
Bien, para saber lo que ha de hacer, sería interesante que tú mismo hicieras una búsqueda en Internet intentando averiguar cómo se hace o qué es "una composición de funciones", de dos funciones en nuestro caso.
Seguramente encontrarás resultados que muestran un montón de fórmulas tan bonitas como complejas e incomprensibles para los que no somos matemáticos....
Aún así intenta averiguarlo por tu cuenta y luego sigues leyendo este post.
Si lo has conseguido, bien.
Si no lo has conseguido entender, te lo explico yo ahora en cristiano...
Básicamente, una composición de dos funciones consiste en que un valor/variable primero lo evalua una de las funciones, y el resultado que origina, es ahora evaluado por la segunda función, que es quien origina ya el resultado final.
Es decir, que el método
evaluate() de nuestra clase ha de hacer que la x que recibe entre paréntesis, la reciba el
evaluate() de su primer atributo
Function.
El resultado que obtenga, acto seguido lo recibe el
evaluate() del segundo atributo
Function.
Y este último resultado obtenido, es lo que ha de retorna el
evaluate() de la clase
CompositeFunction
En realidad, es más fácil de escribir el código que explicarlo, je je.
Igual que antes, intenta por tu cuenta escribir esta clase. Llega hasta donde puedas y luego comparas con la que pongo a continuación.
Como hemos dicho, esta clase posee dos
Function como atributos y lo que evalúa es el resultado de una variable que ha pasado por esas dos funciones de las que se compone.
Con esto, ya podemos ejecutar el programa principal, y comprobar que los resultados en pantalla coinciden con los indicados en los comentarios del código.
Y listo, espero que hayas podido entenderlo bien. Pregunta cualquier cosa que no te haya quedado claro.
Observa que la intención de este ejercicio es demostrar las características de las interfaces.
Todas las clases tienen un método
evaluate() porque todas implementan
Function, pero este método es completamente distinto para cada clase.
Porque las interfaces básicamente sirven para decir qué métodos ha de tener una clase, pero no para decir cómo han de comportarse esos métodos, ya que eso lo deciden las propias clases que lo implementan.
Un saludo.