创建一个通用函数来复制不同的对象

时间:2018-08-01 10:09:07

标签: java object java-8 copy

所以我有一个用例,其中我需要复制 4.2object es(类可能因工厂中的输入类型而异。

这是我要做的事的一个示例

class

如果您查看public interface DataUtil { // the main wrapper static Object copyObject(Object payload){ if(payload instanceof Human)) return copyEntry((Human) payload); if(payload instanceof Car)) return copyEntry((Car) payload); if(payload instanceof Planet)) return copyEntry((Planet) payload); return payload; } static Human copyEntry(Human human) { return Human.builder() .name(human.getName()) .age(human.getAge()) .build(); } static Car copyEntry(Car car) { return Car.builder() .model(car.getModel()) .brand(car.getBrand()) .build(); } static Planet copyEntry(Planet planet) { // return builder like previous } } 函数,它会按预期完成工作,但是他发出的是返回类型。目前,要使其自身 compatible ,它返回一个copyObject,但我宁愿返回它的特定类Object(例如ObjectHuman

有没有一种方法可以通过泛型(使用Car)来完成?还是这首先是一个不好的方法?

3 个答案:

答案 0 :(得分:6)

  

有没有一种方法可以使用泛型完成此操作(使用)?还是这个   首先要采取不好的做法吗?

这是一种不好的方法,因为您会收到Object作为参数。
您无法从该类型推断出具体的类型:而您使用的instanceof。这不是一个好方法。
这里有两个想法(足够相关)

1)引入可复制界面

您可以引入一个接口,您要复制的对象的类可以实现该接口:

public interface Copyable<T> {
    T copy(T t);
}
可以实现的

public class Human implements Copyable<Human> {

   @Override
   public Human copy(Human t) {
       return    Human.builder()
                     .name(human.getName())
                     .age(human.getAge())
                     .build();
   }

}

所以一般的copy()方法看起来像:

// the main wrapper
static <T extends Copyable<T>> T copyObject(T payload) {
    return payload.copy(payload);
}

您可以通过这种方式使用它:

Human human = new Human();
// set some fields  ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile

2)使用访问者模式

作为替代方案,这也是访问者模式的一个很好的例子:您要根据参数的具体类型进行处理。
它允许将复制操作分组到您的实际代码中。

一般的copyObject()方法可以依靠CopyVisitor来根据参数的具体类型进行复制:

@SuppressWarnings("unchecked")
static <T extends Visited> T copyObject(T payload) {
    CopyVisitor visitor = new CopyVisitor();
    payload.accept(visitor);
    return (T) visitor.getCopy();
}

CopyVisitor实现经典的Visitor接口的地方:

public interface Visitor {  
    void visitHuman(Human human);
    void visitCar(Car car);
    void visitPlanet(Planet planet);
}

以这种方式:

public class CopyVisitor implements Visitor {

    private Visited copy;

    @Override
    public void visitHuman(Human human) {
        copy = Human.builder()
                    .name(human.getName())
                    .age(human.getAge())
                    .build();

    }

    @Override
    public void visitCar(Car car) {
        copy = Car.builder()
                  .model(car.getModel())
                  .brand(car.getBrand())
                  .build();
    }

    @Override
    public void visitPlanet(Planet planet) {
        //...
    }

    public Visited getCopy() {
        return copy;
    }

}

被访问的类(汽车,人,计划)将实现一个特定的接口来“接受”访问者:

public interface Visited {
    void accept(Visitor visitor);
}

例如:

public class Human implements Visited {

    @Override
    public void accept(Visitor visitor) {
        visitor.visitHuman(this);
    }

}

因此,您可以通过以下方式使用copy()方法:

Human human = new Human();
// set some fields  ...
Human copiedHuman = copyObject(human); // compile
Car copiedCar = copyObject(human); // doesn't compile

答案 1 :(得分:1)

不幸的是,您必须执行一些未经检查的强制转换,例如:

static <TPayload> TPayload copyObject(Object payload) {
    if (payload instanceof Human)
        return (TPayload) copyEntry((Human) payload);
    if (payload instanceof Car)
        return (TPayload) copyEntry((Car) payload);
    if (payload instanceof Planet)
        return (TPayload) copyEntry((Planet) payload);
    return (TPayload) payload;
}

但是正如评论中所提到的,这并不妨碍您写作:

Number n = DataUtil.copyObject("someString");

答案 2 :(得分:0)

如果您了解Object中的类型,则可以使用:

/settings

然后:

static <T> T copyObject(Object payload)
    {
        if (payload instanceof Human)
        {
            return (T) copyEntry((Human) payload);
        }
        if (payload instanceof Car)
        {
            return (T) copyEntry((Car) payload);
        }
        if (payload instanceof Planet)
        {
            return (T) copyEntry((Planet) payload);
        }
        return (T) payload;
    };

即使Java的Type Erasure不适用,您也需要语言的运行时知识才能做到这一点,也就是“依赖类型”。

因此,在某些语言(例如C ++)中发现的返回类型重载对Human h1 = new ... Human h2= copyObject(h1); 这样的运行时类型切换没有帮助。

但是为什么仍然需要这样做,您将在调用之后再次将所有对象实例收集到新的异构列表中