Как вызвать перегруженный метод, когда параметр является подклассом данного типа? - PullRequest
0 голосов
/ 11 марта 2020

У меня есть абстрактный класс A, два подкласса с именем B, C и два перегруженных метода, которые находятся в отдельном классе:

public void process(B objB) {...}
public void process(C objC) {...}

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

A objA = repo.findById(id);
process(objA);

Я знаю, что приведение требуется, но я не хочу делать много проверок, используя instanceof или множество if операторов.

Каковы наилучшие варианты реализации такого вызова метода? И это хороший дизайн кода?

Ответы [ 2 ]

0 голосов
/ 11 марта 2020

Использование instanceof не является хорошим вариантом, особенно если у вас есть много мест, где вам нужен доступ к определенному подклассу.

  1. Очевидным подходом является добавление абстрактного process() метода без параметров в базовый класс и реализовать его в подклассах, вызывая соответствующий метод process(this) из другого класса и передавая ссылку this в него.

  2. Когда предпочтительнее разделить логи обработки c из иерархии классов (предположительно это ваш случай) есть пара шаблонов: Стратегия или более общая Посетитель . Вот пример использования шаблона Visitor :

    abstract class A {
        <T> T accept(Visitor<T> visitor);
    }
    
    class B extends A {
        @Override
        public <T> T accept(Visitor<T> visitor) {
            return visitor.visit(this);
        }
    }
    
    class C extends A {
        @Override
        public <T> T accept(Visitor<T> visitor) {
            return visitor.visit(this);
        }
    }
    
    interface Visitor<T> {
        T visit(B bObject);
        T visit(C cObject);
    }
    

    Затем определите конкретную операцию путем реализации соответствующего посетителя:

    Visitor<Integer> visitor = new Visitor<Integer>() {
        @Override
        public Integer visit(B bObject) {
            // TODO do something with bObject
            return null;
        }
    
        @Override
        public Integer visit(C cObject) {
            // TODO do something with cObject
            return null;
        }
    };
    

    и просто вызовите accept:

    A objA = repo.findById(id);
    Integer result = objA.accept(visitor);
    
0 голосов
/ 11 марта 2020

Использование перегруженных методов в этом случае невозможно без предварительного приведения объекта, так как программа не будет вызывать перегруженный метод, если явный тип объекта не совпадает. Поэтому он не будет вызывать процесс (B objB), если только передаваемый вами объект явно не относится к классу B.

Чтобы избежать слишком больших хлопот, есть несколько способов сделать это. В зависимости от того, что различает B и C, вы можете создать экземпляр A как этот тип при извлечении объекта из базы данных (это можно сделать в RowMapper) и написать оператор if else, чтобы определить, какой процесс вызывать:

        if(a.getClass() == B.class)
        {
            return process((B) a);
        }
        else
        {
            return process((C) a);
        }

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

...