Java - динамическое приведение классов от интерфейса к реализации - PullRequest
9 голосов
/ 07 октября 2010

Я читал другие связанные посты, но все еще не совсем уверен, как или возможно ли динамическое приведение (интерфейс к реализации) в Java.У меня сложилось впечатление, что я должен использовать отражение, чтобы сделать это.

Конкретный проект, над которым я работаю, требует использования множества instanceof проверок, и он - на мой взгляд - выходит из-под контроля, поэтому буду признателен за любые идеи / решения.

Ниже приведен небольшой пример, который я написал, чтобы уточнить, что именно я хочу сделать.Дайте мне знать, если вам нужна дополнительная информация:

Интерфейс:

public interface IRobot {
    String getName();
}

Реализации:

public class RoboCop implements IRobot {
    String name = this.getClass()+this.getClass().getName();
    public RoboCop() {}
    public String getName() { return name; }
}

public class T1000 implements IRobot {
    String name = this.getClass()+this.getClass().getName();
    public T1000() {}
    public String getName() { return name; }
}

Класс, который обрабатывает реализации:

import java.util.LinkedList;
import java.util.List;
public class RobotFactory {

    public static void main(String[] args) {
        new RobotFactory();
    }

    public RobotFactory() {
        List<IRobot> robots = new LinkedList<IRobot>();
        robots.add( new RoboCop() );
        robots.add( new T1000() );
        System.out.println("Test 1 - Do not cast, and call deploy(robot)");
        for(IRobot robot : robots) {
            deploy(robot);  // deploy(Object robot) will be called for each..
        }
        System.out.println("Test 2 - use instanceof");
        for(IRobot robot : robots) { // use instanceof, works but can get messy
            if(robot instanceof RoboCop) {
                deploy((RoboCop)robot);
            }
            if(robot instanceof T1000) {
                deploy((T1000)robot);
            }
        }
        System.out.println("Test 3 - dynamically cast using reflection?");
        for(IRobot robot : robots) {
            //deploy((<Dynamic cast based on robot's type>)robot);  // <-- How to do this?
        }
    }

    public void deploy(RoboCop robot) {
        System.out.println("A RoboCop has been received... preparing for deployment.");
        // preparing for deployment
    }

    public void deploy(T1000 robot) {
        System.out.println("A T1000 has been received... preparing for deployment.");
        // preparing for deployment
    }

    public void deploy(Object robot) {
        System.out.println("An unknown robot has been received... Deactivating Robot");
        // deactivate
    }
}

Вывод:

[RoboCop@42e816, T1000@9304b1]
Test 1 - Do not cast, and call deploy(robot)
An unknown robot has been received... Deactivating Robot
An unknown robot has been received... Deactivating Robot
Test 2 - use instanceof
A RoboCop has been received... preparing for deployment.
A T1000 has been received... preparing for deployment.
Test 3 - dynamically cast using reflection?

Итак, чтобы подвести итог моего вопроса, как мне полностью избежать использования instanceof в этом случае.Спасибо.

Ответы [ 5 ]

7 голосов
/ 07 октября 2010

Вы можете сделать метод развертывания IRobot или использовать шаблон посетителей .

И нет, размышления здесь не облегчат ситуацию.

3 голосов
/ 07 октября 2010

Отправка перегруженных методов выполняется статически во время компиляции, поэтому ваш подход не может работать.Это также очень плохой дизайн.Разве вас не удивляет, что метод getName(), вещь only , которая отличается между классами роботов, на самом деле никогда не называется ?

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

public void deploy(IRobot robot) {
    System.out.println("A "+robot.getName()+" has been received..."
                        +" preparing for deployment.");
    // preparing for deployment
}
3 голосов
/ 07 октября 2010

Кент Бек говорит в своей книге Разработка через тестирование : Каждый раз, когда вы используете проверку типов во время выполнения, полиморфизм должен помочь.Поместите метод deploy () в ваш интерфейс и вызовите его.Вы сможете прозрачно обращаться со всеми своими роботами.

Забудьте о размышлениях, вы просто слишком обдумали это.Помните свои основные объектно-ориентированные принципы.

2 голосов
/ 07 октября 2010

Вы можете избежать instanceof, переместив метод deploy в свой интерфейс IRobot и реализации.

Объяснение поведения состоит в том, что ваши три метода deploy являются тремя разными методами;перегруженные методы с разными сигнатурами.Во время компиляции определяется, какой из них выбран, а не во время выполнения на основе реального класса ...

0 голосов
/ 07 октября 2010

Вместо использования instanceof вы можете использовать Шаблон фабричного метода

Определение метода Фабрики ...

Как и другие творческие модели, это занимается проблемой создания объекты (продукты) без указания точный класс объекта, который будет создано.

Вам понадобится RobotCreatorFactory, который будет иметь метод с именем IRobot createRobot(String robotName) {...} (поскольку ваш робот возвращает имя. Я предлагаю, чтобы у каждого робота было public static String name NAME = Robocop.class.getName();. Внутри метода у вас будет проверка такие как

if (Robocop.NAME.equals(robotName) { return new RoboCop(); }

Таким образом, вы облегчаете instanceof. А также, вы можете использовать совет @ Meriton для DeploymentVisitor (используя шаблон посетителя) ....

PS Мой пример - грубое объяснение шаблона метода Фабрики. Пример существует в книге GoF и в Википедии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...