Специфичное для подкласса переопределение в Java - PullRequest
2 голосов
/ 31 мая 2011

Моя проблема заключается в следующем:

У нас есть алгоритм, который внутренне работает с

  • Expression-объектами, которые имеют метод "String getContent ()"
  • Объекты-манипуляторы, которые манипулируют над выражениями с использованием метода «Выражение манипулировать (выражение e)»

Это станет основой в Java.Чтобы решить реальную проблему, нужно предоставить конкретную реализацию как Expression, так и Manipulator, а класс Algorithm сделает все остальное.

Допустим, нам нужны ProblemExpression и ProblemManipulator для конкретной задачи.

Выражение ProblemExpression может содержать множество новых полей, которые могут быть использованы IssumManipulator.

Сейчас я могу думать только о двух способах написания чистого кода:

  • Пусть ProblemManipulator.manipulate предполагает, что его аргументы являются выражениями проблем
  • Использование instanceOf

Но у меня такое ощущение, что я должен сделать это не так,Любые другие предложения?

С уважением и заранее спасибо,

Xaero.

Ответы [ 4 ]

5 голосов
/ 31 мая 2011

Звучит так, как будто вы должны использовать Generic. Как

interface Manipulator<E extends Expression> {
    public void manipulate(E expression);
}

class ProblemManipulator implements Manipulator<ProblemExpression> {
    public void manipulate(ProblemExpression expression) {
        // expression is a ProblemExpression
    }
}
1 голос
/ 31 мая 2011

Поскольку «Проблема» - это другая проблема, это может быть интерфейс, который расширяет Expression следующим образом:

interface IProblemExpr extends Expression
{   //additional methods
}

class ProblemExpression implements IProbExpr
{
}

class ProblemManipulator()
{
    ProblemManipulator(IProblemExpr expr)
    {
     ..
    }
}
0 голосов
/ 07 июня 2011

Я изучил, как работают дженерики, и нашел следующее решение:

Сначала я создал два класса, один для выражения и один для манипулятора:

public class ObjectExpression { }

public class ObjectManipulator <E extends ObjectExpression> {

    public void calculate(Set<E> objects) {
        ... // Do something
    }
}

Затем я создал класс Algorithm, который является общим. Требуются два класса:

  1. Некоторое выражение

  2. То, что манипулирует этим типом объекта

Получаем:

public class Algorithm <F extends ObjectExpression, E extends ObjectManipulator<F>> {
    E om;

    public Algorithm( E om ) {
        this.om = om;
    }

    public void run(Set<F> objects) {
        om.calculate(objects);  
    }   
}

Затем я создал реализацию для случая String: нам нужно выражение и манипулятор

public class StringExpression extends ObjectExpression {
}

public class StringManipulator extends ObjectManipulator<StringExpression> {

    @Override
    public void calculate(Set<StringExpression> objects) {
        // Do String stuff
    }
}

Затем мы можем запустить алгоритм для объектов следующим образом:

Algorithm<ObjectExpression, ObjectManipulator<ObjectExpression>> algo1 = new Algorithm<ObjectExpression, ObjectManipulator<ObjectExpression>>(manipo);
Set<ObjectExpression> objects = new HashSet<ObjectExpression>();
... // fill set
algo1.run(objects);

и для строк:

StringManipulator manips = new StringManipulator();
Algorithm<StringExpression, StringManipulator> algo2 = new Algorithm<StringExpression, StringManipulator>(manips);
Set<StringExpression> strings = new HashSet<StringExpression>();
... // fill set
algo2.run(strings);

Мне это кажется элегантным решением. Как вы думаете? Любые альтернативы / улучшения?

0 голосов
/ 31 мая 2011

Недостаточно обобщенных данных, если доступ к ProblemExpresions и ProblemManipulators открыт. Сначала я думал, что какая-то фабричная структура справится с задачей. Т.е. либо выражения должны быть в состоянии создавать манипуляторы, либо наоборот.

например, скажем, ProblemManipulators были частными внутренними классами ProblemExpressions - получены из Expression # createManipulator (...).

Однако, это не совсем подходит ... в конце концов, если Алгоритму разрешено «удерживать ссылки» как на Выражение, так и на Манипулятор, и он может получить разные несвязанные реализации, то реализация Алгоритма всегда может (если неправильно написано) завершить вызов неправильного Манипулятора для данного Выражения - во время компиляции ничего нельзя сделать, чтобы предотвратить эту ошибку времени выполнения, поскольку все Манипуляторы могут быть вызваны с любым Выражением.

Итак, мне кажется, что вызов Манипулятора (или Выражения) должен «проходить через» Выражение (или, наоборот, Манипулятор), таким образом гарантируя, что для данного Выражения вызывается правильный Манипулятор.

Т.е., выражению нужен метод 'манипулировать ()', который делегирует соответствующий манипулятор.

...