【问题标题】:Design pattern compatible with reflection与反射兼容的设计模式
【发布时间】:2019-12-12 03:05:00
【问题描述】:

我有一些代码依赖于反射(使用第三方库)来获取类的字段。其中许多类混合使用相同的字段,有些几乎相同,但有一些不同。

这导致了大量的代码重复,但由于依赖反射,我不确定是否有一个好的模式。

根据documentation

返回一个 Field 对象数组,反映由该 Class 对象表示的类或接口声明的所有字段。这包括公共、受保护、默认(包)访问和私有字段,但不包括继承的字段

这排除了抽象类或任何与继承相关的解决方案。

这是一个代码示例(MyField 代表第三方库对象,myDataMyField 的公共成员):

ClassA.java

public class ClassA {
    private final Field[] myFields;

    private final MyField a = new MyField(1);
    private final MyField b = new MyField(2);
    private final MyField c = new MyField(3);

    public ClassA() {
        myFields = this.getClass().getDeclaredFields();
    }

    public void doStuff(Field[] myFields) {
        // As an example, this clears out the field values.
        // There are several of these methods that use or manipulate the fields
        for (Field f : myFields) {
            if (f.getType() == MyField.class
                || f.getType().getSuperclass() == MyField.class) {
                try {
                    f.setAccessible(true);
                    ((MyField) f.get(this)).myData.reset();
                }
                catch (IllegalArgumentException | IllegalAccessException e) {
                    continue;
                }
            }
        }
    }

    public Field[] getFields() {
        return Arrays.copyOf(myFields, myFields.length);
    {
}

ClassB.java

public class ClassB {
    private final Field[] myFields;

    private final MyField a = new MyField(1);
    private final MyField c = new MyField(3);
    private final MyField d = new MyField(4);

    public ClassB() {
        myFields = this.getClass().getDeclaredFields();
    }

    public void doStuff(Field[] myFields) {
        // Same as above
    }

    public Field[] getFields() {
        return Arrays.copyOf(myFields, myFields.length);
    {
}

请注意,ClassAClassB 共享字段 ac 以及方法 getFields()doStuff()

有什么方法可以在不影响反射的情况下支持这种重复?

【问题讨论】:

  • 那些是你的课?他们为什么首先将这些声明为字段?他们可能应该在Map 中,并为您节省整个反射的事情。您可能应该添加doStuff 对这些字段所做的一些事情以澄清问题。
  • 更新了doStuff()中的示例代码

标签: java reflection


【解决方案1】:

为什么字段需要存储在类中的数组中?似乎obj.getFields() 总是等价于obj.getClass().getDeclaredFields()。请注意,getDeclaredFields 每次都会返回一个新数组,因此调用它一次然后在您自己的 getter 上制作一个防御性副本是多余的。

如果您更喜欢obj.getFields() 的可读性,那么您可以将其设为default interface method,并从接口中的每个类继承它,而无需更改类层次结构:

public interface FieldGetter {
    default Field[] getFields() {
        return this.getClass().getDeclaredFields();
    }
}

例子:

> class A implements FieldGetter { int x; String y; }
> new A().getFields()
Field[2] { int A.x, java.lang.String A.y }

尚不清楚您的doStuff 方法是否对每个类执行相同的操作;如果是这样,您也可以将其设为默认接口方法。

顺便说一句,getDeclaredFields 不返回超类字段这一事实并不是拥有类层次结构的障碍,因为您也可以在超类上调用它;见this other question

【讨论】:

  • 是的,doStuff() 在所有类中都是相同的。我在想我也许可以把它移到一个 Util 类,但接口可能会更好。感谢您的超类提示!我将设置一个测试,看看这是否有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-19
  • 2015-10-20
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多