简体   繁体   中英

Is there a better and cleaner way to write this two functions?

So I am struggling to write this code in a clean way. I do not know if there is a better way.

private function1(Collection<D> collection) {
    for (Iterator it = collection.iterator(); it.hasNext(); ) {
        Object object = it.next();
        switch (object .getClass().getSimpleName()) {
            case "A": do some work with class A
                break;
            case "B": do some work with class B
                break; 
            case "C": do some work with class C
                break;  
        }
    }
}

So I get a collection which I iterate. But the collection can be three different classes in the collection since class A,B,C are of the parent class D. I think my code is not clean and I am looking for a good way to write this. Here is another example that I have which is a bit different.

private function2(Collection<A,B,C> collection) {
    for (Iterator it = collection.iterator(); it.hasNext(); ) {
        Object object = it.next();
        switch (object .getClass().getSimpleName()) {
            case "A": do some work with class A
                break;
            case "B": do some work with class B
                break; 
            case "C": do some work with class C
                break;  
        }
    }
}

In this function I can get either a collection of class A of class B or of class C. I though about making three separate functions for each class. But than I would have code duplicates. But I don't know if it would be actually better to split function2 into function2A, function2B, function2C.

Is there a better and cleaner way to implement those two functions. Classes A,B,C and D are from a framework. So I am unable to edit them.

Here is one idea. Mainly it separates the list of classes to process from the calling method so you don't have to modify your switch method to add other classes. Note that Collections implement Iterable so you don't need an explicit iterator.

It also presumes you would have methods established to do the required work.

  • build a map of name to method to call. This part replaces your switch statement.
  • it uses a default method to catch unknown class names should they appear
  • it them simply iterates, processing the objects.
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

public class WorkFunction {
    Map<String, Consumer<Object>> fnc = Map.of(
              "A", this::doWorkA,
              "B", this::doWorkB,
              "C", this::doWorkC);
    public static void main(String[] args) {
         WorkFunction wf = new WorkFunction();
         
         List<Object> list = List.of(new A(), new B(), new A(), new A(),
                                     new C(), new B(), wf);
         
         wf.function1(list);
    }
      
    static class A {}
    static class B {}
    static class C {}

        public <D> void function1(Collection<D> collection) {
             for(D object : collection) {
                  fnc.getOrDefault(object.getClass().getSimpleName(), 
                           (ob)->System.out.println("Who are you??")))
                  .accept(object);
               }
         }
        
        public void doWorkA(Object ob) {
            System.out.println("Working on A");
        }
        public void doWorkB(Object ob) {
            System.out.println("Working on B");         
        }
        public void doWorkC(Object ob){
            System.out.println("Working on C");
        }
        
}

prints

Working on A
Working on B
Working on A
Working on A
Working on C
Working on B
Who are you??

You can create an interface that A, B, and C can implement from. In your interface you can declare a method that will 'do the work' and A,B, and C can have their own implementations.

interface MyInterface{
  void doTheWork();
}

Then do this for each class

class A implements MyInterface { 
    void doTheWork() { 
        ...
    } 
}

Now you can just loop through the collection without having to check what class the instance is of

EDIT - If you cannot modify A,B, or C than you can use a map with the class as the key and a lambda as the value.

Map<Class,Runnable> lambdaClassMap = new HashMap<>();
lambdaClassMap.put(A.class, () -> doAWork(object));
lambdaClassMap.put(B.class, () -> doBWork(object));
lambdaClassMap.put(C.class, () -> doCWork(object));

//psuedocode
for(...) {
    Object object = it.next();
    lambdaClassMap.get(object.getClass()).run();
}

Utilize polymorphism to avoid the need to determine which subclass it is for the purpose of doing different work for each class.

Add a method doWork (or whatever name you have that would be more appropriate) to the D superclass, and implement it in all the subclasses A , B , and C . It may be abstract in D if appropriate.

Then your method becomes the following:

private void function1(Collection<? extends D> collection) {
    for (Iterator<? extends D> it = collection.iterator(); it.hasNext(); ) {
        D d = it.next();
        d.doWork();
    }
}

Use ? extends D ? extends D so that the method can accept a Collection<D> , Collection<A> , Collection<B> , or Collection<C> . This also avoids the raw Iterator .

You can also use the equivalent, shorter, enhanced for loop:

private void function1(Collection<? extends D> collection) {
    for (D d : collection) {
        d.doWork();
    }
}

Your second method appears just like the first method except that it attempts to use a Collection<A, B, C> , which doesn't make sense. Collection has only one type parameter.

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