Подтвердить что ты не робот

Могу ли я заставить абстрактные методы защищаться, когда кто-то их переопределяет?

В моем абстрактном классе у меня есть что-то вроде этого:

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

protected abstract void methodIDontWantExposed();

Дело в том, что я хочу заставить человека, который расширяет методIDontWantExposed(), чтобы защитить его, потому что я не хочу, чтобы расширяемый класс имел как методIDontWantExposed, так и методIWantToExpose.

Есть ли способ сделать это (или другой подход, который мог бы избежать моей проблемы)?

4b9b3361

Ответ 1

Нет, подкласс всегда может расширить доступ при переопределении метода. Там нет способа предотвратить это. Обычно, однако, когда я переопределяю метод, я редко меняю видимость от защищенного до публики. Документирование цели метода может быть достаточно, чтобы убедить исполнителя в том, что в этом случае это будет плохая идея.

Если вы действительно хотите инкапсулировать поведение по-частному, вы можете сделать что-то в следующих строках:

abstract class YourClass {
    private HandlerInterface unexposedHandler;

    YourClass(HandlerInterface handler) {
        unexposedHandler = handler;
    }

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

С Java 8 вы даже можете сделать HandlerInterface функциональный интерфейс и удобно использовать лямбда следующим образом:

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

    ...
}

Ответ 2

Нет. Подкласс всегда может сделать метод более общедоступным.

Даже если они не могут сделать это с помощью метода, который у вас есть в вашем классе, они всегда могут писать:

public void callsMethodIDontWantExposed() {
    methodIDontWantExposed();
}

... так что вы будете в той же ситуации.

Ответ 3

Это зависит от того, хотите ли вы, чтобы пользователи вашего класса могли переопределить этот метод или нет. Если вы позволите им переопределить его, они всегда могут переопределить его общедоступным методом.

Некоторые способы избежать использования этого метода:

  • Имейте это в абстрактном классе и сделайте его окончательным, поэтому его нельзя переопределить.

  • Сделать пакет приватным и реализовать его в одном из подклассов, относящихся к одному и тому же пакету. Поскольку вы будете внедрять его, вы можете сохранить его в приватном пакете или изменить его на окончательный, чтобы подклассы вне вашего пакета не могли переопределить его с помощью общедоступного метода.

Ответ 4

В некоторых случаях вы можете избежать абстрактного метода (и даже даже подкласса) вообще, и вместо этого вы можете использовать strategy, определенный в перечисление.

Конечно, используемый экземпляр enum может быть открыт, но, по крайней мере, он гарантирует, что единственное допустимое поведение - это те, которые определены в вашем перечислении.

Итак, ваше решение будет примерно таким:

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

Ответ 6

Нет, вы не можете. Если бы это был конкретный метод, вы могли бы сделать его частным. В вашем случае нет разумного способа предотвратить распространение объявляющего класса (можно, конечно, прокомментировать этот метод, заявив, что его не следует публиковать).