2016-07-18 2 views
2

У меня есть описание данных интерфейса:Могу ли я перегрузить метод интерфейса в Java?

public interface DataDescription { 
    int getId(); 
} 

И две реализации:

public class DataWithId1 implements DataDescription { 
    // ... simple getter impl. 
} 

public class OtherDataWithId implements DataDescription { 
    // ... simple getter impl. 
} 

Теперь у меня есть этот интерфейс:

public interface DataProcessor { 
    void process(DataDescription data); 
} 

Я хотел бы реализовать DataProcessor с одним классом , что-то вроде этого:

public class DataProcessorImpl implements DataProcessor { 
    @Override 
    public void process(DataDescription data) { 
     // Do something... 
    } 

    public void process(DataWithId1 data) { 
     // Do something specific with this type (e.g. directly store in table of database) 
    } 

    public void process(OtherDataWithId data) { 
     // Do something specific with this type (convert to format DataWithId1 and then store in DB) 
    } 
} 

И некоторый код, чтобы назвать его:

public Main { 
    private DataProcessor dataProcessor = new DataProcessor(); 

    public static void main(String[] args) { 
     DataDescription data = new DataWithId1(1); 
     dataProcessor.process(data); 
    } 
} 

То, что я хотел бы добиться того, что DataProcessor абонента не придется беспокоиться о преобразовании данных (они имеют DataDescription и не должны знать о двух типах). Кроме того, я хотел бы избежать кода instanceof.

Предположение, которое я сделал, заключается в том, что я могу перегрузить интерфейсный метод, подобный этому. Я не смог найти доказательства для этого, глядя на section 15.12 of the java language specification (что не значит, что его там нет).

Является ли мое предположение о перегрузке правильной? Могу ли я избежать instanceof?

ответ

4

Может быть, вы ищете Visitor Pattern:

public interface DataDescription { 
    int getId(); 
    void accept(DataProcessorImpl p); 
} 

public class DataWithId1 implements DataDescription { 
    private final int id; 

    public DataWithId1(int id) { 
     this.id=id; 
    } 
    @Override 
    public void accept(DataProcessorImpl p) { 
     p.process(this); 
    } 
    @Override 
    public int getId() { 
     return id; 
    } 
    // ... simple getter impl. 
} 

public class OtherDataWithId implements DataDescription { 
    private final int id; 

    public OtherDataWithId(int id) { 
     this.id=id; 
    } 
    @Override 
    public void accept(DataProcessorImpl p) { 
     p.process(this); 
    } 
    @Override 
    public int getId() { 
     return 42; 
    } 
    // ... simple getter impl. 
} 
public interface DataProcessor { 
    void process(DataDescription data); 
} 

public class DataProcessorImpl implements DataProcessor { 
    @Override 
    public void process(DataDescription data) { 
     data.accept(this); 
    } 

    public void process(DataWithId1 data) { 
     System.out.println("process(DataWithId1)"); 
     // Do something specific with this type 
     // (e.g. directly store in table of database) 
    } 

    public void process(OtherDataWithId data) { 
     System.out.println("process(OtherDataWithId)"); 
     // Do something specific with this type 
     // (convert to format DataWithId1 and then store in DB) 
    } 
} 

public class Main { 
    private static DataProcessor dataProcessor=new DataProcessorImpl(); 

    public static void main(String[] args) { 
     DataDescription data = new DataWithId1(1); 
     dataProcessor.process(data); 
     data = new OtherDataWithId(100); 
     dataProcessor.process(data); 
    } 
} 
+0

Я вижу, что метод accept принимает Impl как аргумент. Здесь можно использовать интерфейс 'DataProcessor'? – Timo

+1

Ну, вы можете, если вы объявите все методы 'process' в интерфейсе' DataProcessor'. Но тогда их слишком легко сбить с помощью метода front-end 'process'. Самое чистое решение состояло бы в том, чтобы иметь два интерфейса: интерфейс * Visitor *, используемый методом 'accept', и интерфейс DataProcessor для используемого сайта (здесь, метод' main'). Затем «DataProcessorImpl» может реализовывать оба интерфейса. Таким образом, метод 'main' не должен знать о интерфейсе посетителя, а методы' accept' не должны знать о DataProcessor' (в будущем могут быть и другие посетители). – Holger

+0

Я думаю, что ваше предложение для двух интерфейсов - единственный способ получить это чистое. Если вы не используете два интерфейса, всевозможные детали реализации обойдутся в коде, например, 'DataDescription' должен знать, какие реализации DataProcessor являются релевантными. – Timo

0

Вы можете использовать абстрактный класс для обработки преобразования для вас или, альтернативно, использовать метод по умолчанию в интерфейсах Java8.

Просто добавьте ключевое слово 'default' к методу в вашем интерфейсе и дайте им тело.

5

Нет, это не сработает.

В коде отсутствует никакая перегрузка. Статический тип dataProcessor составляет DataProcessor, а DataProcessor имеет только один метод process.

Если вы измените статический тип dataProcessor на DataProcessorImpl, вы все равно не получите желаемого результата, так как во время компиляции определяется разрешение перегрузки. Поэтому, поскольку тип времени компиляции data равен DataDescription, dataProcessor.process(data) по-прежнему будет ссылаться на public void process(DataDescription data), а не public void process(DataWithId1 data).

+0

Так что я m застрял с 'instanceof'? Это похоже на то, что я получил от своих экспериментов. – Timo

1

Это легко сделать, если вы добавите «что-то конкретное» в метод в интерфейсе DataDescription.

Метод process() относится к каждому подтипу. Вы поместили его в неправильный интерфейс.

Пусть DataProcessor вызвать этот метод на каждом DataProcessor:

public interface DataDescription { 
    void somethingSpecific(); 
} 

полиморфизм делает работу:

public class DataProcessorImpl implements DataProcessor { 
    @Override 
    public void process(DataDescription data) { 
     data.somethingSpecific(); // polymorphism does it for you here 
    } 
} 
Смежные вопросы