简体   繁体   中英

Can I force abstract methods to be protected when someone overrides them?

In my abstract class, I have something like this:

public Object methodIWantToExpose(){
  // ... 
  methodIDontWantExposed()
  // ...
}

protected abstract void methodIDontWantExposed();

The thing is, I want to force the person that extends methodIDontWantExposed() to make it protected, because I don't want the extending class to have both methodIDontWantExposed and methodIWantToExpose exposed.

Is there a way to do this (or a different approach which might avoid my problem)?

No. A subclass can always make a method more public.

Even if they couldn't do this with the method you have in your class, they could always write:

public void callsMethodIDontWantExposed() {
    methodIDontWantExposed();
}

... so you'd be in the same situation.

No, a subclass can always widen the access when overriding a method. There's no way to prevent that. Usually however, when I override a method I rarely change visibility from protected to public. Documenting the purpose of the method carefully might be enough to convince the implementer that it would be a bad idea in this case.

If you really want to encapsulate the behavior in a private way, you could do something along the following lines:

abstract class YourClass {
    private HandlerInterface unexposedHandler;

    YourClass(HandlerInterface handler) {
        unexposedHandler = handler;
    }

    public Object methodIWantToExpose(){
        // ... 
        handler.methodIDontWantExposed();
        // ...
    }
}

With Java 8 you could even make HandlerInterface a functional interface and conveniently use a lambda as follows:

class YourSubClass extends YourClass {
    YourSubClass() {
        super(() -> {
            System.out.println("This is the unexposed code");
        });
    }

    ...
}

It depends on whether you want users of your class to be able to override that method or not. If you let them override it, they can always override it with a public method.

Some ways you can avoid letting them override that method :

  1. Have it implemented in the abstract class and make it final, so it can't be overridden.

  2. Make it package private and implement it in one of more sub-classes that belong to the same package. Since you'd be the one implementing it, you can keep it package private, or change it to final protected, so that sub-classes outside your package wouldn't be able to override it with a public method.

In certain cases you can avoid having an abstract method (and indeed even subclassing) altogether and instead you can use a strategy defined in an enum.

Of course the enum instance used can still be exposed but at least it's guaranteed that the only behaviours allowed are the ones defined in your enum.

So your solution would be something like this:

enum Behaviour {
  ONE() {
     public Object doSomething() { return "ONE"; }
  };

   public abstract Object doSomething();
}

// and your class

public abstract class MyClass {
   private final Behaviour behaviour;

   protected MyClass( Behaviour behaviour ) {
     this.behaviour = behaviour;
   }

   public final void methodIWantToExpose() {
      // ...
      behaviour.doSomething();
      // ...
   } 
}

You can't because increasing the visibility of a method does not break base class contract.

Take a look at Why Java allows increasing the visibility of protected methods in child class?

No you can't. If it were to be a concrete method, you could make it private. In your case there is no smart way to prevent an extending class from declaring it public (you can of course comment the method, saying it shouldn't be made public).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM