设计 - 在执行每个方法之前检查条件

时间:2015-08-10 22:38:11

标签: java oop design-patterns

我有一个名为Document.java的POJO,包含100多个成员变量。有一个转换层,我获取所需的数据,转换它并将其存储在Document类中。

在转换层中,我想仅在满足某个条件(基于可用上下文)时才设置成员变量。

所以它看起来像这样:

if(shouldGetExecuted1(context.getXXX())){
  document.setField1(tranformDataForField1(availableData1));
}

if(shouldGetExecuted2(context.getXXX())){
  document.setField2(tranformDataForField2(availableData2));
}

我想为所有100多个领域做这件事。有干净的方法吗?

其他信息

我不想在这里使用策略,因为它会创建太多的课程,因为策略的增长不会。

3 个答案:

答案 0 :(得分:1)

尝试使用AOP。 AspectJ允许您定义切入点(例如,一些过滤的方法集)并通过 advices 控制它们的执行(方法之前电话,之后,周围):

@Aspect
class ClassName {
...

@PointCut("call(public void ClassName.*(..))") //includes all void methods of ClassName object 
public void myPointCut(){}

@Around("myPointCut()")
public void myLogicMethod(ProceedingJoinPoint thisJoinPoint) {

    if(shouldGetExecuted1(context.getXXX())){
        thisJoinPoint.proceed()
    }
}
}

此处thisJoinPoint.proceed()将执行截获方法的主体。

阅读有关如何定义切入点的文档。在此示例中,相同的逻辑将应用于此类的所有void方法。您可以通过特殊表达式定义更准确的切入点,为每个切入点提供不同的逻辑。

答案 1 :(得分:0)

不,在Java中没有干净的方法。您可以使用反射找到方法,但无法找到诸如“availableDataN”之类的变量。因此,您必须将“availableDataN”设为字段才能使用反射来查找它。

最终的代码会像以下一样丑陋:

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class X {

    public static void main(String[] args) {

        for (int i = 0; i < 100; i++) {

            Method shouldGetExecuted = X.class.getMethod("shouldGetExecuted" + i, String.class);
            boolean b = (boolean) shouldGetExecuted.invoke(null, context.getXXX());
            if (b) {
                Method tranformDataForField = X.class.getMethod("tranformDataForField");
                Field data = X.class.getField("availableData" + i); 
                Object result = tranformDataForField.invoke(null, data.get(null));
                Method set = X.class.getMethod("setField" + i, TransformDataType.class);
                set.invoke(null, result);
            }
        }
    }

}

您需要适应您的具体情况。例如,在这里我假设所有字段和方法都是静态的。如果不是,则需要将null替换为实例引用。

答案 2 :(得分:0)

如果您对方法的命名保持一致,那么反思可能会有很大帮助。

以下代码假定以下内容:

  • 包含Documentxxx等字段的xxYy类(通常会出现getter / setter,但代码无法运行)
  • Transformer的班级
    • 基于上下文信息确定是否应处理字段的能力。这些方法名为shouldTransformXxx(context)
    • 转换字段内容的功能(输入和输出的类型与Document中的相应字段相同)。这些方法名为T transformXxx(T)
  • 具有提供未转换数据的方法的DataProvider类。这些方法名为findXxx()

下面的代码非常乐观 - 如果任何字段的shouldTransformXxx未命中,或者如果它返回true,则会失败,同样适用于findXxxtransformXxx方法。所以你必须创建每个包含100个方法的类,这对我来说似乎不太理想。但另一方面,拥有100名成员的班级无论如何似乎都会导致尴尬的局面......

所以这是代码:

public class Document {
    private String name;
    private int size;

    @Override
    public String toString() {
        return "Document [name=" + name + ", size=" + size + "]";
    }
}

public class Transformer {
    public enum ContextType {
        NAME, SIZE
    }

    public boolean shouldTransformName(Set<ContextType> context) {
        return context.contains(ContextType.NAME);
    }

    public boolean shouldTransformSize(Set<ContextType> context) {
        return context.contains(ContextType.SIZE);
    }

    public String transformName(String name) {
        return "::" + name;
    }

    public int transformSize(int size) {
        return size + 1;
    }
}

public class DataProvider {
    private final String name;
    private final int size;

    public DataProvider(String name, int size) {
        this.name = name;
        this.size = size;
    }

    public String findName() {
        return name;
    }

    public int findSize() {
        return size;
    }
}

public class Main {

    private static final String TRANSFORM_METHOD_PREFIX = "transform";
    private static final String CHECK_METHOD_PREFIX = "shouldTransform";
    private static final String DATAPROVIDER_METHOD_PREFIX = "find";

    private final DataProvider dataProvider;
    private final Transformer transformer;

    public Main(DataProvider dataProvider, Transformer transformer) {
        this.dataProvider = dataProvider;
        this.transformer = transformer;
    }

    public Document transformFields(Set<ContextType> context)
            throws ReflectiveOperationException {
        Document document = new Document();

        for (Field field : Document.class.getDeclaredFields()) {

            String capitalizedfieldName = capitalize(field.getName());
            Class<?> fieldType = field.getType();

            if (shouldTransform(context, capitalizedfieldName)) {

                Object data = findData(capitalizedfieldName);
                Object transformed = transformData(capitalizedfieldName,
                        fieldType, data);

                // in presence of a security manager, a reflective call of the
                // setter could be performed
                field.setAccessible(true);
                field.set(document, transformed);
            }
        }

        return document;
    }

    private Object transformData(String capitalizedfieldName,
            Class<?> fieldType, Object data)
            throws ReflectiveOperationException {

        String methodName = TRANSFORM_METHOD_PREFIX + capitalizedfieldName;
        Method method = Transformer.class.getMethod(methodName, fieldType);
        return method.invoke(transformer, data);
    }

    private Object findData(String capitalizedfieldName)
            throws ReflectiveOperationException {

        String methodName = DATAPROVIDER_METHOD_PREFIX + capitalizedfieldName;
        Method method = DataProvider.class.getMethod(methodName);
        return method.invoke(dataProvider);
    }

    private boolean shouldTransform(Set<ContextType> context,
            String capitalizedfieldName) throws ReflectiveOperationException {

        String methodName = CHECK_METHOD_PREFIX + capitalizedfieldName;
        Method method = Transformer.class.getMethod(methodName, Set.class);
        return (Boolean) method.invoke(transformer, context);
    }

    private String capitalize(String fieldName) {
        char upperCaseFirstChar = Character.toUpperCase(fieldName.charAt(0));

        if (fieldName.length() > 1) {
            return upperCaseFirstChar + fieldName.substring(1);
        } else {
            return Character.toString(upperCaseFirstChar);
        }
    }

    public static void main(String[] args) throws ReflectiveOperationException {
        DataProvider dataProvider = new DataProvider("sample", 1);
        Set<ContextType> context = EnumSet.of(ContextType.NAME,
                ContextType.SIZE);

        Main main = new Main(dataProvider, new Transformer());
        Document document = main.transformFields(context);

        System.out.println(document);
    }
}