2014-09-27 7 views
1

У меня есть интерфейс под названием Section и MapSection, который расширяет раздел. У меня есть список разделов, и если это MapSection, мне нужно сделать некоторую дополнительную обработку. Я могу с двумя способами справиться с этим. Я могу добавить логический isAMapSection() в интерфейс раздела, но это приводит к alot isA .. если я добавляю больше типов. Другой способ, о котором я мог думать, - проверить экземпляр, но мои чувства ООП считают, что это тоже не здорово.instanceof vs boolean type check

curSection instanceof MapSection 

который один из них является правильным способом? или есть другой способ?

+9

Это то, что полиморфизм для. Или, возможно, шаблон посетителя. –

ответ

3

Как упоминалось выше, комментарий Оливера Чарльворта, вы можете использовать Visitor Design Pattern, чтобы дать вашему коду разные действия в зависимости от типа, без необходимости использовать кучу экземпляров или классов.

Например, у вас есть два подобных интерфейсов, раздел и MapSection, где для усмешек даст MapSection один дополнительный метод:

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

interface MapSection extends Section { 
    void additionalProcessingMethod(); 
} 

Мы также дадим Раздел метод accept(...) разрешить действие на посетителя типа SectionVisitor, чей интерфейс выглядит следующим образом:

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

метод visit проведет код, который знает, какие методы для вызова в зависимости от типа, перешедшего в него.

Очень простой конкретный пример может выглядеть следующим образом:

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

} 
1

Лучшим способом может быть добавление метода «дополнительная обработка» в раздел. Внесите этот метод, чтобы выполнить дополнительную обработку в MapSection, и оставьте его пустым в других реализациях.

2

Иногда бывает хорошо, что есть метод isXXX (и соответствующий метод asXXX тоже хорош), но это действительно зависит от того, закончилась ваша иерархия объектов.

Например, в StAX интерфейс XMLEvent будет иметь потомки, которые представляют различные типы событий, которые могут быть получены из XML-документа. Но список этих типов закрыт (никто не собирается радикально изменять формат XML в ближайшее время) и очень короткий (в STAX API есть около 10 различных типов событий), так что это нормально. Эти интерфейсы также определяют основную природу их реализаций, вы бы не просто пометили объект с помощью интерфейса XMLEvent, как и с Serializable или Iterable.

Если интерфейс является более «поведенческая» (за неимением лучшего слова), более необязательных (как Comparable) или слишком открытого состава (как LayoutManager), такие вещи, как посетитель или шаблон стратегия может быть более подходящим.

Судя по именам Section и MapSection, ваша модель относится к первой категории, но на самом деле вы можете принять это решение. То, что я определенно не сделал бы, это оставить его клиенту кода, чтобы обмануть его с помощью вызовов instanceof. Так или иначе решение должно быть частью Section.