Экземпляры и методы литья типов - PullRequest
2 голосов
/ 16 июля 2009

У меня есть вопрос о технике и реализации, а не о реальной проблеме, которую нужно решить. Недавно я создал абстрактный класс, назовем его A, который определяет общее поведение его подклассов.

Я использую это для создания нескольких подклассов B, C и D, которые затем передаются другому методу вне структуры суперкласса-подкласса , которая принимает тип A (таким образом, способна обрабатывать все B, C и D).

В Java я использую instanceof для извлечения истинного типа, однако в итоге мне приходится много приводить к реальному типу, и это выглядит как беспорядок. У кого-нибудь есть предложения, как сделать код чище?

Один из методов, который я попробовал, состоял в том, чтобы восстановить экземпляр типа подкласса из параметров суперкласса, чтобы я мог обрабатывать объект с его фактическим типом, избегая, таким образом, приведения типов. Поскольку каждый из этих подклассов является синглтоном (да, они поддерживают состояние), я чувствую себя нормально, делая это. Похоже ли это на грязную вещь?

Спасибо всем, кто ответит, с благодарностью!

Редактировать: Я добавил дополнительные пояснения курсивом. Спасибо.

Ответы [ 4 ]

3 голосов
/ 16 июля 2009

Я не понимаю, почему вы наследуете их от базового класса, если вам нужно проверять тип. Абстрактный класс / интерфейс A определяет серию функций, которые B, C и D должны реализовывать, а затем функция, которая принимает экземпляр A, должна только когда-либо вызывать эти абстрактные функции. Если вам нужно вызвать функцию, которая содержит только B (и, следовательно, она не переопределена), тогда ваша функция должна использовать экземпляр B, а не A.

Или я полностью упускаю суть? У меня не было кофеина этим утром.

3 голосов
/ 16 июля 2009

Дженерики сделаны для этого.

Рассмотрим следующий пример:

public class SuperClass<T extends SuperClass> {

     public abstract void someMethod(T param);

}


public class SubClassA extends SuperClass<SubClassA> {

    public void someMethod(SubClassA param) {}
}

РЕДАКТИРОВАТЬ: Учитывая комментарий, я бы сказал, что это запах дизайна. Целому другому классу либо потребуются подклассы для связи (в этот момент может быть применена та же методика), либо существует другая проблема проектирования. Странно иметь метод для класса, который принимает суперкласс другого класса, а затем переходит к подтипу.

Если это то, что вам нужно, вы можете просто выполнить это с перегрузкой метода. Рассмотрим:

  public void someMethod(SuperClass param) {
      if (param instanceof SubClassA) {
         someMethod((SubClassA) param);
      } else if (param instanceof SubClassB) {
         someMethod((SubClassB) param);
      }
  }

  public void someMethod(SubClassA param) {}

  public void someMethod(SubClassB param) {}

Но это не вытащило тебя из ловушки if. Это зависит от того, сколько их и насколько они нестабильны, чтобы увидеть, стоит ли здесь более тяжелое решение.

0 голосов
/ 16 июля 2009

Как сказал Ишай, это похоже на дизайнерский запах. Если у вас есть instanceof-s, который изменяет поведение вашего метода, вы идете по неверному пути. Попробуйте переместить это поведение в наследники класса А.

Кроме того, вы можете использовать дженерики для параметризации класса А. Вот пример кода

abstract class A<T extends A>{
   abstract protected void someMethod(T value);
}

class B extends A<B>{
    protected void someMethod(B value) {
    }
}

class C extends A<C>{
    protected void someMethod(C value) {
    }
}
0 голосов
/ 16 июля 2009

Звучит так, как будто вы хотите шаблон посетителя . Лично я не большой поклонник, но он работает следующим образом:

class A { abstract void visit(MyVisitor visitor); }

это должно быть реализовано в каждом подклассе:

class B extends A { 
    public void visit(MyVisitor v) { v.visit(this); }
}

Таким образом, фактический посетитель использует перегрузку следующим образом:

interface MyVisitor {
   public void visit(B b);
   public void visit(C c);
}

Теперь вы можете реализовать своего посетителя и вызвать visit против вашего экземпляра A. Тогда будет вызван правильный метод обратного вызова:

A a = new B();
a.visit(this);

Если предположить, что экземпляр this реализует MyVisitor, это приведет к обратному вызову метода visit(B)

...