Перегрузка и скрывает методы в Java

у меня есть абстрактный класс BaseClass с общественностью insert() метод:

public abstract class BaseClass {

 public void insert(Object object) {
  // Do something
 }

}

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

public class SampleClass extends BaseClass {

 public void insert(Object object, Long param){
  // Do Something
 }

}

Теперь, если я инстанцирую класса SampleClass, я имею два insert() методы:

SampleClass sampleClass = new SampleClass();
sampleClass.insert(Object object);
sampleClass.insert(Object object, Long param);

то, что я хотел бы сделать, должно скрыться insert() метод определил в базовом классе, так, чтобы просто перегрузка была бы видима:

SampleClass sampleClass = new SampleClass();
sampleClass.insert(Object object, Long param);

Это могло быть сделано в ООП?

14
задан Dan Neely 12 May 2019 в 14:07
поделиться

4 ответа

Невозможно скрыть метод. Вы можете сделать это:

@Override
public void insert(Object ob) {
  throw new UnsupportedOperationException("not supported");
}

но это все.

Базовый класс создает контракт. Все подклассы связаны этим контрактом. Подумайте об этом так:

BaseObject b = new SomeObjectWithoutInsert();
b.insert(...);

Как этот код должен знать, что у него нет метода insert (Object) ? Не может.

Ваша проблема похожа на проблему дизайна. Либо рассматриваемые классы не должны наследовать от рассматриваемого базового класса, либо этот базовый класс не должен иметь этого метода. Возможно, вы можете взять insert () из этого класса, переместить его в подкласс и иметь классы, которым требуется insert (Object) , расширить его, а также те, которым требуется insert (Object , Object) расширяет другой подкласс базового объекта.

21
ответ дан 1 December 2019 в 09:01
поделиться

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

В редких случаях это можно обойти, например, создание исключения может быть желательным (или, по крайней мере, приемлемым компромиссом - например, Java Collections Framework), но в целом это признак плохого дизайна.

Вы можете прочитать принцип подстановки Лискова : идея о том, что (как говорит Википедия) «если S является подтипом T, то объекты типа T в программе могут быть заменены с объектами типа S без изменения каких-либо желаемых свойств этой программы ". Переопределяя метод создания исключения или скрывая его любым другим способом, вы нарушаете этот принцип.

Если контракт метода базового класса был «вставляет текущий объект или генерирует исключение» (см., Например, JavaDoc for Collection.add () ), то вы можете утверждать, что вы не нарушая LSP, но если это является неожиданным для большинства вызывающих абонентов, вы можете пересмотреть свой дизайн на этих основаниях.

2
ответ дан 1 December 2019 в 09:01
поделиться

Я не верю, что в Java есть чистый способ полностью скрыть наследуемый метод.

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

В конце концов, если вы наследуете метод, который не имеет смысла для вашего дочернего класса, может оказаться, что вам вообще не следует наследоваться от этого базового класса. Также может быть, что базовый класс плохо спроектирован или включает в себя слишком много функций, но, возможно, стоит задуматься об иерархии классов. Другим путем может быть композиция, когда ваш класс имеет частный экземпляр того, что раньше было базовым классом, и вы можете выбрать, какие методы раскрывать, обернув их в свои собственные методы. (Редактировать: если базовый класс абстрактный, композиция может оказаться невозможной...)

.
6
ответ дан 1 December 2019 в 09:01
поделиться

Звучит как плохо спроектированная иерархия -

Если по умолчанию не существует и пользователь не должен вызывать метод вообще, вы можете пометить метод как @Deprecated и выбросить UnsupportedOperationException , как отметили другие плакаты. Однако - это действительно только проверка во время выполнения. @Deprecated выдает только предупреждение компилятора, и большинство IDE каким-то образом помечают это, но это не предотвращается во время компиляции. Это также действительно отстой, потому что можно получить дочерний класс в качестве ссылки на родительский класс и вызвать метод для него без предупреждения, что он вообще «плохой». В приведенном ниже примере до времени выполнения не будет никаких указаний на то, что что-то не так.

Пример:

// Abstract base builder class
public abstract class BaseClassBuilder {
    public final doBuild() {
        BaseClass base = getBase();
        for (Object obj : getObjects() {
            base.insert(obj);
        }
    }
    protected abstract BaseClass getBase();
    protected abstract Object[] getObjects();
}

// implementation using SampleClass
public class SampleClassBuilder extends BaseClassBuilder {

    @Override
    protected BaseClass getBase() {
        return new SampleClass();
    }

    @Override
    protected Object[] getObjects() {
        Object[] obj = new Object[12];
        // ...
        return obj;
    }
}

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

Пример:

public abstract class BaseClass { 
    public void insert(Object object) {
        // ...
    }
}

public class SampleClass extends BaseClass {

    public static final Long DEFAULT_PARAM = 0L;

    public final void insert(Object object) {
        this.insert(object, DEFAULT_PARAM);
    }

    public void insert(Object object, Long param) {
        // ...
    }
}
1
ответ дан 1 December 2019 в 09:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: