Вопрос

Я ненавижу шаблон JavaBeans со страстью, которая горит, как огонь тысячи солнц.Почему?

  • Многословный.Сейчас 2009 год.Мне не нужно было писать 7 LOC для свойства.Если у них есть слушатели событий, то держитесь за свою шляпу.
  • Нет типобезопасных ссылок.Не существует типобезопасного способа ссылаться на свойство.Весь смысл Java в том, что она типобезопасна, а ее самый популярный шаблон вовсе не типобезопасен.

То, что я хотел бы, это что-то вроде:

class Customer {
    public Property<String> name = new Property();
}

В основном я веб-разработчик, поэтому для этого нужна поддержка JPA и Wicket.

Помоги мне сойти с поезда javabean!

Это было полезно?

Решение

Я думаю, вы довольно близки к тому объявлению, которое у вас там есть (см. Эскиз ниже).Однако, используя подход, отличный от beans, вы, вероятно, потеряете поддержку, предоставляемую большинством инструментов, которые предполагают, что действует протокол JavaBeans.Пожалуйста, будь добр.Приведенный ниже код не укладывается у меня в голове...

public class Property<T> {
    public final String name;
    T value;
    private final PropertyChangeSupport support;

    public static <T> Property<T> newInstance(String name, T value, 
                                              PropertyChangeSupport support) {
        return new Property<T>(name, value, support);
    }

    public static <T> Property<T> newInstance(String name, T value) {
        return newInstance(name, value, null);
    }

    public Property(String name, T value, PropertyChangeSupport support) {
        this.name = name;
        this.value = value;
        this.support = support;
    }

    public T getValue() { return value; }

    public void setValue(T value) {
        T old = this.value;
        this.value = value;
        if(support != null)
            support.firePropertyChange(name, old, this.value);
    }

    public String toString() { return value.toString(); }
}

а затем идите вперед и используйте это:

public class Customer {
    private final PropertyChangeSupport support = new PropertyChangeSupport();

    public final Property<String> name = Property.newInstance("name", "", support);
    public final Property<Integer> age = Property.newInstance("age", 0, support);

    ... declare add/remove listenener ...
}


Customer c = new Customer();
c.name.setValue("Hyrum");
c.age.setValue(49);
System.out.println("%s : %s", c.name, c.age);

Итак, теперь объявление свойства - это одна строка кода, и включена поддержка изменения свойства.Я вызвал методы setValue() и GetValue(), так что это все равно будет выглядеть как компонент для кода типа Rhino и прочего, но для краткости вы могли бы добавить просто get() и set().Остальное оставлено в качестве упражнения для читателя:

  • Правильно обрабатывайте сериализацию
  • Обрабатывать проверку нулевого значения
  • Возможно, добавьте специализацию для атомарных типов, если вы заботитесь о накладных расходах на автоматическую упаковку.
  • ??Я уверен, что есть и другие подводные камни

Также обратите внимание, что вы можете создать подкласс (обычно как анонимный класс) и переопределить setValue(), чтобы обеспечить дополнительную проверку параметров.

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

К сожалению, в наши дни это все еще похоже на программирование на ассемблере...Groovy, C # и т.д. И т.п. Все еще могут быть лучшим выбором, если у вас есть выбор.

Другие советы

Ознакомьтесь с моими аннотациями к Bean на

http://code.google.com/p/javadude/wiki/Annotations

В основном вы делаете такие вещи, как:

@Bean(
  properties={
    @Property(name="name"),
    @Property(name="phone", bound=true),
    @Property(name="friend", type=Person.class, kind=PropertyKind.LIST)
  }
)
public class Person extends PersonGen {}

вместо того, чтобы самостоятельно определять все эти дополнительные методы get / set и т.д.

Существуют другие атрибуты для определения equals / hashCode, observers, delegates, mixins и т.д.

Это набор аннотаций и процессор аннотаций, который запускается в eclipse или в сборке из командной строки (например, в ant).Процессор генерирует суперкласс, содержащий весь сгенерированный код (обработчики аннотаций, кстати, не могут изменить класс, содержащий аннотации)

Возможно, вы захотите проверить Заводной - динамически типизированный язык на основе JVM (и полностью совместимый с Java) с "реальными" свойствами.

Используйте Spring Framework.Его цель - упростить разработку Java, абстрагируясь от многих наработок, на которые вы жалуетесь.

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

Полезные сайты:

www.springsource.org/download

www.hibernate.org/

Для Интернета я бы предложил JSON (Объектная нотация JavaScript),

облегченный формат обмена данными

.Вот ссылка на JSON?Компонент переводчик.

Когда я использовал C # в первый раз, мне понравились свойства, но теперь, после некоторого времени использования их с VS 2008, я должен сказать, что предпочитаю set-/ get-методы.

Главное - это мой личный способ работы.Когда у меня есть новый класс, и я хотел бы знать, что я могу с ним сделать, я просто набираю classname.set, и Eclipse показывает мне, какие "Свойства" я могу изменить.То же самое касается get.Может быть, это просто плохой способ VS, но там мне приходится просматривать длинный список этого itelisense (где все смешано, вместо того, чтобы сначала показывать свойства), просто чтобы узнать после компиляции, что свойство, которое я хотел установить, доступно только для чтения ...doh!

Да, в Java вам нужно много строк, но я просто пишу свои атрибуты и говорю IDE "пожалуйста, создайте для меня геттеры и сеттеры".Но эти методы, как правило, занимают много места, вот почему я хотел бы также иметь области в Java, которые я мог бы складывать в IDE.

Вы также могли бы создать генератор кода, который создает ваши классы .java из DSL, который вы пишете.У вас могла бы быть какая-то разметка, которая описывает имя вашего класса, нужные вам свойства и их типы.Затем обработайте этот файл с помощью программы, которая генерирует ваши javabeans.Или вы могли бы использовать аннотации и постобработать файлы классов, используя что-то вроде ASM для внедрения средств доступа и мутаторов.Я также считаю, что Spring предоставляет некоторые из подобных функций, но я ими не пользовался.

Попробуй ШОВ фреймворк от JBoss, он должен вам понравиться.

Однажды я попробовал это:

interface IListenable {
    void addPropertyChangeListener( PropertyChangeListener listener );
    void removePropertyChangeListener( PropertyChangeListener listener );
}

abstract class MyBean extends IListenable {
    public abstract void setName(String name);
    public abstract String getName();

    // more things
}

public class JavaBeanFactory {

   public <T> Class<T> generate(Class<T> clazz) {
      // I used here CGLIB to generate dynamically a class that implements the methods:
      // getters
      // setters
      // addPropertyChangeListener
      // removePropertyChangeListener
   }
}

Я использовал это как это (это просто пример):

public class Foo {
    @Inject
    public Provider<MyBean> myBeanProvider;

    public MyBean createHook(MyBean a) {
        final MyBean b  = myBeanProvider.get();
        a.addPropertyChangeListener(new PropertyChangeListener() {
             public void propertyChange(PropertyChangeEvent evt) {
                 b.setName((String) evt.getNewValue());
             }
        });
        return b;
    }
}

Я часто использую свойства JavaBean для объектов моей модели (с аннотациями JPA), чтобы иметь возможность привязывать их к пользовательскому интерфейсу (с помощью JFace).

К сожалению, у меня нет решения для второй проблемы (возможно, за исключением определения констант, содержащих имена свойств).

Что я делаю для создания шаблона слушателя, так это расширяю объекты моей модели из суперкласса AbstractJavaBean, который обрабатывает его с помощью отражения.Затем я могу использовать способ создания геттеров / сеттеров по умолчанию, за исключением того, что сеттеры должны быть переписаны следующим образом:

public void setRemarks(String remarks) {
    set("remarks", remarks);
}

AbstractJavaBean.set затем использует отражение (через Apache commons beanutils), чтобы прочитать старое значение свойства "примечания" через его средство получения, присваивает новое значение полю с именем "примечания" и запускает событие изменения свойства, используя старое и новое значения.Фактически, эта идея может быть расширена, чтобы позволить зависимым "производным" свойствам автоматически запускать изменения свойств, когда одно из свойств основано на изменениях, таких как "возраст", изменяемый при изменении свойства "Дата рождения".Вся эта логика может быть закодирована в одном месте внутри AbstractJavaBean и использоваться любым объектом модели.

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

Это доступно по адресу:https://github.com/aditosoftware/propertly.Сейчас мы используем его в нашем продукте.

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

Пример использования:

Простой IPropertyPitProvider.Свойства - это имя, фамилия и возраст.

// Generics describe parent, self and children
public class StudentPropertyPitProvider 
    extends AbstractPPP<IPropertyPitProvider, StudentPropertyPitProvider, Object>
{
  // IPropertyDescription gives static access to an IProperty's meta data like name and type.
  public static final IPropertyDescription<StudentPropertyPitProvider, String> FIRST_NAME =
      PD.create(StudentPropertyPitProvider.class);

  public static final IPropertyDescription<StudentPropertyPitProvider, String> LAST_NAME =
      PD.create(StudentPropertyPitProvider.class);

  public static final IPropertyDescription<StudentPropertyPitProvider, Integer> AGE =
      PD.create(StudentPropertyPitProvider.class);


  // Getters and setters can of course still be used for easier access. 
  public String getFirstName()
  {
    // getValue and setValue is available at AbstractPPP. That class is used for easier access. 
    // Propertly can be used without inheriting from that class, too.
    return getValue(FIRST_NAME);
  }

  public void setFirstName(String pFirstName)
  {
    setValue(FIRST_NAME, pFirstName);
  }

  public String getLastName()
  {
    return getValue(LAST_NAME);
  }

  public void setLastName(String pLastName)
  {
    setValue(LAST_NAME, pLastName);
  }

  public Integer getAge()
  {
    return getValue(AGE);
  }

  public void setAge(Integer pAge)
  {
    setValue(AGE, pAge);
  }

}

Использование определенного поставщика:

public class Sample
{

  public static void main(String[] args)
  {
    // Hierarchy is necessary to initialize the IPropertyPitProviders and for advanced features.
    Hierarchy<StudentPropertyPitProvider> hierarchy =
        new Hierarchy<>("student1", new StudentPropertyPitProvider());
    // The created student can be accessed from the hierarchy.
    StudentPropertyPitProvider student = hierarchy.getValue();
    // Listeners can be added.
    student.addPropertyEventListener(new PropertyPitEventAdapter()
    {
      @Override
      public void propertyChanged(IProperty pProperty, Object pOldValue, Object pNewValue)
      {
        System.out.println(pProperty.getName() + "=" + pNewValue);
      }
    });

    // The following calls will cause
    //  FIRST_NAME=Nils
    //  LAST_NAME=Holgersson
    //  AGE=32
    // to be printed on console through the listener.
    student.setFirstName("Nils");
    student.setLastName("Holgersson");
    student.setAge(32);
  }

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top