Can superclass become subclass?

8

I have the classes Versao , which is a general version, VersaoFirmware and VersaoSoftware . In practice the user can add one or more versions to an equipment. However, at the first moment, it is not yet known what kind of version. So I'm adding the versions with new Versao() . When it finishes adding the versions, it should select the type of versions, VersaoFirmware or VersaoSoftware .

What I've tried:

I have a% super_class which has properties common to all version types, and I have the subclasses Versao and% with% of them inheriting from the superclass, because they have everything that VersaoFirmware has, plus one or another different method. "

class Versao {
    private int id;
    private String name;

    public Versao() {}
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}


class VersaoFirmware extends Versao {
    private String outraCoisa;

    public VersaoFirmware() {}
    public String fazOutraCoisa() {
        return outraCoisa;
    }
}


class VersaoSoftware extends Versao {
    private String outraCoisa;

    public VersaoSoftware () {}
    public String fazOutraCoisa() {
        return outraCoisa;
    }
}

However, I came across the following problem: after the user selects the version type, how do I convert the general version, to the specific version? Should I create new instances of each type and pass the attributes manually? For example:

Versao versao = new Versao();
versao.setName("Versao");

VersaoSoftware versaoSoft = new VersaoSoftware();
versaoSoft.setName(versao.getName());
versaoSoft.setId(versao.getId()); // ....

But what if VersaoSoftware has 50 properties, do I have to manually pass them all? And so I also find the use of inheritance meaningless.

Complementing the title of the question, I tried to invert the class hierarchy, solved the problem, but it is totally meaningless to leave exposed specific methods for the general version.

I read about Builder Copy , which briefly creates a subclass from a superclass. But in the same way, you would have to pass all properties manually.

How do I model this system? Are there any other strategies to solve this problem?

    
asked by anonymous 26.11.2014 / 18:51

4 answers

11

Well, the concept of inheritance is somewhat misunderstood though simple. Inheritance in O.O. not just reuse code (unlike many people say), that's just a consequence. Inheritance must be applied when a class is clearly an extension of another class.

In your situation, you could not use inheritance, as far as I realize, if the idea is just to reuse attributes (not behaviors), you could choose composition:

public class DadosVersao {
   private Tipo atributoA;
   private Tipo atributoB;
}

public class VersaoSoftware {
   private DadosVersao atributos = new DadosVersao();
}

public class VersaoHardware {
   private DadosVersao atributos = new DadosVersao();
}

You could receive the attributes in the class constructor.

But if you really want to use inheritance, I think it makes sense for your class to be abstract, because it does not make sense to exist alone.

public abstract class Versao {
...
}

If you want to create a stereotype for the version, simply create an abstract method that forces the child classes to implement:

public abstract class Versao {
   public abstract String getTipo();
}

public class VersaoSoftware extends Versao {

   @Override
   public String getTipo() {
       return "software";
   }

}

And, if it is popular data of the daughter class with attributes of the mother, simple:

public class VersaoSoftware extends Versao {

   public VersaoSoftware(Atributo atributoEspecificoSoftware, Atributo atributoVersao) {
      this.atributoEspecificoSoftware = atributoEspecificoSoftware;
      super.setAtributoVersao(atributoVersao); //pode usar um atributo protected diretamente ou, ainda, não precisa do super se for o setter publico ;P
   }

   @Override
   public String getTipo() {
       return "software";
   }

}

There are many options for this, but it is best to use inheritance when it makes sense of the specialization of the class in behavioral rather than just characteristic.

    
26.11.2014 / 19:10
2

I think you've already figured it out. The best way, and a well-regarded architectural practice, is the builder copy. Something like:

 Versao versao = new Versao();
 versao.setName("Versao");

 VersaoSoftware versaoSoft = new VersaoSoftware(versao);
 VersaoFirmware versaoFirm = new VersaoFirmware(versao);

In the base class, you would do a function that would be called by the constructor functions:

 public Clone(Versao origem)
 {
       this.prop1 = origem.prop1;
       this.prop2 = origem.prop2; // etc...
 }

This causes you to change the base class without affecting other builders, after all they would always call the same function no matter what version of the software.

You could follow this same architecture for possible future changes in your daughter classes (or daughters extending daughters). So you do not have to worry about setting the properties of the parent class in the child classes, which would be a dangerous repetition of code if someone ever extends the parent class and forget to look at all the daughters.     

26.11.2014 / 19:02
2

Problem

I think you're thinking the wrong way (you should write your requirement to us, not what you already thought). I'll try to focus on the description of your problem. Going by parts, you said that:

  • You have a Equipment
  • In practice the user can add one or more versions to a equipment
  • When it finishes adding the versions, it should select the type of versions, VersaoFirmware or VersaoSoftware (this one was confused, after all a equipment has N versions or I have used the worst case scenario, being 1 equipment for N version, if necessary, you adapt later)

View your diagram :

Being:

  • 1Versionhas1TypeVersion(Iusedenumforsimplicity,butyoucanswitchtoahigherlevelentity)
  • 1VersionhasNPropertiesVersion

OutputthatIimagineyouwant

Testing classes

public class Equipamento {
    public String nome;
    public List<Versao> versoes = new ArrayList<Versao>();
}

public class Versao {
    public TipoVersao tipoVersao;
    public List<PropriedadeVersao> propriedadesVersao = new ArrayList<PropriedadeVersao>();
}

public enum TipoVersao {
    HARDWARE, SOFTWARE
}

public class PropriedadeVersao {
    public String nome;
    public String valor;
}

Sample excerpt with classes

    Equipamento equipamento = new Equipamento();
    equipamento.nome = "TV Samsung";

    // VERSAO DE HARDWARE

    Versao versaoHardware = new Versao();
    versaoHardware.tipoVersao = TipoVersao.HARDWARE;

    PropriedadeVersao propriedadeVersaoChipset = new PropriedadeVersao();
    propriedadeVersaoChipset.nome = "Chipset";
    propriedadeVersaoChipset.valor = "111.1";
    versaoHardware.propriedadesVersao.add(propriedadeVersaoChipset);

    PropriedadeVersao propriedadeVersaoAquecimentoMaximo = new PropriedadeVersao();
    propriedadeVersaoAquecimentoMaximo.nome = "Aquecimento Maximo";
    propriedadeVersaoAquecimentoMaximo.valor = "20º";
    versaoHardware.propriedadesVersao.add(propriedadeVersaoAquecimentoMaximo);

    equipamento.versoes.add(versaoHardware);

    // VERSAO DE SOFTWARE       

    Versao versaoSoftware = new Versao();
    versaoSoftware.tipoVersao = TipoVersao.SOFTWARE;

    PropriedadeVersao propriedadeVersaoFabricante = new PropriedadeVersao();
    propriedadeVersaoFabricante.nome = "Fabricante";
    propriedadeVersaoFabricante.valor = "Microsoft";
    versaoSoftware.propriedadesVersao.add(propriedadeVersaoFabricante);

    equipamento.versoes.add(versaoSoftware);

    // IMPRIME DADOS

    System.out.println("Equipamento: " + equipamento.nome);

    for (Versao versao : equipamento.versoes) {
        System.out.println("- Versao: " + versao.tipoVersao.toString());            
        for (PropriedadeVersao propriedadeVersao : versao.propriedadesVersao) {
            System.out.println("-- " + propriedadeVersao.nome + " = " + propriedadeVersao.valor);
        }
    }
    
06.12.2014 / 00:33
2

Use composition:

// coisas comuns, ainda não definiu se firmware/software
Versao versao = new Versao(1, "0.0.1");
// se firmware...
VersaoFirmware firmware = new VersaoFirmware(versao, "Firmware");
// se software...
VersaoSoftware software = new VersaoSoftware(versao, "software");

Having as superclass:

abstract class PossuiVersao {
  final Versao versao;
  PossuiVersao(Versao versao) {
    this.versao = versao;
  }
  // métodos delegam para Versao, 
  // assim PossuiVersao comporta-se como Versao.
  public int getId() {
    return versao.getId();
  }
  public String getName() {
    return versao.getName();
  }
}

And the subclasses:

class VersaoFirmware extends PossuiVersao {
  final String coisaFirmware;
  VersaoFirmware(Versao versao, String coisaFirmware) {
    super(versao);
    this.coisaFirmware = coisaFirmware;
  }
  void somenteFirmware() {
    // comportamento específico firmware
  }
}

class VersaoSoftware extends PossuiVersao {
  final String coisaSoftware;
  VersaoSoftware(Versao versao, String coisaSoftware) {
    super(versao);
    this.coisaSoftware = coisaSoftware;
  }
  void somenteSoftware() {
    // comportamento específico software
  }
}
    
08.12.2014 / 00:38