Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override Setter in Subclass

I'm stuck with a problem here. I want to change the setter from a attribute from the superclass (parent class) in my subclass (child) however when I overide this method in my subclass I can't access my private attributes from the supperclass. And the point is, they have to stay private.

Superclass (problem: setMinimumVoorraad(int voorraad);)

package domein;

public abstract class Artikel implements Weegbaar
{
    private String omschrijving;
    private double prijs;
    private int aantalInStock;
    private int minimumVoorraad;

    public Artikel(String omschrijving, double prijs, int aantalInStock, int minimumVoorraad)
    {
        this.setOmschrijving(omschrijving);
        this.setPrijs(prijs);
        this.setAantalInStock(aantalInStock);
        this.setMinimumVoorraad(minimumVoorraad);
    }

    @Override
    public String toString()
    {
        String output = String.format(" \n omschrijving: %s \n prijs:  %f \n In stock %d (minimumvoorraad = %d) \n", this.omschrijving, this.prijs, this.aantalInStock, this.minimumVoorraad);
        return output;
    }
//----Getters----
    public String getOmschrijving() {
        return omschrijving;
    }

    public double getPrijs() {
        return prijs;
    }

    public int getAantalInStock() {
        return aantalInStock;
    }

    public int getMinimumVoorraad() {
        return minimumVoorraad;
    }

//----Setters----
    public void setOmschrijving(String omschrijving) {
        this.omschrijving = omschrijving;
    }

    public void setPrijs(double prijs) {
        this.prijs = prijs;
    }

    public void setAantalInStock(int aantalInStock) {
        this.aantalInStock = aantalInStock;
    }

    public void setMinimumVoorraad(int minimumVoorraad) 
    {
        if(minimumVoorraad < 2)
            this.minimumVoorraad = 3;
        else
            this.minimumVoorraad = minimumVoorraad;
    }


}

Subclass

package domein;


public class Food extends Artikel
{

    private String houdbaarheidsDatum;
    private double nettoGewicht;

    public Food(String omschrijving, double prijs, int aantalInStock, int minimumVoorraad, String houdbaarheidsDatum, double nettoGewicht)
    {
        super(omschrijving, prijs, aantalInStock, minimumVoorraad);
        this.setHoudbaarheidsDatum(houdbaarheidsDatum);
        this.setNettoGewicht(nettoGewicht);
    }

    @Override
    public boolean isWeegbaar()
    {
        return true;
    }


//----Getters----
    public String getHoudbaarheidsDatum() {
        return houdbaarheidsDatum;
    }

    public double getNettoGewicht() {
        return nettoGewicht;
    }

//----Setters----
    public void setHoudbaarheidsDatum(String houdbaarheidsDatum) {
        this.houdbaarheidsDatum = houdbaarheidsDatum;
    }

    public void setNettoGewicht(double nettoGewicht) {
        this.nettoGewicht = nettoGewicht;
    }

    @Override
    public void setMinimumVoorraad(int minimumVoorraad) 
    {
        if(minimumVoorraad < 5)
            this.minimumVoorraad = 6;
        else
            this.minimumVoorraad = minimumVoorraad;
    }


}

Someone who can help me? Thanks in advance.

like image 473
Energyfellow Avatar asked Mar 26 '13 07:03

Energyfellow


2 Answers

One possibility is to implement the subclass's setter in terms of the superclass's setter (which, presumably, you do have access to).

For example, assuming the setter is setFoo, then the subclass's version might be:

public void setFoo(Foo f) {

    // Do subclass stuff pre-setting, if any

    super.setFoo(f);

    // Do subclass stuff post-setting, if any
}
like image 72
NPE Avatar answered Oct 18 '22 01:10

NPE


The answer given above by NPE is absolutely the best way to go about solving this problem. It is elegant and honors basic inheritance contracts between superclass and subclass. Even in your original post, the subclass is actually more restrictive than the superclass, so doing something like:

@Override
public void setMinimumVoorraad(int minimumVoorraad) 
{
    if(minimumVoorraad <= 5)
        super.setMinimumVoorraad(6);
    else
        super.setMinimumVoorraad(minimumVoorraad);
}

exactly as NPE suggested would probably work. (Note how I modified your if test. Not sure if it's a typo, but in the original implementation 5 would be a valid minimum, but input like 4 would set it to 6.)

Other (possibly acceptable) patterns would be to:

  1. Make the members in your Parent class protected, which would give visibility. (Realize that you did mention a private restriction; this pattern is solely mentioned to provide a more complete overall answer.)
  2. Delegate the validation logic to another method (that is non-private). This way the child can override the validation method.

And now on to the (probably unacceptable) pattern of using Java reflection:

@Override
public void setMinimumVoorraad(int minimumVoorraad) {

    try {
        Field field = this.getClass().getSuperclass().getDeclaredField("minimumVoorraad");
        field.setAccessible(true);

        if(minimumVoorraad <= 5)
            field.set(this, 6);
        else
            field.set(this, minimumVoorraad);

        field.setAccessible(false);
    }
    catch(NoSuchFieldException | IllegalAccessException e) {
        // do something
    }
}

It's worth noting that if you never ever do this in your entire life you will probably be the better for it. Not only does it completely break all contracts, but it relies on hard-coded Strings to do field name lookups, which in and of itself is pretty painful. But it does exist. And no good answer (already given above by NPE) would be complete without an example of how not to do something...

like image 25
SeKa Avatar answered Oct 18 '22 01:10

SeKa