-1

I'm implementing the composite design pattern and I notice that I have many traversals with code duplication.

For example:

class Composite extends BaseComposite{

    LinkedList<BaseComposite> objs;

    public BaseComposite foo(int id){
        for(BaseComposite obj : objs){
            if(obj.getId() == id){
                return obj;
            }
            BaseComposite tmp = obj.foo(id);
            if(tmp != null){
                return tmp;
            }
        }

        return null;
    }

    public BaseComposite bar(int id){
        for(BaseComposite obj : objs){
            if(obj.getId() == id){
                return obj;
            }
            BaseComposite tmp = obj.bar(id);
            if(tmp != null){
                return tmp;
            }
        }

        return null;
    }
}

class Leaf extends BaseComposite{
    public BaseComposite foo(int id){
        if(this.id == id){
            return this;
        }
        return null;
    }

    public BaseComposite bar(int id){
        return null;
    }
}

Is there a way to prevent this code duplication in the Composite class? Is there a way to have a "callback" that's a virtual method?

I prefer to avoid reflection.

ucMedia
  • 4,105
  • 4
  • 38
  • 46
shinzou
  • 5,850
  • 10
  • 60
  • 124
  • 1
    Take a look at `java.util.function.BiFunction` interface. If you are not satisfied with having to box the `id`, roll your own similar interface. – M. Prokhorov Feb 28 '18 at 17:03

1 Answers1

1

In Java 8 you could pass just one recursive method and pass a function as a second parameter. Then you'd pass this::foo or this::bar as an argument. Something along the lines:

public BaseComposite traverse(BiFunction<Integer, BaseComposite, BaseComposite> f, int id){
        for(BaseComposite obj : objs){
            if(obj.getId() == id){
                return obj;
            }
            BaseComposite tmp = f.apply(obj, id);
            if(tmp != null){
                return tmp;
            }
        }

        return null;
    }

    public BaseComposite foo(int id){
        return traverse(this::foo, id);
    }

    public BaseComposite bar(int id){
        return traverse(this::bar, id);
    }
lexicore
  • 42,748
  • 17
  • 132
  • 221
  • I see that it's better to use `Function` interface so `foo`'s signature would be `foo(int id)` and not `foo(int id, BaseComposite bc)`. I also have a delete function in the base class, is it there a way to `apply` a delete on that list? – shinzou Feb 28 '18 at 17:37
  • @shinzou About delete function - quite probably. – lexicore Feb 28 '18 at 17:39
  • Hmm this doesn't work actually, the `apply` isn't being applied to every `obj`... – shinzou Feb 28 '18 at 18:04