Problema com polimorfismo: Hierarquia de Formas

Estou resolvendo o exercio 10.10 do Deitel 6ªed.

Trata-se de um polimorfismo q envolve Formas. Formas bi e tridimensionais.
Fiz todas as classes.
Só que nem todas as classes estao retornando o valor.

Minha classe Tetraedro so retorna a resposta do método obterArea(), mas o obterVolume() nao…

[code]public abstract class Forma {

protected double base;
protected double altura;
protected double raio;

 
public Forma(double b, double a){
    base = b;
    altura = a;
}

public Forma (double r){
    raio = r;
}


public double getBase() {
    return base;
}

public void setBase(double base) {
    this.base = base;
}

public double getAltura() {
    return altura;
}

public void setAltura(double altura) {
    this.altura = altura;
}

public double getRaio() {
    return raio;
}

public void setRaio(double raio) {
    this.raio = raio;
}

}
[/code]

[code]package formas;

public abstract class FormaBidimensional extends Forma{

public FormaBidimensional(double b, double a){
    super(b,a);
}
public FormaBidimensional(double r){
    super(r);
}
public abstract double obterArea();

public String toString(){
    return String.format("Área: %s", obterArea());
}

}
[/code]

[code]package formas;

public abstract class FormaTridimensional extends Forma{

public FormaTridimensional(double b, double a){
    super(b,a);
}

public FormaTridimensional(double r){
    super(r);
}

public abstract double obterArea();
public abstract double obterVolume();

public String toString(){
    return String.format("Área: %s Volume: %s", obterArea(), obterVolume());
}

}
[/code]

[code]package formas;

public class Tetraedro extends FormaTridimensional {

private double alturaBase;

public Tetraedro (double b, double a, double aBase){
    super(b,a);
    alturaBase = aBase;
}

public double obterArea(){
    double area = 4 * ((base*base)* Math.sqrt(3))/4;
    return area;
}

public double obterVolume(){
    double volume = 1/3 * ((base * alturaBase/2) * altura);
    return volume;
}


public String toString(){
    return String.format("Tetraedro - %s",super.toString());
}

}
[/code]

Esta aki a main

[code]package formas;

public class Main {

public static void main(String[] args) {
    
    Quadrado q = new Quadrado(2,3);
    System.out.println(q.toString());
    
    Circulo cir = new Circulo(3);
    System.out.println(cir.toString());
    
    Cubo c = new Cubo(6);
    System.out.println(c.toString());
    
    

}

}
[/code]

e a classe cubo

[code]package formas;

public class Cubo extends FormaTridimensional{

public Cubo(double b){
    super(b);
}

public double obterArea(){
    double area = 6 * (base * base);
    return area;
}

public double obterVolume(){
    double volume = Math.pow(base,3);
    return volume;
}

public String toString(){
    return String.format(super.toString());
}

}
[/code]

Opa,

a sua classe Forma possui 2 construtores, o primeiro recebe dois parametros (base e altura) e o segundo recebe apenas o raio.

No construtor do Cubo vc está utilizando o construtor de 1 parametro (raio) e está calculando seus valores utilizando a base, que está zerada (pois você não instanciou). Provavelmente se você alterar base por raio o seu codigo irá funcionar.

[]'s

Obrigada!

funcionou desse jeito, mas naum tem como eu fazer isso de outra forma naum?
tentei criar um outro construtor, mas acusava construtor duplicado.
O q posso fazer?

Então,

não tem muito o que você fazer não. Realmetente o compiliador vai acusar metodo duplicado pois para ele não importa o nome dos parametros pois ele vai notar apenas que sao 2 metodos com mesma nome (no caso o construtor) e recebendo ambos um double cada…

O que você pode fazer eh repensar o nome dos atributos de sua classe. O que vale é bom senso mesmo…

[]'s

obrigada…

mas pelo jeito meu programa tah cheio de erros…
minha classe Tetraedro so retorna o valor da area… e do volume nao…

to ficando maluca jha…

[code]package formas;

public class Tetraedro extends FormaTridimensional {

private double alturaBase;

public Tetraedro (double b, double a, double aBase){
    super(b,a);
    alturaBase = aBase;
}

public double obterArea(){
    double area = 4 * ((base*base)* Math.sqrt(3))/4;
    return area;
}

public double obterVolume(){
    double volume = 1/3 * ((base * alturaBase/2) * altura);
    return volume;
}


public String toString(){
    return String.format(super.toString());
}

}
[/code]

Na verdade, existem alguns erros conceituais aí.

A classe Forma não deveria ter base, altura e raio. Afinal, essa é uma propriedade de algumas formas, não de todas as formas. A classe forma, representa o que é comum em todas as formas.

Fazemos isso também na biologia. Ninguém irá dizer que um mamífero tem cauda, só porque os cães e os gatos tem. Nós, seres humanos, somos mamíferos e não temos cauda.

O que é comum a todas as formas? Somente a área.

Portanto, sua classe forma deveria ser:

public abstract class Forma { public abstract double getArea(); }

Note que a forma que a área é calculada varia de forma para forma, portanto, não adianta ter por lá a implementação do método. E onde iriam a base e a largura? Na classe Quadrado.

Siga a mesma lógica para as demais classes.

O Vini tem razão na observação dele. =D

Talvez seja interessante você repensar suas classes.

Bom dia a todos.

Sim há uma maneira até mais enxuta de fazer esse polimorfismo.

Primeiro:
Para que voce declarou os atributos “base”, “altura” e “raio” com o modificador protegido (protected) se depois voce os encapsula com os métodos getters e setters :?:
Se fizer encapsulamento, então mude os modificadores protected para private, senão voce, de certo modo, quebra as regras do encapsulamento.

Segundo:
Para que servem construtores em classes abstratas, se estas classe não podem ser instanciadas :?:
Este procedimento só tem uma finalidade de invocar os seus construtores com a sintaxe super, contudo, já que voce encapsulou os atributos, então qual é a diferença entre usas “super(b,a)” de setBase(b), setAltura(a)" nas classes herdadas (extendidas) :?: Se voce pretende definir base e altura em apenas um método, então vamos construir um método void que faça isso.

Vamos então as modificações:

// Classe Forma
public class Forma {

    private double base;
    private double altura;
    private double raio;

    public double getBase() {
        return base;
    }

    public void setBase(double base) {
        this.base = base;
    }

    public double getAltura() {
        return altura;
    }

    public void setAltura(double altura) {
        this.altura = altura;
    }

    public double getRaio() {
        return raio;
    }

    public void setRaio(double raio) {
        this.raio = raio;
    }

    // Método novo que defini base e altura ao mesmo tempo    
    public void setBaseAltura(double base, double altura){
        this.base = base;
        this.altura = altura;
    }

}

// Classe Bidimensional
public abstract class FormaBidimensional extends Forma{

    public abstract double obterArea();

    @Override
    public String toString(){
        return String.format("Área: %s", obterArea());
    }

}

// Classe Tridimensional
public abstract class FormaTridimensional extends Forma {

    public abstract double obterArea();
    public abstract double obterVolume();

    @Override
    public String toString(){
        return String.format("Área: %s Volume: %s", obterArea(), obterVolume());
    }

}

// Classe Cubo
public class Cubo extends FormaTridimensional {
    
    public Cubo(double b){
        setBase(b);
    }
    
    public Cubo(double b, double a){
        setBaseAltura(b, a);
    }
    
    public double obterArea(){
        double area = 6 * (getBase() * getBase());
        return area;
    }

    public double obterVolume(){
        double volume = Math.pow(getBase(),3);
        return volume;
    }

    public String toString(){
        return String.format(super.toString());
    }

}

Repare que eu eliminei os construtores nas classes abstratas e passei a utilizar os métodos getters e setters, que outrora estavam sem finalidade, dando acesso as atributos area, altura e raio. Faça isso também nas classes “Quadrado” e “Circulo”.

Eu faria assim:

[code]public abstract class Forma {
public abtract double getArea();

@Override  
public String toString(){  
    return String.format("Área: %.2f", getArea());  
}  

}

public class Forma2D extends Forma {
public void getPerimetro();

@Override  
public String toString(){  
    return String.format("%s Perímetro: %.2f", super.toString(), getPerimetro());  
}  

}

public class Circulo extends Forma2D {
private double raio;
public Circulo(double raio) {
this.raio = raio;
}

@Override
public double getArea() {
   return Math.PI * raio * raio;
}

@Override
public double getPerimetro() {
   return Math.PI * getDiametro();
}

public void getRaio() { return raio; }
public void getDiametro() { return raio * 2; }

}

public class Retangulo extends Forma2D {
public double l1;
public double l2;

public Retangulo(double l1, double l2) {
this.l1 = l1;
this.l2 = l2;
}

public Retangulo(double l1) {
this(l1, l1);
}

@Override
public double getPerimetro() {
return 2*(l1 + l2);
}

@Override
public double getArea() {
return l1 * l2;
}

public double getLado1() {
return l1;
}

public double getLado2() {
return l2;
}
}

public class Forma3D extends Forma {
public abstract void getVolume();

@Override  
public String toString(){  
    return String.format("%s Volume: %.2f", super.toString(), getVolume());  
}  

}

public class Esfera extends Forma {
public double raio;
public Esfera(double raio) {
this.raio = raio;
}

@Override
public double getArea() {
return 4 * Math.PI * raio * raio;
}

@Override
public double getVolume() {
return 4 / 3 * Math.PI * raio * raio * raio;
}

public double getDiametro() {
return 2*raio;
}
}

public class Caixa extends Forma {
private double l1;
private double l2;
private double l3;

public Caixa(double l1, double l2, double l3) {
this.l1 = l1;
this.l2 = l2;
this.l3 = l3;
}

public Caixa(double lado) {
this(lado, lado, lado);
}

@Override
public double getArea() {
2*(l1l2 + l1l3 + l2*l3);
}

@Override
public double getVolume() {
return l1l2l3;
}

public double getLado1() {
return l1;
}

public double getLado2() {
return l2;
}

public double getLado3() {
return l3;
}

}

public class Main {
private static Forma[] formas = new Forma[4];

public static void main(String args[]) {
formas[0] = new Circulo(2);
formas[1] = new Retangulo(3, 4);
formas[2] = new Esfera(2);
formas[3] = new Caixa(3,4,5);
for (Forma forma : formas) {
System.out.println(forma.toString());
}
}
}
[/code]

PS: Não compilei o código, talvez tenha passado algum erro de sintaxe.

Tem repetição? Sim.

Mas não expressa erroneamente os conceitos. Uma forma3D não é um tipo de forma 2D. São criaturas completamente diferentes.
Da mesma forma, a esfera não é uma espécie de círculo, nem uma caixa um tipo de retângulo.

Não faz sentido em falar em perímetro de uma forma 3D. Pelo menos, não em um perímetro só.

As superclasses também não tem dados ou métodos que não fazem sentido em todas as subclasses. Aliás, desconfie quando isso ocorrer, geralmente, representa um erro de modelagem clássico, conhecido como “herança negada”, pois algumas subclasses irão ignorar parte do que o pai oferece (como sua classe Circulo, que ignorava os lados, ou a classe do quadrado, que ignorava o raio).

Muuuito obrigada pela ajuda…

pelo jeito vou ter q refazer tudo…
mas naum tem problema…

Voces ajudaram bastante… Espero q esteja sabendo tudo pra minha prova amanhã…

medooo

Algumas perguntas simples podem te ajudar.

No caso da herança, pergunte-se.

O objeto filho é um objeto pai?

Por exemplo:

Um círculo é uma forma? Sim
Uma esfera é um circulo? Não

Na hora de criar atributos, pense sempre que o atributo deve valer para todos. E, lembre-se que atributos representam uma composição, a relação tem um.

Todas as formas tem um raio? Não, só o círculo e a esfera tem. Então o atributo raio não está na classe formas.
Todos os retângulos tem um lado l1 e tem um lado l2? Sim. Então os atributos l1 e l2 estão no lugar certo.

Muito obrigada pessoal…

Vcs me ajudaram bastante…

Estou amando esse forum… é realmente esclarecedor…

[]'s