0

I want to create a wrapper class over another class so that it hides the functionality of wrapped class and also the wrapper provides certain methods of its own.

For example, lets say we have class A as

public class A{
    void method1(){ ... do something ... }
    void method2(){ ... do something ... }
    void method3(){ ... do something ... }
}

Now I want another class B which wraps class A, so that it has its own methods, and also if someone asks method of class A, it should delegate it to class A.

public class B{
     // if someone asks method1() or method2() or method3() ... it should delegate it to A
     
     // and also it has own methods
     void method4(){ ... do something ... }
     void method5(){ ... do something ... }
}

I can't use inheritance (i.e B extends A) because its not easy with my use case (where A has concrete constructor with some parameters which we can't get ... but we can get the object of A).

I can't simply delegate each function in A using object of A (because there are several functions in A)

Is there any other way to obtain class B with said restrictions?

Important Note: Class A is handled by someone else. We can't change any part of it.

Harsha Chittepu
  • 115
  • 1
  • 8
  • Probably, reflection is your only option. Are you sure you can't delegate those methods? – Andrew Vershinin Aug 05 '20 at 14:29
  • 2
    Can you explain better why "I can't simply delegate each function in A using object of A (because there are several functions in A)" ? – Frighi Aug 05 '20 at 14:34
  • Can class A be singleton or you need multiple inheritances ? – bakero98 Aug 05 '20 at 14:37
  • @bakero98 class A inherits from single interface containing several methods. Class A doesn't need to be singleton – Harsha Chittepu Aug 06 '20 at 06:44
  • @AndrewVershinin ... I can delegate every function of A in B by writing each method explicitly. But I don't want that because of 2 reasons 1) There are several functions in A, and I don't want to do tedious work of writing each method explicitly in B. 2) The class A is not in my control, I mean someone might update its method signatures, In that case I need to watch over class A and made changes to my class B. – Harsha Chittepu Aug 06 '20 at 06:55
  • @Frighi .. please refer to my previous comment – Harsha Chittepu Aug 06 '20 at 06:56
  • 1
    There is a contradiction in your requirement “…so that it hides the functionality of wrapped class” and the fact that you want to create a delegating method for every method of A, even reflecting potential changes of A’s API. In other words, you are not hiding but exposing every functionality of A. You couldn’t have less encapsulation. So why not just add a method to `B` that returns the `A` and you’re done. Your pseudo encapsulation is only wasting development efforts for no benefit. – Holger Aug 06 '20 at 15:57
  • @HSReddy "class A inherits from single interface containing several methods" are these methods those you want to preserve (1 .. 3)? – Hawk Aug 07 '20 at 13:36

2 Answers2

0

This can be easily done with CGLIB but will require few modifications. Consider if those modifications may not be harder to do that the actual delegation of the methods.

  1. You need to extend the classes, this can be done by adding the no arg constructor to class A, we will still delegate all the methods so do not worry about unreachable params, we are not worried about missing data, we just want the methods

  2. You need to have CGLIB on you classpath cglib maven, maybe you already have it

Than

A would look like

public class A {

    private String arg = "test";

    public A() {
        // noop just for extension
    }

    public A(String arg) {
        this.arg = arg;
    }

    public void method1() {
        System.out.println(arg);
    }
}

B would look like

public class B extends A implements MethodInterceptor {

    private A delegate;

    private B(A delegate) {
        this.delegate = delegate;
    }

    public static B createProxy(A obj) {
        Enhancer e = new Enhancer();
        e.setSuperclass(obj.getClass());
        e.setCallback(new B(obj));
        B proxifiedObj = (B) e.create();
        return proxifiedObj;
    }

    void method2() {
        System.out.println("a");
    }


    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        Method m = findMethod(this.getClass(), method);
        if (m != null) { return m.invoke(this, objects); }
        Object res = method.invoke(delegate, objects);
        return res;
    }

    private Method findMethod(Class<?> clazz, Method method) throws Throwable {
        try {
            return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
        } catch (NoSuchMethodException e) {
            return null;
        }
    }

}

That you can do

MyInterface b = B.createProxy(new A("delegated"));
b.method1(); // will print delegated

This is not very nice solution and you probably do not need it, please consider refactoring your code before doing this. This should be used only in very specific cases.

Pavel Polivka
  • 858
  • 4
  • 22
  • Thanks for this approach. I have forgot to mention in question that we can't modify anything in class A(its handled by someone else). But your approach seems fine with the fact that we add default constructor in A. But without changing anything in class A, can we solve this problem of delegating A methods in B? – Harsha Chittepu Aug 06 '20 at 06:53
  • You would need to implement all the methods by your self. So my guess is no, if you cannot change anything in A. – Pavel Polivka Aug 06 '20 at 07:03
0

What you have described is a Decorator pattern coined by GOF. There is plenty of sources on the Internet about it. It is similar to the Proxy pattern (as in the answer of Pavel Polivka) but the intent is different. You need the Decorator pattern:

Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality. sourcemaking.com

As you have written in a comment

class A inherits from single interface containing several methods

I assume A implements AIntf and contains all the methods you want.

public class BDecorator implements AIntf {
    private A delegate;

    private BDecorator(A delegate) {
        this.delegate = delegate;
    }

    void method1(){ delegate.method1(); }
    // ...

    void method4(){ /* something new */ }

There are several functions in A, and I don't want to do tedious work of writing each method explicitly in B.

Java is a verbose language. However, you don't need to do this by hand, every decent IDE provides automatic generation of delegate methods. So it will take you 5 seconds for any amount of methods.

The class A is not in my control, I mean someone might update its method signatures, In that case I need to watch over class A and made changes to my class B.

If you create B you are responsible for it. You at least notice if anything changed. And once again, you can re-generate the changed method with the help of an IDE in an instant.

Hawk
  • 2,042
  • 8
  • 16