2

I have an interface called Section and MapSection which extends section. I have a list of Sections and if it is a MapSection I need to do some additional processing. I can thing of two ways to handle this. I can add a boolean isAMapSection() to the Section interface but that leads to alot of isA.. if I add more types. The other way I could think of is instanceof check but my OOP senses think this is not great either.

curSection instanceof MapSection

which one of these is the right way? or is there another way?

user1634451
  • 5,133
  • 6
  • 30
  • 43

3 Answers3

6

As mentioned above by Oliver Charlesworth's comment, you could use a Visitor Design Pattern to give your code to do different actions depending on the type involved, without having to use a bunch of instanceof's or class equals.

For example, say you have two similar interfaces, Section and MapSection, where for grins will give MapSection one additional method:

interface Section {
   void someMethod();
   void accept(SectionVisitor visitor);
}

interface MapSection extends Section {
   void additionalProcessingMethod();
}

We'll also give Section the accept(...) method to allow action by a Visitor of type SectionVisitor whose interface looks like:

interface SectionVisitor {
   void visit(Section section);
   void visit(MapSection mapSection);
}

The visit method will hold code that knows which methods to call depending on the type passed into it.

A very simple concrete example could look like:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class VisitorTest {
   public static void main(String[] args) {
      Random random = new Random();
      List<Section> sectionList = new ArrayList<>();
      for (int i = 0; i < 10; i++) {
         Section section = random.nextBoolean() ? new ConcreteSection() : new ConcreteMapSection();
         sectionList.add(section);
      }

      SectionVisitor visitor = new ConcreteSectionVisitor();
      for (Section section : sectionList) {
         section.accept(visitor);
      }
   }
}

interface Section {
   void someMethod();
   void accept(SectionVisitor visitor);
}

interface MapSection extends Section {
   void additionalProcessingMethod();
}

interface SectionVisitor {
   void visit(Section section);
   void visit(MapSection mapSection);
}

class ConcreteSection implements Section {

   @Override
   public void someMethod() {
      System.out.println("someMethod in ConcreteSection");
   }

   @Override
   public void accept(SectionVisitor visitor) {
      visitor.visit(this);
   }

}

class ConcreteMapSection implements MapSection {

   @Override
   public void someMethod() {
      System.out.println("someMethod in ConcreteMapSection");
   }

   @Override
   public void additionalProcessingMethod() {
      System.out.println("additionalProcessingMethod in ConcreteMapSection");
   }

   @Override
   public void accept(SectionVisitor visitor) {
      visitor.visit(this);
   }

}

class ConcreteSectionVisitor implements SectionVisitor {

   @Override
   public void visit(Section section) {
      section.someMethod();
   }

   @Override
   public void visit(MapSection mapSection) {
      mapSection.someMethod();
      mapSection.additionalProcessingMethod();
   }

}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
3

Best way might be to add a method "additionalProcessing" to Section. Implement this method to do your additional processing in MapSection, and leave it blank in your other implementations

ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
3

Sometimes it's fine to have an isXXX method (and the corresponding asXXX method is nice too), but it really depends on how open-ended your object hierarchy is.

For example in StAX the XMLEvent interface will have descendants that represent the different types of events that can come from an XML document. But the list of those types is closed (no-one's going to radically change the XML format any time soon) and very short (there are about 10 different types of events in the StAX API), so it's fine. These interfaces also define the primary nature of their implementations, you wouldn't realistically just tag an object with an XMLEvent interface like you do with Serializable or Iterable.

If your interface is more "behavioural" (for want of a better word), more optional (like Comparable) or too open-ended (like LayoutManager), things like the visitor or the strategy pattern may be more appropriate.

Judging just by the names Section and MapSection, your model seems to belong to the first category but really only you can make that decision. What I definitely wouldn't do is leave it to the client of the code to fool around with instanceof calls. One way or another the solution should be part of Section.

biziclop
  • 48,926
  • 12
  • 77
  • 104