Метод, чтобы взять несколько типов
В настоящее время я работаю с конструктором, который принимает объект типа. Затем я проверяю его тип на основе instanceof.
Public MyClass (Object obj)
{
if(obj instanceof CusClass1){
CusClass1 myObject = (CusClass1) obj;
globalVar1 = myObject.getAttrib1();
globaVar2 = myObject.getAttrib2();
}
if(obj instanceof CusClass2){
CusClass2 myObject = (CusClass2) obj;
globalVar1 = myObject.getAttrib1();
globaVar2 = myObject.getAttrib2();
}
}
Можно ли сместить метод инициализации, вызываемый из конструктора. Основная проблема заключается в кастинге Объекта. У меня всегда было впечатление, что повторяющийся код - это плохой код. Можно ли сделать это более элегантным?
6 ответов
Гораздо лучший, более безопасный для типов дизайн - создание нескольких перегруженных конструкторов. В таком случае вам не понадобятся никакие приведения, и вы не сможете создать объект, передав ему объект неподходящего типа.
public MyClass(CusClass1 myObject) {
globalVar1 = myObject.getAttrib1();
globalVar2 = myObject.getAttrib2();
}
public MyClass(CusClass2 myObject) {
globalVar1 = myObject.getAttrib1();
globalVar2 = myObject.getAttrib2();
}
Делать CusClass1
а также CusClass2
имеют те же getAttrib1()
а также getAttrib2()
методы? Затем рассмотрите возможность создания интерфейса, который реализуют оба этих класса, и создайте конструктор, который принимает объект, реализующий этот интерфейс:
public interface Attribs {
String getAttrib1();
int getAttrib2();
}
public class CusClass1 implements Attribs {
// ...
}
public class CusClass2 implements Attribs {
// ...
}
public class MyClass {
// You can now pass anything that implements interface Attribs
public MyClass(Attribs myObject) {
globalVar1 = myObject.getAttrib1();
globalVar2 = myObject.getAttrib2();
}
}
Если вы можете изменить CusClass1
а также CusClass2
Вы могли бы создать интерфейс
public interface AttributeProvider {
Object getAttrib1(); // or whatever type getAttrib1 should return
Object getAttrib2();
}
а затем убедитесь, что CusClass1
а также CusClass2
реализовать этот интерфейс:
public class CusClass1 implements AttributeProvider {
...
}
тогда вы можете иметь конструктор только с этим интерфейсом:
public MyClass(AttributeProvider myObject) {
globalVar1 = myObject.getAttrib1();
globaVar2 = myObject.getAttrib2();
}
Таким образом, вам не придется изменять MyClass
если вы создаете новый CusClass3
который также должен быть использован в MyClass
Не повторяйте код и не разыгрывайте. Создайте 2 конструктора: один принимает CusClass1, второй CusClass2. Реализуйте их отдельно.
Если у вас есть много таких пользовательских классов, может быть лучше использовать отражения и / или аннотации (и особенно, если не все они известны во время компиляции, это может быть единственным решением).
Если все пользовательские классы имеют необходимые атрибуты / методы с одинаковыми именами (например, attrib1
а также attrib2
в вашем примере), отражение тем легче. Все, что вам нужно, это набор потенциальных имен классов и имен атрибутов для запроса.
Однако, если имена атрибутов могут различаться, вы можете рассмотреть возможность использования аннотаций для маркировки требуемых исходных атрибутов в каждом классе.
Вместо этого создайте один метод для каждого типа объекта.
public MyClass(CusClass1 obj) {
field1 = obj.getProperty1();
field2 = obj.getProperty2();
}
public MyClass(CusClass2 obj) {
field1 = obj.getOtherProperty1();
field2 = obj.getOtherProperty2();
}
Если ваш конструктор можно изменить так, чтобы он принимал CusClass1 и CusClass2, а не Object, тогда вы можете следовать одному из решений, приведенных в других ответах.
В противном случае, да, вы можете использовать метод init так:
public class MyClass {
public MyClass (Object obj) {
if (obj instance of CusClass1) {
init((CusClass1) obj);
} else if (obj instanceof CucClass2) {
init((CusClass2) obj);
}
// shared initialization code
}
public void init(CusClass1 obj) {
globalVar1 = obj.getAttrib1();
globaVar2 = obj.getAttrib2();
}
public void init(CusClass2 obj) {
globalVar1 = obj.getAttrib1();
globaVar2 = obj.getAttrib2();
}
}