简体   繁体   English

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

[英]creating a generic function to copy different objects

so i have a use case where i need to copy an object of class es ( classes may vary depending on the input type in factory. 所以我有一个用例,我需要复制 class es的object (类可能会有所不同,具体取决于工厂的输入类型。

here is a sample of what i am trying to do 这是我想要做的样本

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
    }
}

If you look at copyObject function, it does the job as intended but he issue is in return type. 如果你看一下copyObject函数,它可以完成预期的工作,但是他的问题是返回类型。 At present, to make itself compatible , its returning an Object but i would rather prefer to return it specific class Object ( say Human or Car for instance ) 目前,为了使自己兼容 ,它返回一个Object但我更愿意返回它特定的类Object(例如HumanCar

Is there a way to get this done with Generics (using <T> )? 有没有办法用Generics完成这个(使用<T> )? or is this a bad approach in the first place to do? 或者这首先是一个糟糕的做法?

Is there a way to get this done with Generics (using )? 有没有办法通过Generics(使用)完成这项工作? or is this a bad approach in the first place to do? 或者这首先是一个糟糕的做法?

It is a bad approach because you receive as parameter a Object . 这是一个不错的办法,因为您作为参数Object
You cannot infer from that the concrete type : whereas the instanceof you used. 你不能从中推断具体类型:而你使用的instanceof Which is not a fine approach. 这不是一个好方法。
Here two ideas (related enough) 这里有两个想法(足够相关)

1) Introducing a Copyable interface 1)介绍可复制的界面

You could introduce an interface that the classes of the objects you want to copy implement : 您可以引入一个接口,您要复制的对象的类实现:

public interface Copyable<T> {
    T copy(T t);
}

that could be implemented such as : 可以实施,如:

public class Human implements Copyable<Human> {

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

}

So the general copy() method could look like : 所以一般的copy()方法可能如下所示:

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

And you could use it in this way : 你可以用这种方式使用它:

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

2) Use the visitor pattern 2)使用访客模式

As alternative, it is also a good case for the visitor pattern : you want to apply a processing according to the concrete type of the parameter. 作为替代方案,它也是访问者模式的一个好例子:您希望根据参数的具体类型应用处理。
It allows to group together copy operations as in your actual code. 它允许将复制操作组合在一起,就像在实际代码中一样。

The general copyObject() method could rely on CopyVisitor that will do the copy according to the concrete type of the parameter : 一般的copyObject()方法可以依赖于CopyVisitor ,它将根据参数的具体类型进行复制:

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

Where CopyVisitor implements a classic Visitor interface : CopyVisitor实现了一个经典的Visitor接口:

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

in this way : 通过这种方式 :

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;
    }

}

The visited classes (Car, Human, Plan) would implement a specific interface to "accept" the visitor : 被访问的类(Car,Human,Plan)将实现一个特定的接口来“接受”访问者:

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

such as : 如 :

public class Human implements Visited {

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

}

So you can use the copy() method in this way : 所以你可以用这种方式使用copy()方法:

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

Unfortunately you have to do some unchecked casts like this: 不幸的是你必须做一些这样的未经检查的演员:

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;
}

But as mentioned in the comments this does not prevent you from writing: 但正如评论中所提到的,这并不妨碍你写作:

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

If you have knowledge about the type in Object you can do it with: 如果您对Object中的类型有所了解,可以使用:

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;
    };

and then: 然后:

Human h1 = new ...
Human h2= copyObject(h1);

Even if Java's Type Erasure would not apply you need runtime knowledge for your language to do so aka "dependent typing". 即使Java的类型擦除不适用,您也需要为您的语言提供运行时知识,即“依赖类型”。

So return type overloading found in some languages like in C++ wouldn't help for runtime type switches like in List<Object> . 因此,在C ++等某些语言中发现的返回类型重载对于List<Object>运行时类型切换没有帮助。

But why you need this anyway, you will collect all object instances after the call in a new heterogeneous List again 但是为什么你还需要这个,你将在调用之后再次收集所有对象实例

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

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