Как определить общие операции между различными объектами в Java? - PullRequest
0 голосов
/ 22 декабря 2010

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

Скажем для начала, что у меня есть скаляры (то есть числа), матрица и множества матрицы или скаляров, и что я хочу определить операцию плюс на них:

  • scalar1.plus (scalar2) возвращает скаляр, равный scalar1 + scalar2,

  • matrix.plus (scalar1) или scalar.plus (matrix) оба возвращают матрицу где 'scalar1' каждый элемент был добавлен к каждому элементу матрица,

  • matrixSet.plus (matrix1) возвращает набор, в котором каждая матрица была добавлено в матрицу1

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

Мои цели следующие:

1 - повторно использовать как можно больше кода (важно, потому что у меня будет много больше операций и типов данных),

2 - делать как можно больше проверок во время компиляции

3 - упростить добавление новых типов данных или операций в будущем (для Например, я могу захотеть добавить векторный тип данных позже)

Сначала я думал, что определю интерфейс операнда, который мой скаляр, матрица и набор этих элементов будут реализованы, и которые будет включать такие методы, как:

public Operand plus(Operand op);

Это позволило бы определить операцию плюс снизу вверх, начиная с самого простого элемента (скаляра):

public Operand plus(Operand operand) {
  if (Scalar.class.equals(operand.getClass())) {
    return new Scalar(this.value + ((Scalar) operand).getValue());
  } else {
   // assume the other operand will define the addition for me
   // since add is commutative
    return operand.plus(this);
  }
}

А потом для матрицы:

public Operand plus(Operand operand) {
  if (Scalar.class.equals(operand.getClass())) {
    // return a matrix where we add scalar value to all matrix elements
  } else if (Matrix.class.equals(operand.getClass())) {
    // return a matrix where we perform a scalar addition between each element
  } else {
    // assume the other operand will define the addition for me
    // since add is commutative
    return operand.plus(this);
  }
}

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

Этот подход соответствует целям 1 и 3, но не 2: все операции возвращаются Операнды объектов, и заставляет меня делать много кастинга и классов проверка во время выполнения, что не кажется хорошей практикой.

Есть ли лучший способ решить мою проблему?

Ответы [ 4 ]

1 голос
/ 22 декабря 2010

Похоже, вам нужно использовать шаблон адаптера .В основном вы определите общий интерфейс, а затем адаптируете его так, как вам нужно, в соответствии с вашими потребностями.

0 голосов
/ 10 декабря 2013

Правильный способ сделать это с помощью Java - определить методы работы в ваших классах данных и перегрузить при необходимости.Если у вас есть класс матрицы, этот класс должен знать, как добавить другую матрицу к себе и скаляр к себе.Я не знаю, есть ли у вас особая причина для разделения операндов и операторов, но в остальном это правильный путь.Вот некоторый код для пояснения концепции:

class Matrix{
  Matrix add(Matrix m){
    //add matrix to self
    return this;
  }
  Matrix add(Scalar s){
    //add scalar to self
    return this;
  }
}
0 голосов
/ 07 января 2011

Через некоторое время я решил, что неправильно подхожу к проблеме, определяя операции для каждого типа данных, которые я создал.Это просто не работало, независимо от того, что я пытался.

Я закончил тем, что имел один класс на операцию, определенный для целых чисел.Например, Addition, Multiply, Addition8BitSat и т. Д. Кроме того, у меня есть один класс Evaluator, в котором я определяю, как получить операцию между двумя блоками, между блоком и целым числом, между наборами блоков и целым числом и т. Д. На основе результатаоперации между только целыми числами.

Этот подход решает три проблемы, которые я перечислил выше: нулевая избыточность в моем коде, методы, которые возвращают результаты правильного типа, и легко расширяемые до других типов.

0 голосов
/ 23 декабря 2010

Я не уверен, что понимаю, почему вы вообще используете интерфейс Operand.Кажется, что ваш основной метод повторного использования кода - это вызов операции над операндом, когда этот операнд уже определил операцию.Но использование интерфейса не поможет вам в этом.Что мне не хватает?Разве для этого не используется такой же объем кода, но допускаются такие приятные вещи, как определенные типы возвращаемых данных и исключения?

Скаляр:

public Scalar plus(Scalar operand) {
    return new Scalar(this.value + operand.getValue());
}

public Matrix plus(Matrix operand) {
    return operand.plus(this);
}

Матрица:

public Operand plus(Scaler operand) {
    return new Scalar(this.value + operand.getValue());
}

public Operand plus(Matrix operand){
  // return matrix plus matrix
}
...