2010-04-06 2 views
12

меня есть абстрактный класс BaseClass с insert() методом открытой:перегрузки и скрытие методы в Java

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

Это можно сделать в ООП?

ответ

18

Нет способа сокрытие метод. Вы можете сделать это:

@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), расширяют другой подкласс базового объекта.

6

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

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

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

1

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

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

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

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

1

Это звучит как плохо разработанной иерархии -

Если по умолчанию не существует, и пользователь не должен вызывать метод вообще можно пометить метод как @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) { 
     // ... 
    } 
}