简体   繁体   English

Java中的null检查重构

[英]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. 假设Foo和Bar不同,但是某些字段相同。

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. 3个字段没什么大不了的。

But if there are a lot of fields, there would be a lot of if() too. 但是,如果有很多字段,那么也会有很多if()。

I'm wondering there is a nice automatic and program nice ways for it in java or C++. 我想知道在Java或C ++中有一种不错的自动方式和编程方式。

Or you may use a mapping framework like eg. 或者您可以使用类似的映射框架。 Dozer: http://dozer.sourceforge.net/ 推土机: 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. 使用其他配置,您将能够添加转换逻辑或非平凡的映射规则(将Foo#prop1的值并将其放入Boo#prop2)或对象图的深层副本。 And many more. 还有很多。

You can remove if statements using functional interfaces and method references like this. 您可以使用类似的功能接口和方法引用来删除if语句。

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 ! 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) 在C ++ 17中,这是超级可自动化的(在C ++ 17之前,您可以获取optional类的任何实现,并使代码以相同的方式工作)

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 为了概括这一点,您可以考虑将可选对象放入动态调整大小的容器中,例如std::vector

You can use java reflection API for this task. 您可以将Java Reflection API用于此任务。 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. 您可以从类中获取所有的setter和getter,并且基于此信息可以进行必要的调用。

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. 您会发现,好的OO是关于创建模型或 抽象的 模型 ,它们代表您的代码正在处理的“现实世界元素”。 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; 除此之外:当您有两个班级A和B。A有5个字段,B有7个字段,...,您发现其中3个字段是“公共的” ... 真正的真实答案是:创建一个C类,包含这三个字段; 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 . ,然后将类型C的字段放入A和B。是的, 默认设置是在A和B中包含一个C字段-因为您更喜欢组合而不是继承

So, yes; 所以,是的; there are frameworks that help with this. 有一些框架对此有所帮助。 Or you could re-organize your fields into a single Map instance. 或者,您可以将字段重新组织到一个Map实例中。

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". 但是(可能是自以为是):我认为您应该首先与一些真实的人交谈,查看当前的解决方案并问自己:“我们是在这里进行真正的OO;还是我们的对象不过是记录我们四处移动而后的过程代码正在努力”。 In other words - ask yourself if you are really doing OOP here. 换句话说-在这里问自己是否真的在做OOP。

Maybe you should store your String in a map. 也许您应该将String存储在地图中。

When you fill your foo class you do it using insert. 当您填充foo类时,可以使用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. 这样一来,您还可以正确地复制一个null值。 It's a lot of more fragile code, so it's only going to be useful if you have a lot of members. 它包含很多易碎的代码,因此只有在拥有许多成员的情况下它才有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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