首页 > 解决方案 > 与反射兼容的设计模式

问题描述

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

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

根据文档

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

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

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

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()

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

标签: javareflection

解决方案


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

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

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不返回超类字段的事实并不是拥有类层次结构的障碍,因为您也可以在超类上调用它;看到另一个问题


推荐阅读