У вас есть концепции с ног на голову.
Наследование , как говорится в слове, это когда вы «берете» из существующего объекта функциональность. Это известно как отношения IS-A. Например, Грузовик IS-A Автомобиль.
В вашем первом примере это не наследование, потому что вы ничего не берете из списка. В вашем примере вы «внедряете» этот список, а не «расширяете» его.
Композиция - это когда вы строите объект, используя других (вы комбинируете объекты). Это известно как отношения HAS-A. Например, грузовик HAS-A колесо (но не колесо). В вашем примере вы «расширяете» (наследуете) от другого объекта
Наконец, interface в ООП - это "контракт", который объект обязуется выполнить. На какие функции или сообщения будет реагировать объект.
В Java «интерфейс» также является артефактом, в котором определены методы, на которые будет реагировать объект.
Итак, для стека вы должны определить методы стека (интерфейс)
public interface Stack {
public void push( Object o );
public Object pop();
}
Затем, используя наследование , вы можете создать реализацию стека. Для этого вам нужно расширить (или наследовать) функциональность от другого класса. Допустим, ArrayList
/**
* Sample stack implementation using inheritance
*/
public class ArrayListStack extends ArrayList implements Stack {
// you use the keyword extends because you're inheriting from ArrayList
// and the keyword implements because you claim to respond to push and pop methods.
public void push( Object o ) {
this.add( o ); // add inherited from ArrayList
}
public Object pop() {
return this.remove( this.size() -1 ); // remove inherited from ArrayList
}
}
Поскольку вы «наследуете» от ArrayList, большая часть того, что вам нужно, уже есть. Но представляет ли это отношение IS-A? Правда ли, что Stack IS-An ArrayList всегда?
Чтобы реализовать стек, используя состав , вам нужно «объединить» ваш объект с другим.
/**
* Sample stack implementation using composition
*/
public class ComposedStack implements Stack {
// you didn't extend anything here
// But you'll need another object to help you
// to do the work.
private ArrayList holder = .... // Should be declared as List holder = ....
public void push( Object o ) {
this.holder.add( o );
}
public Object pop() {
return this.holder.remove( this.holder.size() -1 );
}
}
Реализация очень похожа, вы используете методы "добавить" и "удалить" из ArrayList
Разница в том, что в первом случае, используя наследование , вы не только используете эти два метода, но и полностью связываете свой объект с самим ArrayList (поскольку вы также унаследовали все другие методы, и атрибут ArrayList имеет)
Когда вы используете состав , вы не связываете свой объект с массивом (или связь низкая, что хорошо). Вы просто используете другой объект, чтобы помочь вам выполнить работу. , В данном случае это был ArrayList.
Снаружи (используя композицию) вы не видите, что внутри есть ArrayList, это информация скрывается. Пользователь (клиент) вашего класса видит только два доступных метода «push» и «pop», и больше ничего нельзя сделать с вашим классом. Это похоже на «настоящий» стек.
С наследованием (используя ключевое слово extends), клиент класса также видит все методы из ArrayList , хотя вы можете захотеть использовать только pop и push, ничто не мешает клиенту использовать "removeRange" " например.
Заключение: Понимание различий между отношениями «есть» и «есть» имеет важное значение для технологии ОО. Я надеюсь, что это поможет вам.