user2374720 user2374720 - 7 days ago 6
Java Question

Access to a common method without casting objects

I have a type of class which is the GeneralProduct and it looks as follows:

public class GeneralProduct()
{
String label;
Object obj;
public GeneralProduct(String label, Object obj)
{
this.label = label;
this.obj = obj;
}
}


Then I have two different classes,
ProductA
and
ProductB
. These both classes have a common method called
getPrice()
. On the other hand, I have an array called
auxList
:

ArrayList<GeneralProduct> auxList = new ArrayList<GeneralProduct>();
auxList.add(new GeneralProduct(new ProductA(), "ProductA"));
auxList.add(new GeneralProduct(new ProductB(), "ProductB"));


The problem now is that I can't access
getPrice()
in classes
ProductA
and
ProductB
from the
auxList
. How could I manage this? Should I use something like this? And if so, how can I inherit the method getPrice() from the children?

public class ProductA extends GeneralProduct

Answer

In your question, it seems like ProductA and ProductB are meant to be subclasses of GeneralProduct; that is, that ProductA "is a" GeneralProduct, just more specialized.

If so: Define GeneralProduct with an abstract getPrice method (but keep readingĀ¹), which the subclasses implement. You'd probably also do away with obj, you don't need it:

public abstract class GeneralProduct {
    String label;
    public GeneralProduct(String label)
    {
        this.label = label;
    }

    public abstract double getPrice();
}

class ProductA extends GeneralProduct {
    @Override
    public double getPrice() {
        // implementation
    }
}

// and the same for ProductB

Then:

auxList.add(new ProcuctA("ProductA"));
auxList.add(new ProcuctB("ProductB"));

(But you can put obj back if you need it for something.)

Note that getPrice doesn't have to be abstract, if there's a reasonable implementation that GeneralProduct could provide, making overriding it in a subclass optional.

You can even take it further and separate out the interface of products from the implementation:

public interface Product {
    double getPrice();
}

Then the list would be

List<Product> list = new ArrayList<Product>();

If you still need GeneralProduct (if there's a need for a base class), it can implement that interface.

public abstract class GeneralProduct implements Product {
    // ...
}

But if you don't need a base class at all, ProductA and ProductB can just implement the interface themselves.


However, inheritance is only one way to provide functionality, and sometimes it's the right way, and other times another approach is useful: Composition. In this case, GeneralProduct would "have a" ProductA or ProductB, but ProductA (and ProductB) wouldn't have an "is a" relationship with GeneralProduct.

That still probably involves an interface and/or an abstract class, just in a different place:

public interface Product {
    double getPrice();
}

class ProductA implements Product {
    public double getPrice() {
        // implementation
    }
}

// ...same for ProductB

public class GeneralProduct {
    String label;
    Product product;
    public GeneralProduct(String label, Product product)
    {
        this.label = label;
        this.product = product;
    }

    // You might have something like this, or not
    public double getProductPrice() {
        return this.product.getPrice();
    }
}

// Then using it:
auxList.add("ProductA", new ProcuctA("ProductA"));
auxList.add("ProductB", new ProcuctB("ProductB"));

Both inheritance and composition are powerful tools.

Comments