Альтернативы JavaBeans? - PullRequest
       29

Альтернативы JavaBeans?

10 голосов
/ 14 января 2009

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

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

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

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

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

Помоги мне сойти с поезда Явабей!

Ответы [ 11 ]

10 голосов
/ 14 января 2009

Я думаю, что вы довольно близки к тому, что у вас там есть (см. Рисунок ниже). Однако, используя подход не от bean-компонентов, вы, вероятно, потеряете поддержку, предоставляемую большинством инструментов, которые предполагают, что протокол 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 # и т. Д. И т. Д. Все еще могут быть лучшим выбором, если у вас есть выбор.

4 голосов
/ 15 января 2009

Проверьте мои аннотации Бина на

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, наблюдателей, делегатов, миксинов и т. Д.

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

3 голосов
/ 14 января 2009

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

2 голосов
/ 14 января 2009

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

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

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

www.springsource.org / скачать

www.hibernate.org /

1 голос
/ 27 июля 2009

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

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

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

1 голос
/ 14 января 2009

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

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

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

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

Я искал то же самое и был очень удивлен, что не смог найти подходящую библиотеку. Поскольку я регулярно чувствовал боль, я начал небольшой проект, посвященный этим вопросам 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);
  }

}
0 голосов
/ 02 мая 2013

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

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

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

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

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

0 голосов
/ 14 января 2009

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

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;
    }
}
0 голосов
/ 14 января 2009

Попробуйте SEAM framework от JBoss, вам должно понравиться.

...