Universidad Carlos III de Madrid

Grado en Ingeniería Telemática/Grado en Ingeniería de Sistemas de Comunicaciones

Enero-Mayo 2014

Orientación a Objetos y Herencia

Lab Section1. Sesión 2 (laboratorio): Orientación a Objetos y Herencia (I)

Exercise Section1.1. Puntos y Figuras Geométricas (I)

Un punto en el plano se puede representar mediante un par de coordenadas x e y, ambas tomando valores en el conjunto de los números reales. En Java podemos representar un punto en el plano mediante una instancia de la siguiente clase:

public class Point {
    private double x;
    private double y;
}

Apartado 1: Constructor de la clase Point

Programa un constructor para la clase Point. Debe recibir como parámetros las dos coordenadas del punto.

Apartado 2: Método para representar un punto en formato de texto

El método String toString() tiene un significado especial en los objetos Java. Es el método que se utiliza para obtener una representación breve como cadena de texto del objeto.

Programa el método String toString() de la clase Point para que devuelva una cadena de texto con la representación del punto como en el siguiente ejemplo: "(23, -3)". El primer número representa la coordenada x del punto y el segundo la coordenada y.

Apartado 3: El método main

Ahora debes probar el código anterior. Programa una clase llamada TestPoint que tenga un método main. Este método debe recibir como argumentos de línea de comandos las coordenadas x e y, crear un nuevo objeto de la clase Point con dichas coordenadas e imprimir en la salida estándar la representación textual de dicho objeto.

El programa debe comprobar que el número de argumentos de línea de comandos recibido sea el correcto.

Ten en cuenta que el método parseDouble de la clase Double transforma una cadena de texto a un tipo primitivo double.

Apartado 4: Los métodos de acceso

Es habitual que los atributos de un objeto se declaren como privados (private) para evitar accesos incontrolados desde otros puntos del programa. Si es necesario que desde el exterior de la clase se acceda a estos atributos, se proporcionan métodos cuyo nombre empieza, por convenio, con las cadenas "get" (acceso en lectura) y "set" (acceso en escritura).

Programa en la clase Point los siguientes métodos, que devuelven el valor de las coordenadas x e y:

public double getX() {
    /* ... */
}

public double getY() {
    /* ... */
}

Modifica el código de tu clase TestPoint para comprobar que su comportamiento es correcto.

Apartado 5: Cálculo de distancias

Programa el siguiente método de la clase Point que devuelva la distancia del punto al origen de coordenadas:

public double distance() {
  /* ... */
}

Sobrecarga el método anterior con el siguiente método, que recibe como parámetro otro objeto de la clase Point y devuelve la distancia entre el punto representado por el objeto al cual pertenece el método y el objeto recibido como parámetro:

public double distance(Point anotherPoint) {
    /* ... */
}

Modifica el código de tu clase TestPoint para comprobar que el funcionamiento de estos dos métodos sea correcto.

Apartado 6: Cálculo de cuadrante

Programa un método de la clase Point que devuelva el cuadrante en el que se encuentra el punto como un valor de tipo int:

  • Devuelve 0 si está en el origen de coordenadas o sobre alguno de los ejes.
  • Devuelve 1 si está en el primer cuadrante (x e y positivos).
  • Devuelve 2 si está en el segundo cuadrante (x negativo e y positivo).
  • Devuelve 3 si está en el tercer cuadrante (x e y negativos).
  • Devuelve 4 si está en el cuarto cuadrante (x positivo e y negativo).

El prototipo del método se muestra a continuación:

public int quadrant()  {
  /* ... */
}

Modifica el código de tu clase de prueba para comprobar que su comportamiento es correcto.

Apartado 7: Cálculo del punto más cercano.

Programa un método en Point que reciba como parámetro un array de objetos de la clase Point y devuelva una referencia al objeto de dicho array que esté más cercano al punto al cual pertenece el método. El prototipo del método se muestra a continuación:

public Point nearest(Point[] otherPoints) {
  /* ... */
}

Modifica el código de tu clase de prueba para comprobar que su comportamiento es correcto.

Apartado 8: La clase Triangulo.

Un triángulo está plenamente definido por sus tres vértices. Estos vértices se pueden representar como objetos de la clase Point.

Programa la clase Triangle con sus atributos y un constructor que reciba como parámetro tres vértices del triángulo (como objetos de la clase Point).

Apartado 9: Longitud de los lados.

Programa el método sideLengths() de la clase Triangulo, que debe devolver un array de tres posiciones, cada una de las cuales debe ser la longitud de uno de los lados del triángulo. El prototipo del método se muestra a continuación:

public double[] sideLengths() {
    /* ... */
}

Programa una clase para probar el correcto funcionamiento de la clase Triangle.

Soluciones

public class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    /**
     * Returns the string representation of the point.
     *
     */
    public String toString() {
        return "(" + x + ", " + y + ")";
    }

    /**
     * Returns the distance to the origin.
     *
     */
    public double distance() {
        Point origin = new Point(0.0, 0.0);
        return distance(origin);
    }

    /**
     * Returns the x coordinate of the point.
     *
     */
    public double getX() {
        return x;
    }

    /**
     * Returns the y coordinate of the point.
     *
     */
    public double getY() {
        return y;
    }

    /**
     * Returns the distance to another point.
     *
     */
    public double distance(Point anotherPoint) {
        return Math.sqrt(Math.pow(x - anotherPoint.getX(), 2) +
                         Math.pow(y - anotherPoint.getY(), 2));
    }

    /**
     * Returns the quadrant in which the point is.
     *
     */
    public int quadrant() {
        if (x > 0.0 && y > 0.0) {
            return 1;
        } else if (x < 0.0 && y > 0.0) {
            return 2;
        } else if (x < 0.0 && y < 0.0) {
            return 3;
        } else if (x > 0.0 && y < 0.0) {
            return 4;
        } else {
            // (x==0.0 || y==0.0)
            return 0;
        }
    }

    /**
     * Returns the nearest point of the array in the parameter, or
     * null if array is empty.
     *
     */
    public Point nearest(Point[] otherPoints) {
        Point nearestPoint = null;
        double minDistance = Double.MAX_VALUE;
        double currentDistance;

        for (int i=0; i<otherPoints.length; i++) {
            currentDistance = this.distance(otherPoints[i]);
            if (currentDistance <= minDistance) {
                minDistance = currentDistance;
                nearestPoint = otherPoints[i];
            }
        }
        return nearestPoint;
    }
}
public class TestPoint {

    public static void main(String args[]) {
        // Check the number of arguments (the two coordinates)
        if (args.length != 2) {
            System.out.println("Usage: java TestPoint x y");
            System.out.println("where x and y are the coordinates of a point.");
            System.exit(1);
        }
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        Point p = new Point(x, y);
        System.out.println("The point is " + p);
        System.out.println("Its distance to origin is " + p.distance());
        System.out.println("Its X coordinate is " + p.getX()
                           + " and its Y coordinate is " + p.getY());
        System.out.println("It is located in the quadrant " + p.quadrant());

        Point[] pointsArray = new Point[] {new Point(1, 1), new Point(5, 3),
                                           new Point(10, 10), new Point(-3, 2),
                                           new Point(-4, -5)};
        for (int i = 0; i < pointsArray.length; i++) {
            System.out.println("Its distance to the point "
                               + pointsArray[i] + " is "
                               + p.distance(pointsArray[i]));
        }
        System.out.println("The nearest point is " + p.nearest(pointsArray));
    }
}
public class Triangle {
    private Point vertex1;
    private Point vertex2;
    private Point vertex3;

    public Triangle(Point vertex1, Point vertex2, Point vertex3) {
        this.vertex1 = vertex1;
        this.vertex2 = vertex2;
        this.vertex3 = vertex3;
    }

    /**
     * Returns an array with the length of every side of the triangle.
     *
     */
    public double[] sideLengths() {
        double edgesLength[] = new double[3];
        edgesLength[0] = vertex1.distance(vertex2);
        edgesLength[1] = vertex2.distance(vertex3);
        edgesLength[2] = vertex3.distance(vertex1);

        return edgesLength;
    }
}
public class TestTriangle {

    public static void main(String args[]) {
        // Check the number of arguments (two coordinates for every point)
        if (args.length != 6) {
            System.out.println("Usage:");
            System.out.println("  java PruebaTriangulo x1 y1 x2 y2 x3 y3");
            System.out.println("where (xi,yi) are the coordinates of every"
                               + " vertex");
            System.exit(1);
        }

        double x1 = Double.parseDouble(args[0]);
        double y1 = Double.parseDouble(args[1]);
        double x2 = Double.parseDouble(args[2]);
        double y2 = Double.parseDouble(args[3]);
        double x3 = Double.parseDouble(args[4]);
        double y3 = Double.parseDouble(args[5]);

        // Create the vertices and the triangle
        Point v1 = new Point(x1, y1);
        Point v2 = new Point(x2, y2);
        Point v3 = new Point(x3, y3);
        Triangle t = new Triangle(v1, v2, v3);

        // Display the info
        System.out.println("The triangle has vertices " + v1.toString() + ", "
                           + v2.toString() + ", " + v3.toString());

        double[] sideLengths = t.sideLengths();
        System.out.println("Its sides are " + sideLengths[0] + ", "
                           + sideLengths[1] + ", " + sideLengths[2] + " long");
    }
}

Homework Section2. Actividades para casa

Exercise Section2.1. Números racionales

Un número racional es aquel que puede ser expresado como una fracción de dos números enteros. En este ejercicio debes programar una clase llamada Rational que represente un número racional y permita operar con él.

Es muy recomendable que a medida que programas cada nueva funcionalidad en la clase la vayas probando, en vez de esperar a tener la clase completamente programada. A medida que vas resolviendo los distintos apartados, programa una clase de prueba en que vayas comprobando el correcto funcionamiento de cada nueva funcionalidad que vas añadiendo.

Apartado 1

Programa la estructura básica de la clase, incluyendo sus atributos y dos constructores. El primer constructor recibe dos enteros (numerador y denominador). El segundo constructor recibe únicamente un entero, y creará un número entero representado como racional, esto es, con denominador 1. Este segundo constructor debe ser implementado mediante una llamada al otro constructor.

Añade el método String toString() a esta clase. Debe devolver una representación textual con el formato de los siguientes ejemplos: "-5 / 2", "1 / 3", "6", "-7". Fíjate en que cuando el denominador es 1 se muestra sólo el numerador.

Apartado 2

Modifica el primer constructor para que cuando se construyan objetos de la clase, estos se uniformicen automáticamente haciendo las siguientes operaciones:

  1. Si el denominador es negativo, multiplica numerador y denominador por -1.
  2. Simplifica la fracción dividiendo numerador y denominador por su máximo común divisor.

Probablemente sea una buena decisión de diseño crear un método auxiliar privado que implemente estas operaciones, e invocarlo desde el constructor.

Para calcular el máximo común divisor de dos números puedes copiar el siguiente método en tu clase:

    private int gcd() {
        int a = /* put here the attribute that represents the numerator */
        int b = /* put here the attribute that represents the denominator */
        while (b != 0) {
            int tmp = b;
            b = a % b;
            a = tmp;
        }
        if (a < 0) {
            a = -a;
        }
        return a;
    }

Apartado 3

Añade a la clase un método que reciba otro número racional, como objeto de la clase Rational, y devuelva un nuevo objeto de esta clase que represente la suma del objeto al cual pertenece el método (el objeto this) y el objeto que se recibe como parámetro:

    public Rational sum(Rational other) {
        (...)
    }

Apartado 4

Haz lo mismo que en el apartado anterior, pero en este caso devuelve un nuevo objeto Rational que represente el producto del objeto this y el objeto que se recibe como parámetro:

    public Rational multiply(Rational other) {
        (...)
    }

Apartado 5

Sobrecarga los métodos de los apartados anteriores con dos variantes que admitan como parámetros, en vez de un objeto Rational, dos enteros que representen el numerador y denominador del otro número. Para reutilizar código, impleméntalos de tal forma que en lugar de resolver el producto o suma directamente, invoquen a los métodos de los dos apartados anteriores para hacerlo:

    public Rational sum(int otherNumerator, int otherDenominator) {
        (...)
    }

    public Rational multiply(int otherNumerator, int otherDenominator) {
        (...)
    }

Soluciones

public class Rational {
    private int numerator;
    private int denominator;

    public Rational(int integer) {
        this(integer, 1);
    }

    public Rational(int numerator, int denominator) {
        this.numerator = numerator;
        this.denominator = denominator;
        simplify();
    }

    public String toString() {
        if (denominator == 1) {
            return "" + numerator;
        } else {
            return numerator + " / " + denominator;
        }
    }

    public Rational sum(Rational other) {
        int sumNumerator = numerator * other.denominator
            + other.numerator * denominator;
        int sumDenominator = denominator * other.denominator;
        return new Rational(sumNumerator, sumDenominator);
    }

    public Rational sum(int otherNumerator, int otherDenominator) {
        return sum(new Rational(otherNumerator, otherDenominator));
    }

    public Rational multiply(Rational other) {
        int prodNumerator = numerator * other.numerator;
        int prodDenominator = denominator * other.denominator;
        return new Rational(prodNumerator, prodDenominator);
    }

    public Rational multiply(int otherNumerator, int otherDenominator) {
        return multiply(new Rational(otherNumerator, otherDenominator));
    }

    private void simplify() {
        if (denominator < 0) {
            numerator = -numerator;
            denominator = -denominator;
        }
        int gcdValue = gcd();
        if (gcdValue != 0) {
            numerator = numerator / gcdValue;
            denominator = denominator / gcdValue;
        }
    }

    private int gcd() {
        int a = numerator;
        int b = denominator;
        while (b != 0) {
            int tmp = b;
            b = a % b;
            a = tmp;
        }
        if (a < 0) {
            a = -a;
        }
        return a;
    }
}
public class TestRational {

    public static void main(String[] args) {
        System.out.println(new Rational(-21, 14));
        System.out.println(new Rational(21, -14));
        System.out.println(new Rational(-6, -2));
        System.out.println(new Rational(-6));
        System.out.println(new Rational(-6).sum(new Rational(2, 3)));
        System.out.println(new Rational(1, 4).sum(new Rational(1, 10)));
        System.out.println(new Rational(1, 4).multiply(new Rational(2)));
        System.out.println(new Rational(2, 3).multiply(new Rational(1, 2)));
        System.out.println(new Rational(-6).sum(2, 3));
        System.out.println(new Rational(1, 4).sum(1, 10));
        System.out.println(new Rational(1, 4).multiply(2, 1));
        System.out.println(new Rational(2, 3).multiply(1, 2));
    }
}