具有动态字段的Java类 [英] Java classes with dynamic fields

查看:178
本文介绍了具有动态字段的Java类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找聪明的方式来构建动态Java类,那就是可以在运行时添加/删除字段的类。使用场景:我有一个编辑器,用户应该可以在运行时向模型添加字段,甚至可以在运行时创建整个模型。



一些设计目标: / p>


  • 如果可以使用适用于动态字段的自定义代码,那么输入安全的代码(该代码将来自以不可预见的方式扩展模型的插件)

  • 良好的性能(可以击败 HashMap ?也许使用数组并在设置过程中为这些字段分配索引? li>
  • 字段重用(即如果您在几个地方使用相同类型的字段,应该可以定义一次,然后重新使用)。

  • 计算的字段取决于其他字段的值

  • 当字段更改值(不一定通过Beans API)时,应发送信号

  • 自动的父子关系(当您将一个孩子添加到父母时,然后孩子中的父指针应设置为免费)。

  • nderstand

  • 易于使用



请注意,这是一个思考圈外的问题。我会在下面的例子中给出你的心情: - )

解决方案

明显的答案是使用 HashMap (或 LinkedHashMap 如果您关心字段的顺序)。然后,您可以通过 get(String name) set(String name,Object value)添加动态字段方法。



此代码可以在一个公共基类中实现。由于只有几种方法,如果需要扩展其他方法,使用委托也很简单。



为避免投射问题,您可以使用类型安全对象地图

  TypedMap map = new TypedMap(); 

String expected =Hallo;
map.set(KEY1,expected);
String value = map.get(KEY1); //看马,不投!
assertEquals(expected,value);

列表< String> list = new ArrayList< String> ();
map.set(KEY2,list);
列表< String> valueList = map.get(KEY2); //甚至用泛型
assertEquals(list,valueList);

这里的诀窍是包含类型信息的键:

  TypedMapKey< String> KEY1 = new TypedMapKey< String>(key1); 
TypedMapKey< List< String>> KEY2 = new TypedMapKey< List< String>>(key2);

表现将OK。



现场重用是通过使用相同的值类型或通过扩展具有附加功能的类型安全对象映射的关键类来实现。



计算的字段可以使用第二个映射存储执行计算的未来实例。



由于所有的操作只发生在两个(或至少一个发送信号很简单,可以任何你喜欢的方式进行。



要实现自动父/子处理,请在set parent上安装一个信号侦听器孩子的信号,然后将孩子添加到新的父母(如果需要,将其从旧的父项中删除)。



由于没有框架被使用,也没有必要的技巧,所得到的代码应该很干净,易于理解。不使用String作为键具有额外的好处,人们不会用字符串字面量丢弃代码。


I'm looking for clever ways to build dynamic Java classes, that is classes where you can add/remove fields at runtime. Usage scenario: I have an editor where users should be able to add fields to the model at runtime or maybe even create the whole model at runtime.

Some design goals:

  • Type safe without casts if possible for custom code that works on the dynamic fields (that code would come from plugins which extend the model in unforeseen ways).
  • Good performance (can you beat HashMap? Maybe use an array and assign indexes to the fields during setup?)
  • Field "reuse" (i.e. if you use the same type of field in several places, it should be possible to define it once and then reuse it).
  • Calculated fields which depend on the value of other fields
  • Signals should be sent when fields change value (no necessarily via the Beans API)
  • "Automatic" parent child relations (when you add a child to a parent, then the parent pointer in the child should be set for "free").
  • Easy to understand
  • Easy to use

Note that this is a "think outside the circle" question. I'll post an example below to get you in the mood :-)

解决方案

The obvious answer is to use a HashMap (or a LinkedHashMap if you care for the order of fields). Then, you can add dynamic fields via a get(String name) and a set(String name, Object value) method.

This code can be implemented in a common base class. Since there are only a few methods, it's also simple to use delegation if you need to extend something else.

To avoid the casting issue, you can use a type-safe object map:

    TypedMap map = new TypedMap();

    String expected = "Hallo";
    map.set( KEY1, expected );
    String value = map.get( KEY1 ); // Look Ma, no cast!
    assertEquals( expected, value );

    List<String> list = new ArrayList<String> ();
    map.set( KEY2, list );
    List<String> valueList = map.get( KEY2 ); // Even with generics
    assertEquals( list, valueList );

The trick here is the key which contains the type information:

TypedMapKey<String> KEY1 = new TypedMapKey<String>( "key1" );
TypedMapKey<List<String>> KEY2 = new TypedMapKey<List<String>>( "key2" );

The performance will be OK.

Field reuse is by using the same value type or by extending the key class of the type-safe object map with additional functionality.

Calculated fields could be implemented with a second map that stores Future instances which do the calculation.

Since all the manipulation happens in just two (or at least a few) methods, sending signals is simple and can be done any way you like.

To implement automatic parent/child handling, install a signal listener on the "set parent" signal of the child and then add the child to the new parent (and remove it from the old one if necessary).

Since no framework is used and no tricks are necessary, the resulting code should be pretty clean and easy to understand. Not using String as keys has the additional benefit that people won't litter the code with string literals.

这篇关于具有动态字段的Java类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆