简体   繁体   English

Java:如何使用相同的代码相同地对待2个不同的对象?

[英]Java: How To Treat 2 Different Objects The Same, With The Same Code?

I have a situation where I have two different objects that do mostly the same thing, but that have a different API. 我遇到的情况是,我有两个不同的对象,它们执行的功能大致相同,但是具有不同的API。

If I could treat them the same I could use one method to take care of both of them. 如果我能一视同仁,我可以使用一种方法来照顾他们两个。

Basically, I need to iterate through either using a for loop. 基本上,我需要使用for循环进行迭代。 The two objects have different function names for getting the size and retriving the latest result inside of each: 这两个对象具有不同的函数名称,用于获取大小并检索每个对象内部的最新结果:

CustomUnMutableObj1.getMySize() CustomUnMutableObj2.getTotal() CustomUnMutableObj1.getMySize()CustomUnMutableObj2.getTotal()

CustomUnMutableObj1.getlastresult() CustomUnMutableObj2.getlastvalue() CustomUnMutableObj1.getlastresult()CustomUnMutableObj2.getlastvalue()

Is there anyway I can use the same for loop for both, without a big clumsy set of conditionals, and having the code being blind to the type of object? 无论如何,在没有大量笨拙的条件集且代码对对象类型视而不见的情况下,我可以为两者都使用相同的for循环吗?

If you can't modify the two classes in question so they implement a common interface, you could still get the same effect by writing some "adapter classes" : 如果您不能修改有问题的两个类,以便它们实现一个公共接口,则可以通过编写一些“适配器类”来达到相同的效果:

interface CustomObjInterface {
    int getSize();
    int getLatestResult();
}

class CustomUnMutableObj1Adapter implements CustomObjInterface {
    private CustomUnMutableObj1 wrapped;
    public CustomUnMutableObj1Adapter(CustomUnMutableObj1 wrapped) {
        this.wrapped = wrapped;
    }
    @Override int getSize() {return wrapped.getMySize();}
    @Override int getLatestResult() {return wrapped.getTotal();}
}

// and a similar class for CustomUnMutableObj2

and then use the adapters instead of the original objects: 然后使用适配器而不是原始对象:

void doStuff(CustomObjInterface obj) {
    // do stuff with obj here, using getSize and getLatestResult
}

// call it like this, for a CustomUnMutableObj1
// If you had a CustomUnMutableObj2, you'd use a CustomUnMutableObj2Adapter instead
doStuff(new CustomUnMutableObj1Adapter(obj));

Something that is unclear: you said "iterate thru either using a for loop", does it mean that your method is getting either a Collection<Obj1> or a Collection<Obj2> , but not a Collection<Object> which will contains both Obj1 and Obj2 ? 尚不清楚的一件事:您说过“使用for循环迭代”,是否表示您的方法获取的是Collection<Obj1>Collection<Obj2> ,但不是同时包含两个Obj1Collection<Object>Obj2吗? (My answer is base on the above assumption) (我的回答是基于上述假设)

IMHO, using adapter (as suggested in other answer) may not be a good choice for above case, because if you are passing in a List<Obj1> , you have to construct a List<CustomUnMutableObj1Adapter> and pass to your "common processing method" for which you still need a bunch of code to handle it, and you will create one adapter list + one adapter for each element for each invocation of process logic, which may not be a good idea 恕我直言,使用适配器(如其他答案所示)可能不是上述情况的好选择,因为如果要传递List<Obj1> ,则必须构造一个List<CustomUnMutableObj1Adapter>并传递给您的“通用处理方法” ”,您仍然需要一堆代码来处理它,并且对于流程逻辑的每次调用,您将为每个元素创建一个适配器列表+一个适配器,这可能不是一个好主意

Of course the best way to solve is to introduce a common interface/superclass to give these operations a meaningful concept. 当然,最好的解决方法是引入公共接口/超类,以使这些操作有意义。 However if it is not a choice, you may see if the following helps you. 但是,如果这不是一个选择,则可能会看到以下内容对您有帮助。

One way to reduce the boiler-plate code is by using something similar to a template method (If you are familiar with Spring, there are a lot of similar template like this) 减少样板代码的一种方法是使用类似于模板方法的方法(如果您熟悉Spring,则有很多类似的模板)

eg (pseudo-code, not compiled) 例如(伪代码,未编译)

interface ProcessInfoExtractor<T> {
    int getSize(T entity);
    String getLastValue(T entity);
}

The above interface will be responsible to perform the "common" operation against a provided object. 上面的接口将负责对提供的对象执行“公共”操作。

Then make your processing method like this: 然后使您的处理方法如下:

void <T> process(Collection<? extends T> entities, ProcessInfoExtractor<T> infoExtractor) {
    for (T entity : entites) {
        System.out.println("size " + infoExtractor.getSize(entity)
                         + " last value " + infoExtractor.getLastValue(entity));
    }
}

so when you need to iterate thru a List<Obj1> , simply do: 因此,当您需要遍历List<Obj1> ,只需执行以下操作:

process(obj1List,
        new ProcessInfoExtractor<Obj1> (
            @Override
            int getSize(Obj1 obj1) { return obj1.getMySize(); }
            @Override
            String getLastValue(Obj1 obj1) { return obj1.getLastResult(); }
        ));

(Similar case for Obj2 ) (与Obj2类似的情况)

To ease caller, you can make 2 wrapper methods which internally call the above process method, like 为了简化调用程序,您可以创建2个内部调用上述process方法的包装方法,例如

void process(Collection<Obj1> obj1List) {
    process(obj1List, obj1InfoExtractor); // assume extractor is stateless,
                                          // you can create one and reuse it
};

void process(Collection<Obj2> obj2List) {
    process(obj2List, obj2InfoExtractor); // assume extractor is stateless,
                                          // you can create one and reuse it
};

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

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