Перегруженный конструктор, вызывающий другого конструктора, но не как первый оператор

Я испытываю некоторые затруднения с помощью нескольких конструкторов в Java.

то, что я хочу сделать, является чем-то вроде этого:

public class MyClass {

 // first constructor
 public MyClass(arg1, arg2, arg3) {
  // do some construction
 }

 // second constructor
 public MyClass(arg1) {
      // do some stuff to calculate arg2 and arg3
      this(arg1, arg2, arg3);
    }
}

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

Каково общее решение для такой ситуации? Я не могу вычислить arg2 и arg3 "в строке". Я думал, возможно, создавая вспомогательный метод конструкции, который сделает фактическую конструкцию, но я не уверен, что это так "симпатично"...

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

17
задан David B 7 September 2012 в 20:54
поделиться

9 ответов

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

public class MyClass { 

    // first constructor 
    public MyClass(arg1, arg2, arg3) { 
      init(arg1, arg2, arg3); 
    } 

    // second constructor 
    public MyClass(int arg1) { 
      // do some stuff to calculate arg2 and arg3 
      init(arg1, arg2, arg3); 
    } 

    private init(int arg1, int arg2, int arg3) {
      // do some construction 
    }
} 

Альтернативой является подход в стиле Factory, в котором у вас есть MyClassFactory , который предоставляет вам экземпляры MyClass , а MyClass имеет только один конструктор:

public class MyClass { 

    // constructor 
    public MyClass(arg1, arg2, arg3) { 
      // do some construction 
    } 
} 

public class MyClassFactory { 

    public static MyClass MakeMyClass(arg1, arg2, arg3) { 
      return new MyClass(arg1, arg2, arg3);
    } 

    public static MyClass MakeMyClass(arg1) { 
      // do some stuff to calculate arg2 and arg3 
      return new MyClass(arg1, arg2, arg3);
    } 
} 

Я определенно предпочитаю первый вариант.

24
ответ дан 30 November 2019 в 10:45
поделиться

Следующее возможное решение - Заводской метод . Эти статические методы могут быть перегружены, и после расчета они могут вызывать закрытый / защищенный конструктор

public class MyClass {

    private MyClass( arg1, arg2, arg3 ) {
         // do sth
    }

    public static MyClass getInstance( arg1 ) {
         // calculate arg2,3
        return new MyClass( arg1, arg2, arg3 );
    }

    public static MyClass getInstance( arg1, arg2, arg3 ) {
        return new MyClass( arg1, arg2, arg3 );
    }
}

EDIT: Этот метод также является идеально, когда у вас есть финальные поля

9
ответ дан 30 November 2019 в 10:45
поделиться

Другой способ:

public class MyClass {

  // first constructor
  public MyClass(arg1, arg2, arg3) {
   // do some construction
   doSomeStuffToArg3Arg3(arg2, arg3)
  }

  // second constructor
  public MyClass(int arg1) {
      this(arg1, arg2, arg3);
  }

  private void doSomeStuffToArg3Arg3(int arg2, int arg3) {
     // do some stuff to calculate arg2 and arg3
  }
}
1
ответ дан 30 November 2019 в 10:45
поделиться

Можно создать фабричный метод, который вызывает конструктор:

public class MyClass { 

    // first constructor 
    public MyClass(arg1, arg2, arg3) { 
    // do some construction

    } 

    // second constructor as factory method
    public static createMyClassAndDoFunkyStuff(int arg1) { 
      // do some stuff to calculate arg2 and arg3 
      return new MyClass(arg1, arg2, arg3); 
    } 

} 
0
ответ дан 30 November 2019 в 10:45
поделиться

Вы можете переместить код MyClass(arg1, arg2, arg3) в вспомогательный метод (назовите его Init или как-то еще) и затем вызвать этот метод в обоих конструкторах.

0
ответ дан 30 November 2019 в 10:45
поделиться

В качестве альтернативы приведенным ответам, самый простой способ - это преобразовать вычисление аргументов в конструктор с тремя аргументами;

public class MyClass {

    // first constructor
    public MyClass(arg1, arg2, arg3) {
        if (null == arg2) {
            // calculate arg2
        }
        if (null == arg3) {
            // calculate arg3
        }
        // do some construction
    }

    // second constructor
    public MyClass(arg1) {
        this(arg1, null, null);
    }
}
0
ответ дан 30 November 2019 в 10:45
поделиться

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

public class MyClass {
    public MyClass(int arg1, int arg2, int arg3) {
        // do some construction
    }

    public MyClass(int arg1) {
      //call to this() must be the first one
      this(arg1, calculateArg2(arg1), calculateArg3());
      //you can do other stuff here
    }

    private static int calculateArg2(int arg1) {
      //calc arg2 here
    }

    private static int calculateArg3() {
      //calc arg3 here
    }
}
8
ответ дан 30 November 2019 в 10:45
поделиться

Используйте значения маркеров для «пропавших без вести»

public class MyClass {
 public MyClass(arg1, arg2, arg3) {
  // do some stuff to calculate arg2 and arg3 if they are the missing values
  // do some construction
 }
 public MyClass(arg1) {
   this(arg1, null, null);
 }
}

Для достижения наилучших результатов сделайте «общий» конструктор защищенным или частный .

3
ответ дан 30 November 2019 в 10:45
поделиться

Вспомогательная и заводская опции очень хороши.

Есть еще один:

public MyClass(int arg1) {
    this(arg1, calculateArg2(), calculateArg3());
}

private static int calculateArg2() {..}
private static int calculateArg3() {..}
4
ответ дан 30 November 2019 в 10:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: