Метод, чтобы взять несколько типов

В настоящее время я работаю с конструктором, который принимает объект типа. Затем я проверяю его тип на основе 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();
    }
}
Другие вопросы по тегам