2014-09-25 3 views
1

Класс A происходит от абстрактного класса B и реализует абстрактный метод foo. Теперь в методе foo я хочу сделать что-то, что зависит от переменной-члена класса A, mType. Однако это приводит к ошибке, поскольку foo вызывается в конструкторе из абстрактного класса B, поэтому mType еще не инициализирован.Инициальная переменная-член перед вызовом конструктора базового класса

Невозможно инициализировать mType перед супер(), поэтому я не знаю, как это сделать. Конечно, я могу сделать mType членом B, но я думаю, что это не очень хороший способ, потому что mType не имеет никакого отношения к этому классу, в этом примере это, возможно, неясно, но, конечно, я переписал практическую ситуацию на короткий простой, чтобы объяснить проблему.

Что такое хороший способ решить эту проблему?

public abstract class B { 
    public B() { 
     foo(); // A::mType IS NOT INITIALISED!! 
    } 

    protected abstract void foo(); 
} 

private class A extends B { 
    public enum Type { TYPE1, TYPE2 }; 

    public A(Type aType) { 
     super(); 
     mType = aType; 
    } 

    @Override 
    protected void foo() { 
     if (mType == Type.TYPE1) { 
      // .. 
     } else { 
      // ... 
     } 
    } 
} 
+3

[Никогда не вызывайте переопределяемые методы из конструктора] (http://stackoverflow.com/questions/3404301/whats-wrong-with-overridable-method-calls-in-constructors). – Seelenvirtuose

+0

Вы можете просто сделать любой код установки, который вы делаете в 'foo()' в конструкторе? Зачем переопределять его, если вы просто вызываете его немедленно? –

+0

Плохая практика вызова переопределяемых методов в конструкторе, но если вы * must *, вы можете изменить подпись 'foo', чтобы взять' foo (Type) 'и делать все, что вы там хотите, то есть назначить своего участника и выполнить другую проверку и т.п. – webuster

ответ

0

Соглашаясь на комментарий, сделанный Seelenvirtuose, я собираюсь ответить на мой вопрос. Это действительно вредная практика для вызова переопределяемых методов в конструкторе. Далее решает эту проблему:

public abstract class B { 
    public B() { } 

    protected abstract void foo(); 

    protected void init() { 
     foo(); 
    } 
} 

private class A extends B { 
    public enum Type { TYPE1, TYPE2 }; 

    public A(Type aType) { 
     super(); 
     mType = aType; 
     init(); 
    } 

    @Override 
    protected void foo() { 
     if (mType == Type.TYPE1) { 
      // .. 
     } else { 
      // ... 
     } 
    } 
} 

На первом взгляде может показаться, возможно, непрактично, почему бы не просто вызвать Foo в конструкторе класса А. Но в моей реальной практической ситуации, а более сложным, различные перекрытые методы должны для вызова в определенной последовательности. Базовый класс должен предоставить метод для этого, чтобы избежать дублирования кода. Эта проблема возникает при добавлении простого метода init, который вызывается из производного класса.

Смежные вопросы