Это показывает, почему важно " обращаться к объектам по их интерфейсам ", как описано в Effective Java book.
Если вы кодируете реализацию и используете ArrayList, скажем, в 50 местах в вашем коде, когда вы найдете хорошую реализацию "List", которая подсчитывает элементы, вам придется изменить все эти 50 мест, и, вероятно, вы ' Вам придется взломать ваш код (если он используется только вами, это не имеет большого значения, но если его использует кто-то другой, вы тоже сломаете его код)
Программируя интерфейс, вы можете оставить эти 50 мест без изменений и заменить реализацию из ArrayList на «CountItemsList» (например) или какой-либо другой класс.
Ниже приведен очень простой пример того, как это можно написать. Это только образец, список готовых к производству будет намного более сложным.
import java.util.*;
public class CountItemsList<E> extends ArrayList<E> {
// This is private. It is not visible from outside.
private Map<E,Integer> count = new HashMap<E,Integer>();
// There are several entry points to this class
// this is just to show one of them.
public boolean add( E element ) {
if( !count.containsKey( element ) ){
count.put( element, 1 );
} else {
count.put( element, count.get( element ) + 1 );
}
return super.add( element );
}
// This method belongs to CountItemList interface ( or class )
// to used you have to cast.
public int getCount( E element ) {
if( ! count.containsKey( element ) ) {
return 0;
}
return count.get( element );
}
public static void main( String [] args ) {
List<String> animals = new CountItemsList<String>();
animals.add("bat");
animals.add("owl");
animals.add("bat");
animals.add("bat");
System.out.println( (( CountItemsList<String> )animals).getCount( "bat" ));
}
}
Применяемые здесь ОО-принципы: наследование, полиморфизм, абстракция, инкапсуляция.