2017-01-17 1 views
0

Я видел, как некоторые люди использовали самый верхний родительский класс как тип переменной для хранения дочернего экземпляра, а некоторые люди используют только родительский класс. Например:Должен ли мы использовать самый верхний родительский класс как тип ссылочной переменной?

Collection obj = new ArrayList(); 
Or 
List obj = new ArrayList(); 

Здесь список подпадает под коллекцию, тогда мы не можем использовать выше первой строки вместо второй?

Опять же, мы не можем использовать всюду в структуре коллекции ссылочную переменную класса Collection только для хранения любого экземпляра класса в коллекции?

Это хорошая практика?

Итак, я хотел знать, что входит в лучшие практики и почему?

Если кто-то может обосновать технически подобные проблемы с производительностью и т. Д., Будем очень благодарны.

ответ

2

Общая идея скрывает столько, сколько вы можете, поэтому все проще изменить. Если вам нужна индексация, например (List.get (int index), то она ДОЛЖНА быть списком, потому что коллекция не поддерживает .get (index). Если вам не нужна индексация, а затем скрывает тот факт, что вы используете список , означает, что вы можете переключиться на другие коллекции, которые впоследствии не могут быть перечислены без каких-либо проблем.

Например, возможно, через месяц я хочу использовать набор вместо списка, но Set не поддерживает .get (index). Таким образом, любой, кто использует этот Список, может использовать функции индексирования списка, и это затруднит переход к набору, потому что каждый, где кто-то еще использовал .get(), будет ломаться.

С другой стороны, чрезмерное скрытие ваших типов может привести к случайным проблемам производительности, поскольку потребитель вашего метода не знал этого типа. Предположим, вы вернули List th at на самом деле связанный список (где индексирование O (n)). Предположим, что потребитель этого списка выполняет поиск каждой записи в другом списке. Это может быть производительность O (n * m), которая очень медленная. Если вы рекламируете, что это был связанный список, в первую очередь, потребитель связанного списка понял бы, что, вероятно, не очень хорошая идея сделать несколько индексов в этом списке, и потребитель может сделать локальную копию.

код библиотеки (предположим, что один вы разрабатываете)

public class Util { 
    public static List<String> makeData() { 
    return new LinkedList(Arrays.asList("dogs", "cats", "zebras", "deer")); 
    } 
} 

код вызывающего абонента (предположим, тот, который использует вашу библиотеку или метод)

public static void main(String [] args) { 
    List<String> data = Util.makeData(); 
    int [] indicesToLookUp = {1,4,2,3,0}; 
    for(int idx : indicesToLookUp) { 
    if(idx < data.size()) { 
     // each index (LinkedList.get()) is slow O(N) 
     doSomethingWithEntry(idx, list.get(idx)); 
    } 
    } 
} 

Вы можете возразить, что это вина абонента, потому что он неправильно предположил, что List является ArrayList <> и должен был сделать локальную копию списка.

+0

Это может быть хороший ответ так, я дам вам один голос вверх. но я не мог понять значение последнего пара, в котором вы упомянули «Это может быть производительность O (n * m), которая очень медленная». Не могли бы вы дать мне несколько хороших ссылок на это, чтобы лучше понять это? – Joy

+0

У меня нет ссылки на него, так как это анекдот моего развития. Я попытаюсь добавить пример. У меня есть больше на первых двух параграфах здесь: http://softwareengineering.stackexchange.com/questions/132019/what-is-the-value-in-hiding-the-details-through -abstractions-isnt-there-value , Они делают БОЛЬШУЮ лучшую работу, чем я. – joseph

2

Это действительно зависит от ваших потребностей. В вашем примере это не сильно изменяет основные потребности, но если вы проверите два интерфейса, есть некоторые изменения. Посмотрите: https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html и https://docs.oracle.com/javase/7/docs/api/java/util/List.html

Мы можем заметить, что список дает вам доступ к методам сбора не.
set (int index, E element), например, определен в интерфейсе List, а не в Collection.

Это потому, что каждому классу, наследующему от Collection, не нужно реализовывать все те же методы.

Производительность не имеет никакого влияния.

Всегда используйте самый верхний родительский класс, который обладает всеми необходимыми функциями. Для вашего примера нет необходимости идти выше списка.

2

Существует нет так называемой «лучшей практики» для выбора класса, который будет использоваться для ссылочного типа. Фактически, класс в самой высокой иерархии - это класс Object. Используете ли вы Object в качестве ссылочного типа для всего, что вы делаете? Нет, но обычно вы можете выбрать более высокий класс со всеми методами, доступными для ваших нужд.

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

Вот некоторые преимущества и недостатки для использования более высоких классов иерархии как тип опорного:

Advantage

  • Позволяет группировку объекта, который разделяет один и тот же предок (супер класс)
  • Позволяет все экземпляры данного класса, которые должны быть назначены ему

    Animal dog = new Dog(); 
    Animal cat = new Cat(); 
    
  • Позволяет полиморфизм

    dog.makeNoise(); 
    cat.makeNoise(); 
    

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

Неудобство

  • Требуется литье, когда вы обращаетесь к модели поведения, которые существуют в одном объекте, но не другие.

    dog.swim(); //error, class Animal do not have swim() 
    ((Dog)dog).swim(); 
    
  • Как начать сброс различных объектов в общем родительском классе, вы можете иметь трудное время, пытаясь выяснить, какие члены принадлежит к какому классу.

    (Cat(cat)).swim(); //error, class Cat do not have swim()