在子类中重写Setter方法

7

我在这里遇到了一个问题。我想要在子类中更改来自超类(父类)的属性的setter,但是当我在子类中覆盖此方法时,我无法访问超类中的私有属性。而且关键是,它们必须保持私有。

超类(问题:setMinimumVoorraad(int voorraad);)

包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;
    }


}

子类

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;
    }


}

有人能帮助我吗? 提前感谢。


1
相当明显,我们需要看到代码。 - T.J. Crowder
2个回答

11

一种可能性是通过在子类中实现基于父类的setter(假设您确实可以访问它)来完成。

例如,假设setter为setFoo,那么子类的版本可能如下:

public void setFoo(Foo f) {

    // Do subclass stuff pre-setting, if any

    super.setFoo(f);

    // Do subclass stuff post-setting, if any
}

谢谢,但我想摆脱已在我的超类中定义的条件。 - Energyfellow
3
@Energyfellow说:“这听起来像是你会违反超类的合约。子类不应该这样做。但从实用的角度来看,如果这些字段是私有的,而且你唯一可以访问的setter做了一些你不想要的事情,那么你就无能为力了。(按设计而言;超类正在保护其定义的行为。)” - T.J. Crowder

3

NPE上面给出的答案是解决这个问题的最佳方法。它很优雅,遵循超类和子类之间的基本继承契约。即使在您的原始帖子中,子类实际上比超类更加受限制,因此做一些类似以下的操作:

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

正如NPE建议的那样,可能会起作用。(请注意我修改了您的if测试。不确定是否有错别字,但在原始实现中,5将是有效的最小值,但像4这样的输入将将其设置为6。)
其他(可能可以接受的)模式包括:
1. 将父类中的成员变量设置为protected,这将提供可见性。(请注意,您确实提到了私有限制;仅提供此模式是为了提供更完整的整体答案。) 2. 将验证逻辑委托给另一个非私有方法。这样,子类就可以重写验证方法。
现在进入(可能不可接受的)使用Java反射的模式:
@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
    }
}

值得注意的是,如果您在一生中从未这样做过,您可能会因此受益。它不仅完全打破了所有合同,而且依赖于硬编码字符串来查找字段名称,这本身就很痛苦。但它确实存在。没有一个好的答案(NPE已在上面给出)是完整的,如果没有一个如何不做某事的例子...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接