Как сделать эту часть кода масштабируемой, - PullRequest
2 голосов
/ 27 апреля 2011

В моем java-коде есть часть, где я расширяю класс из библиотеки, которую я не написал.

@override
public Object getPropertyValue(Object id) {
    if(id.equals(model.PROPERTY_RENAME))
        model.setName((String)value);
    else if(id.equals(model.PROPERTY_COLOUR))
        model.setColor((Color)value);
}

Теперь в этом случае, как мне изменить этот код, чтобы сделать его масштабируемым.Было бы намного больше свойств, таких как местоположение, измерение и т. Д. Теперь эта модель является экземпляром абстрактного класса AbsModel.

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

Ответы [ 7 ]

1 голос
/ 27 апреля 2011

Похоже, что вы хотите выполнить некоторую операцию с моделью при вызове этого метода (getPropertyValue).Я бы создал карту идентификатора на интерфейсе ModelOperation, определенном следующим образом:

public interface ModelOperation {
    void operate(Object value);
}

Тогда карта будет определена следующим образом:

map.put(model.PROPERTY_RENAME, new RenameOperation(model));

Ваш класс расширения будет выглядеть так:

@Override
public Object getPropertyValue(Object id) {
    map.get(id).operate(model);
    // etc...
}

Например, RenameOperation будет определен следующим образом:

public class RenameOperation implements ModelOperation {
    public RenameOperation(Model model) {
        // etc...
    }

    public void operate(Object value) {
        model.setName((String)value);
    }
}

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

0 голосов
/ 30 апреля 2011

Я решил эту проблему, создав интерфейс.Итак, код:

public interface IModel
{
  public void setProperty(String propertyName); 
}

Остальные классы были

public class HelloModel implements IModel
{
       public void setProperty(String propertyName)
       { code for handling the properties goes here ... }
}

Так что в этом случае каждый класс должен обрабатывать свои собственные установщики свойств.Это лучший способ справиться с абстракцией?Я думаю, что эта модель очень масштабируема ...

0 голосов
/ 27 апреля 2011

Версия, не использующая отражение, вызывает реализацию базового класса:

public Object getValue(Object id) {
  Object ret = super.getValue(id);
  if (ret == null) {
     // Subclass specific properties
  }
  return ret;
}
0 голосов
/ 27 апреля 2011

Поскольку в Java функции не являются гражданами первого класса, «хороший» маршрут будет очень неудобным: определите перечисление с одним значением для каждой константы выше (т.е. для каждого свойства) и виртуальный метод, например update(Object value,переопределите метод в каждом перечислении, чтобы обновить соответствующее свойство.Если вы можете, переопределите сами константы PROPERTY_RENAME и т. Д. Как перечисления.Это по-прежнему приводит к раздутию кода.

Другой способ - использовать отражение.Если вы можете использовать те же идентификаторы, что и имена свойств, которые хотите обновить, вам нужно только вызвать установщик для свойства (как показано в других ответах).В противном случае вам может потребоваться ввести сопоставление идентификаторов с именами свойств.

0 голосов
/ 27 апреля 2011

Есть несколько способов сделать это - хотя это зависит от того, что вы подразумеваете под "масштабируемым" (способность справляться с большим количеством запросов в секунду или способность справляться с большим количеством свойств?):

  • Одним из способов - если вы собираетесь пойти по пути, который вы наметили в своем коде, это иметь те свойства, которые очень часто используются в верхней части блока if / then / else, - то есть путь их выполнения очень короткий это хорошо «масштабировалось бы» для большого количества запросов, так как на выполнение метода не тратится слишком много времени (по крайней мере, в большинстве случаев!)
  • другой способ - и он хорошо масштабируется для большого количества свойств и простоты обслуживания кода, но вы потратите время на выполнение: получите карту, которая отображает имена свойств на имена методов setxxx (), затем вы можете использовать отражение для вызова этих методов на целевой объект (идентификатор в вашем случае) при каждом вызове. Классы, расширенные для вашего класса, должны будут предоставить только метод getMap (), который будет возвращать метод сопоставления имени и сеттера, который может быть статическим членом и инициализироваться при загрузке класса.
  • Сохраните ваши свойства на карте - в этом случае setName () совпадает с map.put (PROPERTY_RENAME, значение)
0 голосов
/ 27 апреля 2011

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

Это не будет хорошо, но идея в том, что у вас будет метод, который будет отражать тип и искать соответствующий метод. Код Belwo

public Object setPropertyValue(Object id) {
    String className = id.getClass().getSimpleName();

    // Hope that the method is called set<CLASS> and takes a single parameter that is the class
    Method method = model.class.getMethod("set" + className, id.getClass());

    // Invoke the method (TODO deal with all of the exceptions)
    method.invoke(model, id);
}
0 голосов
/ 27 апреля 2011

Обычный способ обойти это - использовать отражение как

public Object getValue(IdType id) {
    Method getter = model.getClass().getMethod("get" + id);
    return getter.invoke(model); // throws Exceptions.
}

ИЛИ

public void setValue(IdType id, Object value) {
    Method setter = model.getClass().getMethod("set" + id, value.getClass());
    setter.invoke(model, value); // throws Exceptions.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...