Перегрузка абстрактного метода в Java?

#java #class #interface #overloading #abstract-class

Вопрос:

У меня есть следующий интерфейс и абстрактный класс:

 public interface DataExporter {
    MultipartFile export() throws IOException;
}


public abstract class AbstractExporter<T> implements DataExporter {
    protected abstract Iterable<T> getData();
}
 

Я вызываю getData() метод в своем классе экспортера, как показано ниже:

 public class EmployeeExporter extends AbstractExporter<EmployeeDTO> {
    
    protected Iterable<EmployeeDTO> getData() {
        // code omitted
    }
}
 

Однако в другом классе, например, ManagerExporter, мне нужно передать параметр getData() методу:

 public class ManagerExporter extends AbstractExporter<ManagerDTO> {
    
    protected Iterable<ManagerDTO> getData(UUID uuid) {
        // code omitted
    }
}
 

Я думаю, что перегружать этот метод AbstractExporter не очень хорошая идея,
потому что в этом случае EmployeeExporter его нужно будет реализовать, даже если он его не использует. Итак, каков наиболее правильный подход к использованию getData() метода с параметром amp; без параметра?

Примечание: Мне также могут понадобиться другие реализации, для которых требуется несколько параметров, например protected Iterable<ManagerDTO> getData(UUID uuid, UUID departmentUuid, UUID staffUuid) . В этом случае мне нужно будет использовать массив объектов и т. Д. нравится Object[] ?

Комментарии:

1. У кого-нибудь еще нет опыта работы с интерфейсными / абстрактными классами?

2. @ChrisPratt Любой ответ, пожалуйста?

3. Если вам нужны разные сигнатуры методов, то вы не должны расширять один и тот же абстрактный класс.

4. @LouisWasserman В этом случае, что мне делать? Не могли бы вы, пожалуйста, опубликовать ответ, чтобы объяснить свое предложение?

5. Для чего используется параметр uuid в качестве идентификатора? Определяет ли он, какой менеджер или что-то еще? Возможно ли, что это должно быть передано конструктору ManagerExporter, а не методу getData ()? Или вам нужно иметь возможность экспортировать различные наборы данных из одного экземпляра ManagerExporter?

Ответ №1:

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

Так что…просто не беспокойтесь.

 public interface DataExporter {
    MultipartFile export() throws IOException;
}

public class EmployeeExporter implements DataExporter {
    protected Iterable<EmployeeDTO> getData() {
        // code omitted
    }
}
public class ManagerExporter implements DataExporter {   
    protected Iterable<ManagerDTO> getData(UUID uuid) {
        // code omitted
    }
}
 

Комментарии:

1. Вы имеете в виду, что мне нужны 2 абстрактных метода как protected abstract Iterable<T> getData(); и protected abstract Iterable<T> getData(UUID uuid); в AbstractExporter классе?

2. Нет. Я имею в виду, что вам нужны нулевые абстрактные методы и нулевые абстрактные классы, и что вы должны AbstractExporter полностью удалить класс, основываясь на том, что вы нам сказали.

3. Большое спасибо. Тогда должен ли я использовать 2 метода в интерфейсе? Не могли бы вы, пожалуйста, добавить интерфейс и другие классы, которые я опубликовал? Я в замешательстве.

4. Нет. Интерфейс не следует изменять. Ни один тип не должен иметь оба этих метода.

5. Не могли бы вы, пожалуйста, добавить интерфейс и другие классы, которые я опубликовал?

Ответ №2:

Это зависит от того, как вы собираетесь использовать свой dataExporter. Если вы хотите использовать оба метода этого класса, то вам необходимо добавить метод во все реализации, в противном случае вам просто не нужен один из этих методов в родительском классе.

Комментарии:

1. Как насчет публикации примера кода, охватывающего все классы в моем вопросе?

Ответ №3:

Вам нужно посмотреть код, по которому вы звоните getData() .

В своем первоначальном вопросе вы сказали: «Я вызываю getData() метод в своем классе экспортера, как показано ниже». Но то, что вы показываете ниже, не является вызовом, это конкретная реализация абстрактного метода.

getData() Метод защищен, поэтому он вызывается только AbstractExporter или его подклассами. Есть ли у AbstractExporter хотя бы одна конкретная реализация метода, которая вызывает getData() ?

Если нет, то вы можете просто удалить getData() этот абстрактный класс. Все вызовы getData() находятся в подклассах, и они, по-видимому, знают правильные аргументы для передачи. getData() Метод может быть удален из абстрактного класса и объявлен (возможно, как закрытый) в конкретных классах реализации.

 public interface DataExporter {
    MultipartFile export() throws IOException;
}

public abstract class AbstractExporter<T> implements DataExporter {
    // No call to getData() occurs anywhere in this class
}

public class EmployeeExporter extends AbstractExporter<EmployeeDTO> {

    private Iterable<EmployeeDTO> getData() {
        // code omitted
    }
}

public class ManagerExporter extends AbstractExporter<ManagerDTO> {

    private Iterable<ManagerDTO> getData(UUID uuid) {
        // code omitted
    }
}
 

Если AbstractExporter содержит вызовы getData() , то как он определяет, какие аргументы он должен передать этому методу? Что-то пахнет рыбой. Экземпляры AbstractExporter могут использоваться взаимозаменяемо. Каждый подкласс должен знать, как работать getData() с использованием одного и того же набора параметров. Если ManagerExporter требует UUID для выполнения своего экспорта, то вы можете назначить это значение при создании экземпляра, а не передавать его в качестве аргумента getData() .

 public interface DataExporter {
    MultipartFile export() throws IOException;
}

public abstract class AbstractExporter<T> implements DataExporter {
    protected abstract Iterable<T> getData();

    public MultipartFile export() throws IOException {
        // Call to getData() occurs here or somewhere else in this class
    }
}

public class EmployeeExporter extends AbstractExporter<EmployeeDTO> {

    protected Iterable<EmployeeDTO> getData() {
        // code omitted
    }
}

public class ManagerExporter extends AbstractExporter<ManagerDTO> {
    private uuid;
    public ManagerExporter( UUID uuid ) {
        // The uuid is determined when the object is constructed
        this.uuid = uuid;
    }
    protected Iterable<ManagerDTO> getData() {
        // Use this.uuid in my implementation
    }
}
 

Комментарии:

1. Спасибо за объяснения, но опять же было бы лучше, если бы вы просто сосредоточились на коде. Возможно, я не очень хорошо объясняю, но код показывает все. Я думаю, что проблема ясна из просмотра кода, и я просто хочу перегрузить метод getData() параметром/без параметра. Не имеет значения, почему я использую параметр, ни тип параметра.