简体   繁体   中英

null checking refactoring in java

We have two classes:

class Foo {
    private String a;
    private String b;
    private String c;
    ...
    getter...setter...
}

class Boo {
    private String a;
    private String b;
    private String c;
    ...
    getter...setter...
}

Assume that Foo and Bar are different but some fields are the same.

here is code I want to do:

  private void map(foo f) {
    Boo b = new Boo();
    if (f.getA() != null)  b.setA(f.getA());
    if (f.getB() != null)  b.setB(f.getB());
    if (f.getC() != null)  b.setC(f.getC());
    ....
  }

3 fields are not a big deal.

But if there are a lot of fields, there would be a lot of if() too.

I'm wondering there is a nice automatic and program nice ways for it in java or C++.

Or you may use a mapping framework like eg. Dozer: http://dozer.sourceforge.net/

You would be able to write code like this:

Mapper mapper = new DozerBeanMapper();
Boo destObject = new Boo();
mapper.map(foo, destObject);

... and it will copy your properties from one object to the other (using reflection).

With additional configuration you would be able to add conversion logic or non-trivial mapping rules (take value of Foo#prop1 and put it to Boo#prop2) or deep copy of an object graph. And many more.

You can remove if statements using functional interfaces and method references like this.

static <X> void setIfNotNull(Consumer<X> setter, Supplier<X> getter) {
    X value = getter.get();
    if (value != null)
        setter.accept(value);
}

private void map(Foo f) {
    Boo b = new Boo();
    setIfNotNull(b::setA, f::getA);
    setIfNotNull(b::setB, f::getB);
    setIfNotNull(b::setC, f::getC);
}

std::optional !

In C++17 this is super automatable, (before C++17, you can just fetch any implementation of an optional class and have the code work the same way)

class Container {
public:
    std::array<std::optional<std::string>, 3> three_string_nullables;
};

int main() {
    auto strings = std::array<std::optional<std::string>, 3>{};
    // fill the strings or don't
    auto container = Container{};
    container.three_string_nullables = strings;
}

To generalize this, you can consider putting the optionals in a dynamically sized container like a std::vector

You can use java reflection API for this task. Reflection allows you to get metadata about classes (like: fields in class, methods and other). Among other things you can invoke class methods. You can take all setters and getters from class, and based on this information can make the necessary calls.

The real answer is to step back and look at the requirements that are driving your question.

You see, good OO is about creating models aka abstractions that represent the "real world elements" your code is dealing with. In a helpful way. In that sense, good OO is much more about behavior (aka methods) than about state (aka fields).

From there: having classes that have a lot of fields is a first design smell already. And then having getters/setters on most/all of those fields is making things rather worse .

Beyond that: when you have two classes A and B. A has 5 fields, B has 7, ... and you find that 3 of those fields are "common" ... the real real answer is: create a class C that contains those 3 fields; and put a field of type C into A and B. And yes, the default would be to have a C field within A and B - because you favor composition over inheritance .

So, yes; there are frameworks that help with this. Or you could re-organize your fields into a single Map instance.

But (probably opinionated): I think you should first talk to some real people, review the current solution and ask yourself: "are we doing real OO here; or are our objects nothing but records that we move around and that procedural code is then working on". In other words - ask yourself if you are really doing OOP here.

Maybe you should store your String in a map.

When you fill your foo class you do it using insert.

Then when you want to copy from each other you iterate on the values.

If you have a lot of members in the class(es), you can use reflection to copy fields. That will allow you to also copy a null value across correctly. It's a lot of more fragile code, so it's only going to be useful if you have a lot of members.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM