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();
}
}