angryITguy
angryITguy

Reputation: 9551

How do I create a list of multiple types using an interface?

I have been struggling to grasp this concept in Java. I have a list of objects I need to print. Either a string or bitmap. Each has its own way to be printed. My current interface would look like this:

public interface IPrintJob {
    void print();
}

I have PrintJobText, and PrintJobBitmap classes which each implements IPrintJob. I need to be able to add them both to the same list. Can I do it with

ArrayList<IPrintJob> printjobs

Is this the right approach ? Should this be done with generics ? How would PrintJobText/PrintJobBitmap classes look ? I'm a bit lost after trawling the net for an understanding on the best way to handle this.

Upvotes: 1

Views: 904

Answers (3)

Rees Pozzi
Rees Pozzi

Reputation: 1

Create a custom class that could contain attributes of either a string or a bitmap to contain the relevant object but under a different guise I guess, you can then create an array list of these custom objects, and use if ( object instanceof string ) then // do string code, and vice versa for bitmaps.

Upvotes: 0

cegredev
cegredev

Reputation: 1579

Depends on what you mean by

Each has its own way to be printed

in my opinion. If you just mean what this answer demonstrates, you could also simply override toString() in both of the classes like this:

public class PrintJobText {

   private String text;

   PrintJobText(String text) {
      this.text = text;
   }

   @Override
   public String toString() {
       return text;
   }
}

public class PrintJobBitmap {

   private boolean bit;

   PrintJobBitmap(boolean bit) {
      this.bit = bit;
   }

   @Override
   public String toString() {
       return String.valueOf(bit);
   }
}

And simply store the objects in a List<Object> or some other common super-class.

Now does that mean you should do it this way? Probably not. At least don't store the objects in a List<Object>, because what if you wanted to add more functionality to your interface down the line?

Not only would you need to refactor a bunch of type definitions, but before the change nothing would have stopped you from adding instances of classes to the list that don't make any sense to be there, so now you either have to figure out a way to implement the new methods for those classes as well or restructure your code so those classes never get added to the list in the first place.

Another pitfall is that classes could forget to override toString() because there's no way to enforce them to do so.

Another possible definition of the interface could like this:

public interface IPrintJob {
    String getPrintValue();
}

This would cut both the problems I mentioned above and is slightly cleaner than having a void print() as it removes the duplication of System.out.println(...) in the implementations.

Upvotes: 1

Tomas F
Tomas F

Reputation: 7596

One example could be like this.. (not completely sure what you mean with a bitmap in this case though, so just made it a boolean)

public interface IPrintJob {
    void print();
}

public class PrintJobText implements IPrintJob {
   private String text;
   PrintJobText(String text) {
      this.text = text;
   }
   void print() {
       System.out.println(text);
   }
}

public class PrintJobBitmap implements IPrintJob {
   private boolean bit;
   PrintJobBitmap(boolean bit) {
      this.bit = bit;
   }
   void print() {
       System.out.println(bit ? "true" : "false");
   }
}

List<IPrintJob> printjobs = new ArrayList<>();
printJobs.add(new PrintJobText("test1");
printJobs.add(new PrintJobBitmap(true);

printJobs.forEach(IPrintJob::print);

Of course the implementation of the print method can be anything. The system out is just an example.

Upvotes: 2

Related Questions