Tem várias formas de fazer (e tudo depende dos requisitos), mas uma forma simples seria ter apenas uma classe triângulo:
public class Triangulo {
private float lado1, lado2, lado3;
private String tipo;
public Triangulo(float lado1, float lado2, float lado3) {
this.lado1 = lado1;
this.lado2 = lado2;
this.lado3 = lado3;
if (lado1 == lado2 && lado1 == lado3) {
this.tipo = "equilátero";
} else if ((lado1 == lado2) || (lado1 == lado3) || (lado2 == lado3)) {
this.tipo = "isósceles";
} else {
this.tipo = "escaleno";
}
}
public float getLado1() {
return lado1;
}
public float getLado2() {
return lado2;
}
public float getLado3() {
return lado3;
}
public String getTipo() {
return tipo;
}
public float getPerimetro() {
return this.lado1 + this.lado2 + this.lado3;
}
public float getArea() {
float p = this.getPerimetro() / 2;
return (float) Math.sqrt(p * (p - this.lado1) * (p - this.lado2) * (p - this.lado3));
}
}
Repare que as fórmulas para perímetro e área são as mesmas, independente do tipo do triângulo, então não faz sentido ter um método diferente para cada tipo.
Além disso, faz menos sentido ainda passar os lados como parâmetros do método, pois os lados que você vai usar são os do próprio triângulo.
Ou seja, em vez disso:
public float getArea(float lado1, float lado2, float lado3) { .... }
Fiz apenas isso:
public float getArea() { .... }
Pois entendo que a ideia é que o triângulo calcule sua própria área, usando os lados que ele já tem (em vez de receber os valores dos lados como parâmetros do método).
Então você usaria assim:
public static void main(String[] args) {
Triangulo t = new Triangulo(1, 2, 2);
System.out.println(t.getTipo());
System.out.println(t.getPerimetro());
System.out.println(t.getArea());
}
Repare também que não criei os setters, pois pelo que entendi, não faz sentido mudar os valores dos lados depois que o triângulo é criado.
Claro que depende dos requisitos (se o exercício “exige” que tenham setters, aí você cria), mas eu acho que se mudar um dos lados, não é mais o mesmo triângulo. Enfim, isso é só para dizer que você não deve sair criando getters e setters para tudo, tem que criar só o que faz sentido.
E no construtor eu recebo os lados e já verifico o tipo. Fiz tudo no construtor porque não adianta criar um triângulo se eu não tiver os lados (não faz sentido fazer new Triangulo()
, sem receber nenhum lado, e só depois setá-los), e se eu já tenho os lados, então eu posso verificar o tipo. Assim eu garanto que o construtor já faz tudo que precisa para que o triângulo criado seja válido e com todos os campos preenchidos.
E também troquei Float
(com “F” maiúsculo) por float
(com “f” minúsculo), pois não parece haver motivo - e nem ganho - nenhum para usar o wrapper (leia mais sobre isso aqui).
Com mais de uma classe
Mas se a ideia é ter várias classes (pois está escrito “criar classes dos triângulos”), então eu deixaria o Triangulo
como uma classe abstrata:
public abstract class Triangulo {
protected float lado1, lado2, lado3, perimetro, area;
protected String tipo;
public static Triangulo criarTriangulo(float lado1, float lado2, float lado3) {
if (lado1 == lado2 && lado1 == lado3) {
return new TrianguloEquilatero(lado1, lado2, lado3);
} else if ((lado1 == lado2) || (lado1 == lado3) || (lado2 == lado3)) {
return new TrianguloIsosceles(lado1, lado2, lado3);
}
return new TrianguloEscaleno(lado1, lado2, lado3);
}
protected Triangulo(float lado1, float lado2, float lado3) {
this.lado1 = lado1;
this.lado2 = lado2;
this.lado3 = lado3;
this.perimetro = this.lado1 + this.lado2 + this.lado3;
float p = this.perimetro / 2;
this.area = (float) Math.sqrt(p * (p - this.lado1) * (p - this.lado2) * (p - this.lado3));
}
public float getLado1() {
return lado1;
}
public float getLado2() {
return lado2;
}
public float getLado3() {
return lado3;
}
public String getTipo() {
return tipo;
}
public float getPerimetro() {
return this.perimetro;
}
public float getArea() {
return this.area;
}
}
Agora deixei os campos e o construtor protected
, assim eles podem ser acessados pelas sub-classes. Também criei um método estático para criar o triângulo, e internamente ele verifica qual tipo deve ser retornado (padrão conhecido como static factory method).
E as subclasses seriam bem simples (atenção, cada classe deve ficar em seu próprio arquivo .java
):
public class TrianguloEquilatero extends Triangulo {
public TrianguloEquilatero(float lado1, float lado2, float lado3) {
super(lado1, lado2, lado3);
this.tipo = "equilátero";
}
}
public class TrianguloIsosceles extends Triangulo {
public TrianguloIsosceles(float lado1, float lado2, float lado3) {
super(lado1, lado2, lado3);
this.tipo = "isósceles";
}
}
public class TrianguloEscaleno extends Triangulo {
public TrianguloEscaleno(float lado1, float lado2, float lado3) {
super(lado1, lado2, lado3);
this.tipo = "escaleno";
}
}
Outro detalhe é que, como eu não criei setters para os lados, então eles não mudam, por isso eu já posso calcular o perímetro e a área no próprio construtor (já que eles também não vão mudar).
Mas se os lados puderem mudar, aí o perímetro e área devem ser calculados toda vez (como está no primeiro código acima). Exemplo de uso:
public static void main(String[] args) {
Triangulo t = Triangulo.criarTriangulo(1, 2, 2);
System.out.println(t.getTipo());
System.out.println(t.getPerimetro());
System.out.println(t.getArea());
}