3

I am working on an assignment, and required is that I create two generic collections (called ComputerOrder and PartyTrayOrder) of several classes: ComputerPart, Peripheral, and Service, and and of Cheese, Fruit, and Service respectively. All of these classes (ComputerPart, Fruit, Service, etc) extend one class called Product.

The problem I have encountered is that it seems to be impossible to bound more than one class in Java, as you may only bound multiple interfaces, and I am not allowed to modify the existing class structure.

I've read around and seen it suggested that I create and interface that "codes in" all of the relevant classes, but I fail to see how this is possible without ComputerPart, Peripheral, etc ALSO being interfaces and then using the extend keyword. I've seen it further suggested that I create abstract classes called ComputerProduct and PartyTrayProduct, but I fail to see how this will in any way restrict the types.

I am not allowed to post images, but here is a class diagram, including some unrelated assignment objects

Here is my current code for ComputerOrder, though it only bounds the parent class product, meaning it isn't really as the assignment specifies.

public class ComputerOrder<T extends Product> extends GenericOrder<T> {
    public ComputerOrder() {
        super();
    }
}

Here are the assignment specifications:

  1. Design and implement a generic container called GenericOrder that acts as a collection of an arbitrary number of objects in Products.java. Design a mechanism that gives each instance of the container a unique identifier. You must use Java generics features.

  2. Design and implement a subclass of GenericOrder called ComputerOrder that takes an arbitrary number of different classes of ComputerPart objects, Peripheral objects, and Service objects. Implement as many methods as necessary.

  3. Design and implement a subclass of GenericOrder called PartyTrayOrder that takes an arbitrary number of different classes of Cheese objects, Fruit objects and Service objects. Implement as many methods as necessary. (...)

memyarn
  • 33
  • 3
  • That diagram shows you how the class hierarchy look alike so what is the problem? – Antoniossss Jun 16 '19 at 20:34
  • The problem is that I need to create a generic collection bounding more than one class, but I don't see a way to bound more than one class since Java will not allow me to do that without modifying some classes in the hierarchy to be interfaces. I have just edited some things to make the query more clear. – memyarn Jun 16 '19 at 20:36
  • You can bound to any level of ansestors. – Antoniossss Jun 16 '19 at 20:40
  • In a comment below, you mentioned "the assignment specification requires that the generic bound exactly ComputerPart...". But if the assignment is really written like that, then this is not true. It only says that `ComputerOrder` should be able to take the mentioned objects. It does **not** say that it should **not** be able to take a `Fruit`, for example. (Sure, that wouldn't make sense. I'm just wondering whether you're wasting time with trying to accomplish something that was not requested in the assignment (and may not even be possible - but I'd have to think more about that)) – Marco13 Jun 16 '19 at 22:26
  • Unfortunately I double-checked with the teacher and they clarified that they DID mean that one should *not* be able to take objects not specifically mentioned in the order. – memyarn Jun 17 '19 at 03:38
  • @memyarn If Product is a class, I don't think there's a way to bound one generic type to multiple classes, only interfaces. Do update your post if you find the answer outside of here. I'm now curious from what your teacher said. – ilightwas Jun 17 '19 at 07:06
  • @memyarn An aside: If you reply to a comment, mentioning someone (e.g. with `@Marco13`) will cause him to receive a notification - otherwise, your comment might be overlooked. – Marco13 Jun 17 '19 at 12:30
  • See https://stackoverflow.com/questions/21824402/java-multiple-inheritance – Raedwald Jun 17 '19 at 15:27

2 Answers2

3

Here's the only solution that I came up with, which follows the assignment to the letter and still makes some sense (even though I think that it is not a "good" solution - see the notes below): The ComputerOrder and PartyTrayOrder could offer methods that only accept the specialized types of Product:

abstract class Product {}
class ComputerPart extends Product {}
class Peripheral extends Product { }
class Cheese extends Product {} 
class Fruit extends Product {}
class Service extends Product {} 

abstract class GenericOrder<T extends Product> {
    protected final void addImpl(T t) {
    }
}

class ComputerOrder extends GenericOrder<Product> {
    void add(ComputerPart t) {
        addImpl(t);
    }
    void add(Peripheral t) {
        addImpl(t);
    }
    void add(Service t) {
        addImpl(t);
    }
}

class PartyTrayOrder  extends GenericOrder<Product> {
    void add(Cheese t) {
        addImpl(t);
    }
    void add(Fruit t) {
        addImpl(t);
    }
    void add(Service t) {
        addImpl(t);
    }
}

This way, the order implementations could exactly accept the right types:

public class ProductExample {

    public static void main(String[] args) {
        ComputerOrder c = new ComputerOrder();
        c.add(new ComputerPart());
        c.add(new Peripheral());
        //c.add(new Cheese()); // Not allowed
        //c.add(new Fruit()); // Not allowed
        c.add(new Service());

        PartyTrayOrder p = new PartyTrayOrder();
        //p.add(new ComputerPart());  // Not allowed
        //p.add(new Peripheral());  // Not allowed
        p.add(new Cheese());
        p.add(new Fruit());
        p.add(new Service());

    }
}

I assume that this is the intended solution, because the assignment contains the broad hint:

Implement as many methods as necessary.

So most likely, the goal is not to implement one method that is magically bounded for multiple classes. Instead, one method for each "category" has to be added.


An aside: My gut feeling is that this design could be improved. Just imagine you'd have to create classes CarOrder and FahsionOrder etc. for new types of orders. Or imagine the PartyTrayOrder would have to be extended to also handle classes like Meat or Dip or Salad: You'd end up with dozens of classes with dozens of specialized methods.

This could all be avoided by introducing a dedicated "product type" that exactly matches the types that are acceptable for specific "order type". So I think that (Productshould be an interface to begin with, and) there should be interfaces like ComputerProduct and PartyTrayProduct, as in

interface Product {}

interface ComputerProduct extends Product {}
class ComputerPart implements ComputerProduct  {}
class Peripheral implements ComputerProduct  {}

interface PartyTrayProduct extends Product {}
class Cheese implements PartyTrayProduct{} 
class Fruit implements PartyTrayProduct{}

class Service implements Product {} 
class DeliveryService implements PartyTrayProduct{} 
class AssemblyService implements ComputerProduct  {}

That way, the required bounds for the specific ComputerOrder and PartyTrayOrder are already modeled with the class hierarchy. The advantage then is: You don't need the ComputerOrder and PartyTrayOrder classes any more! The GenericOrder could then be non-abstract, and in order to create the specific types of orders you'd just properly use the generic type bound.

Here is a complete example, where I've just thrown in Salad as a new PartyTrayProduct, and CarPart as a new type of product, without having to extend or modify any of the "infrastructure classes":

interface Product {}

interface ComputerProduct extends Product {}
class ComputerPart implements ComputerProduct  {}
class Peripheral implements ComputerProduct  {}

interface PartyTrayProduct extends Product {}
class Cheese implements PartyTrayProduct{} 
class Fruit implements PartyTrayProduct{}

class Service implements Product {} 
class DeliveryService implements PartyTrayProduct{} 
class AssemblyService implements ComputerProduct  {}

class Salad implements PartyTrayProduct{} // A new PartyTrayProduct

// Entirely new product type:
interface CarProduct extends Product {}
class CarPart implements CarProduct  {}
class CarInterior implements CarProduct  {}

class GenericOrder<T extends Product> {
    public void add(T t) { }
}

public class ProductExample2 {
    public static void main(String[] args) {

        GenericOrder<ComputerProduct> c = new GenericOrder<ComputerProduct>();
        c.add(new ComputerPart());
        c.add(new Peripheral());
        //c.add(new Cheese()); // Not allowed
        //c.add(new Fruit()); // Not allowed
        c.add(new AssemblyService());

        GenericOrder<PartyTrayProduct> p = new GenericOrder<PartyTrayProduct>();
        //p.add(new ComputerPart());  // Not allowed
        //p.add(new Peripheral());  // Not allowed
        p.add(new Cheese());
        p.add(new Fruit());
        p.add(new Salad()); // Just add it...
        p.add(new DeliveryService());

        // Easy to extend:
        GenericOrder<CarProduct> e = new GenericOrder<CarProduct>();
        e.add(new CarPart());
        e.add(new CarInterior());
    }
}
Marco13
  • 53,703
  • 9
  • 80
  • 159
  • Thank you so much! This is the method that I ended up going with, since nothing else seemed to be possible at all. Thank you for your comprehensive explanation! – memyarn Jun 23 '19 at 18:11
0

That diagram shows you exactly how class hierarchy looks alike. Every fat arrow is a class extension. When arrow points from A to B it means that A extends B. You just have to close that into java code.

When A extends B and B extends C, A is a C. I see no need for multiple base inheritance here.

Antoniossss
  • 31,590
  • 6
  • 57
  • 99
  • The diagram is generated from code that already exists, for example here is my code for ComputerPart ```class ComputerPart extends Product { public ComputerPart(float p) { price = p; } public float price() { return price; } }``` The class diagram as I have linked is auto-generated from code that I already have written, it is not a blueprint provided to me. Edit: Oh I see your point now. – memyarn Jun 16 '19 at 20:41
  • I've added another comment to specify that while I see your point, the assignment specification requires that the generic bound exactly ComputerPart, Peripheral, and Service (for example), so I cannot just have it bound Product. That is what I initially did, but that would also include classes that are specifically disallowed (Cheese, Fruit). – memyarn Jun 16 '19 at 20:45