Provide an abstract method implementation, but limit visibility

I have a method in an abstract class that calls an abstract method for which subclasses must provide an implementation.

public abstract class AClass {

    public void foo() {
        ...
        fooToImplement();
        ...
    }

    // DON'T CALL THIS METHOD, ONLY PROVIDE IMPLEMENTATION!
    protected abstract void fooToImplement();

}

I want subclasses not to call fooToImplement (), they should always use foo (). Behavior is something like a "private abstract" method, but it is not possible in Java.

Is there an alternative? Thanks!

+4
source share
4 answers

If you do not want your subclasses to be able to call this method, you could use the strategy: Extract the behavior of the method into the interface and pass the implementation of this interface to the object. For example.

IStrategy {
  public void fooToImplement();
} 

AClass {
   public AClass(IStrategy impl) {...}

    public void foo() {
      ...
      strategy.fooToImplement();
      ...
    }
}

. java 8 .

IStrategy AClass, .

+4

, , . , AClass .

public class BClass extends ACLass {
   @Override 
   protected void fooToImplement() {
      System.out.println("override me im famous");
   }
}
public class CClass {
   private BCLass bInstance;
   public void doSomething(){
      bInstance.foo();
      // !!! NO ACCESS TO fooImplement()
   }
}
+2

fooToImplement() , , " " " ", .

, fooToImplement() :

interface FooImplementation {
    void fooToImplement(AClass a);
}

public abstract class AClass {

    private final FooImplementation fooImpl;
    protected AClass(FooImplementation fooImpl) {
         this.fooImpl = fooImpl;
    }

    public void foo() {
        ...
        fooImpl.fooToImplement(this);
        ...
    }

}

- yourFooImpl.fooToImplement(yourAClass). , , , fooToImplement(), AClass:

interface FooImplementation {
    void fooToImplement(AClass.AClassFooView a);
}

public abstract class AClass {

    private final FooImplementation fooImpl;

    protected AClass(FooImplementation fooImpl) {
        this.fooImpl = fooImpl;
    }

    public class AClassFooView {
        ...
        private AClassFooView() {
        }
    }

    public void foo() {
        ...
        fooImpl.fooToImplement(this.new AClassFooView());
        ...
    }

}

fooToImplement AClassFooView ...

, , fooToImplement(), .

, , - , , + + ..

+1

You can use AOP to do this, for example, add the @Before aspect in fooToImplement () and check the stacktrace of the call and throw an IllegalArgumentException if fooToImplement () can be called by any method other than foo (), something like:

if(!Thread.currentThread().getStackTrace()[1].getMethodName().equals("foo")) {
   throw new IllegalArgumentException("You musn't call fooToImplement() directly"+ 
", using foo() instead");
}

However, this path has two problems:

  • Perfomance
  • runtime exception
0
source

Source: https://habr.com/ru/post/1620721/


All Articles