Home > database >  Automatically call superclass method after inherited subclass method
Automatically call superclass method after inherited subclass method

Time:12-22

I have a class A where I want foo to be called immediately after blah is called, including calls to blah from subclasses. So below, B().blah() will also call A.foo. I think this type of thing is possible in Python using decorators, but don't know how to achieve the same effect in Java.

class A {
  @protected
  void blah() {
    // pass
  }

  void foo() {
    System.out.println("foo called");
  }
}

class B extends A {
  void blah() {
    System.out.println("blah called");
  }
}

In python, something like this works although it still needs the blah decorator to be added in the subclass:

from abc import ABC, abstractmethod

def blah(fn):
    def wrapper(*args, **kwargs):
        retval = fn(*args, **kwargs)
        print("blah called")
        return retval
    return wrapper

class A(ABC):
    @abstractmethod
    @blah
    def foo(self):
        pass

class B(A):
    @blah
    def foo(self):
        print("foo called")

B().foo()
# prints:
#   foo called
#   blah called

CodePudding user response:

In java you can also use decorator pattern

Based on your example, try this:

class A {
  void foo() {
    System.out.println("foo called");
  }

  void blah() {
    // Implementation of blah
  }
}

class B extends A {
  @Override
  void blah() {
    super.blah();
    foo();
  }
}

Now, when you call blah on an instance of B, the foo method will be called immediately after the original implementation of blah.

CodePudding user response:

You can make blah() a final method in your base class, with an onBlah() method in your child classes which is implemented instead of overriding blah. This enforces the calling of foo().



abstract class A {
    public final void blah() {
        onBlah();
        foo();
    }

    public final void foo() {
        System.out.println("Foo called");
    }

    /**
     * Subclasses implement this to provide blah behaviour
     */
    protected abstract void onBlah();
}

class B extends A {

    @Override
    protected void onBlah() {
        System.out.println("Subclass blah");
    }
}

public class So74882376 {
    public static void main(String[] args) {
        new B().blah();
    }
}

Because blah() is final, no subclass can break the relationship between calling blah and calling foo.

onBlah() is protected so that we don't pollute the public interface of A.

Designing for inheritance is something which needs careful thought. It is often better to use composition.

An alternative to using inheritance here would be to compose an A and a BlahStrategy instance:

interface BlahStrategy {
    public void onBlah();
}

final class A2 {
    private final BlahStrategy blahStrategy;

    public A2(BlahStrategy blahStrategy) {
        this.blahStrategy = blahStrategy;
    }

    public void blah() {
        blahStrategy.onBlah();
        foo();
    }

    public void foo() {
        System.out.println("Foo called");
    }
}

public class So74882376 {
    public static void main(String[] args) {
        new B().blah();
        new A2(() -> System.out.println("my blah action")).blah();
        new A2(() -> System.out.println("another blah action")).blah();
    }
}
  • Related