如何将班级字段映射到另一个班级?

时间:2019-02-04 21:01:08

标签: java

我不是在寻找实现此目的的最佳方法,而是在遵循DRY原理的情况下寻求任何方法来完成我需要的工作。

让我们说我有一个Source课,如下所示。 Source包含三十个字符串。

class Source {
    private String sourceAttrOne = "sourceValueOne";
    private String sourceAttrTwo = "sourceValueTwo";
    ...
    private String sourceAttrThirty = "sourceValueThirty";
}

此信息将用于创建类Destination的新对象。 Destination的25个属性中的名称具有相似的格式(但相同名称则没有)。其中10个是字符串,而5个是日期,而5个是整数。但是,最后5个字段完全不同。

class Destination {
    private String AttrOne;
    ...
    private Date AttrSixteen;
    ...
    private Integer AttrTwentyOne;
    ...
    // Last 5 fields are different
    private SomeOtherClass someOtherName;
    private TheBestClass imAlsoSpecial;

    // Standard getters and setters
}

对于25个“普通”属性,我需要使用一个辅助方法来从源值获取结果。使用的帮助程序方法取决于目标类型:

destination.setAttrOne(getResultingString(source.getSourceAttrOne()));
destination.setAttrSixteen(getResultingDate(source.getSourceAttrSixteen());
destination.setAttrSeventeen(getResultingDate(source.getSourceAttrSeventeen()/*, custom Date format for AttrSeventeen */));

其余5个属性需要自定义(个体)逻辑。

任何朝着正确方向的指针将不胜感激,我不需要完整的解决方案:)

3 个答案:

答案 0 :(得分:1)

N.B。::我可能完全误解了,如果是这种情况,请不要介意。
我也还没有发表评论,尽管这可能是最好的评论。不便之处,敬请谅解。


如果第1到第15个属性是字符串,那么可以假设您可以将它们简单地影响到相应的属性,或者根据需要先克隆它们。

对于日期的第16到21(?),您可以使用DateFormat's parse(String)方法;不过,我对如何帮助编译器获取使用的格式或它是否可以自行正确使用一无所知。

对于22到27(?)的整数,您应该可以使用Integer's parse(String)方法,或者可以通过 Double的使用,然后再转换回Integer或int。

答案 1 :(得分:1)

您可以尝试对类似目标进行反射。
像这样:

public void fillFieldsHelper(Object source) {

List<Field> sourceFields = source.getClass().getDeclaredFields();

or

Field valueOne = source.getClass().getDeclaredField("sourceAttrOne");

System.out.println(valueOne.getName());
System.out.println(valueOne.getType());

...

Object value = valueOne.get(source);
Field attrOne = this.getClass().getDeclaredField(valueOne.getName().replace("source",""));

switch (attrOne.getType().getName()) {
 case "java.lang.Integer":
  attrOne.set(this, Integer.valueOf(value));
  break;
 default: 
  attrOne.set(this, value);
}
...

etc.

我不能说反射很优雅,但是在很多情况下它很有用。

答案 2 :(得分:1)

因此,在您的情况下,您有几种可能。

  1. 从对象创建对象

最简单但可能不是最好的解决方案(取决于您的进一步处理/需求)是使用需要Object作为参数的构造函数。

public class Source {
    private String sourceAttrOne;
    private String sourceAttrTwo;
    // further class attributes....

    // getters (& setters)
}

public class Destination {
    private String attrOne;
    private String attTwo;

    public Destination(Source source) {
        this.attrOne = source.getSourceAttrOne;
        this.attrTwo = source.getSourceAttrTwo;
        // etc..
    }
}
  1. 用户构建器模式

上述解决方案中的问题是,根据创建Destination.class所需的字段,构造函数将具有很多参数。另外,如果您将来必须更改构造器(例如,其他必填字段),则必须创建一个新的构造器或更改已经存在的构造器(这意味着您必须更改该构造器的所有当前用法)。 因此,要保持DRY,我建议使用Builder Patter。

public class Destination {
    private String attrOne;
    private String attTwo;
    private String attThree; // attribute which comes not from any other source class and is e.g. not a required field

    private Destination() {
        // should not be accessible 
    }

    public static class Builder {
        private String attrOne;
        private String attTwo;
        private String attThree;

        private Builder() {
            // do nothing
        }

        public static Builder create(Source source) {
            Builder builder = new Builder();

            builder.attrOne = source.getSourceAttrOne();
            builder.attrTwo = source.getSourceAttrTwo();

            return builder;
        }

        public Builder attThree(String attThree) {
            this.attThree = attThree;
            return this;
        } 

        public Destination build() {
            Destination destination = new Destination();

            destination.attrOne = builder.attrOne;
            destination.attrTwo = builder.attrTwo;
            destination.attrThree = builder.attrThree;

            //add several validations e.g. assert destination.attrOne != null

            return destination;
        }
    }
}

要使用Destination.class创建Source.class,请执行以下操作:

Destination.Builder.create(source).build();

用于具有不同的类型,例如Source.sourceAttrOne是一个字符串,而Destination.attrOne中的是一个日期,您只需要调整Destination.class

public class Destination {
    private LocalDate attrOne;
    // ...

    private Destination() {}

    public static class Builder {
        private String attrOne;
        // ...

        private Builder() {}

        public static Builder create(Source source) {
            Builder builder = new Builder();

            builder.attrOne = LocalDate.parse(source.getSourceAttrOne());
            // ...

            return builder;
        }

        public Destination build() {
            Destination destination = new Destination();

            destination.attrOne = builder.attrOne;
            // ...

            return destination;
        }
    }
}