Как объявлять переменные

Мы с коллегой обсуждали, как объявить переменные в функции.

Допустим, у вас есть класс с именем TStrings (используя Delphi для пояснения), который имеет по крайней мере один абстрактный метод и класс-потомок с именем TStringList, который, очевидно, реализует абстрактный метод, но он не вводит ничего, что вам нужно, что еще не реализовано в предок, как бы вы объявили функциональную переменную типа TStringList?

Вот два примера. Что считается лучшей практикой и почему?

procedure AddElements;
var
  aList: TStringList;
begin
  aList := TStringList.Create;
  try
    aList.Add('Apple');
    aList.Add('Pear');
  finally
    aList.free;
  end;
end;

procedure AddElementsII;
var
  aList: TStrings;
begin
  aList := TStringList.Create;
  try
    aList.Add('Apple');
    aList.Add('Pear');
  finally
    aList.free;
  end;
end;

person Gerhard Wessels    schedule 09.12.2008    source источник
comment
кто-то хочет добавить языковой тег, или он уже есть, а я просто не знаю.   -  person UnkwnTech    schedule 09.12.2008


Ответы (5)


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

person schnaader    schedule 09.12.2008

Мой голос - вторая форма - идея в том, что TStrings определяет контракт/интерфейс, и его лучше кодировать для них.

person Chris Kimpton    schedule 09.12.2008

Я бы сказал, что это зависит от того, ожидаете ли вы, что TStringList может быть изменен на что-то еще, реализующее TStrings или нет. Если вы не ожидаете, что он изменится, используйте TStringList и получите доступ к специальным функциям, которые есть только в TStringList (думаю, это не так). Если вы ожидаете, что это может измениться, объявите его как TStrings и придерживайтесь «безопасных» методов.

В данном конкретном случае я бы сказал, что это не имеет значения. Черт, вы, вероятно, могли бы изменить объявление переменной, и все равно ничего не изменилось бы. Так что используйте то, что вам больше нравится - это вопрос предпочтений.

person Vilx-    schedule 09.12.2008

Я согласен со Шнадером.

TStringList имеет больше свойств и методов, чем TStrings (который является абстрактным классом). Использование переменной TStrings запрещает использование этих членов, если вы не используете приведения типов. Но это, на мой взгляд, усугубляет ситуацию.

Вы можете использовать TStrings в качестве аргумента функции.

procedure TMyClass.MyMethod(const AList: TStrings);
begin
end;

Или как собственность. Но локальные переменные и поля более универсальны, если им объявлен их реальный тип.

person Toon Krijthe    schedule 09.12.2008

Это зависит...

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

Например:

Collection list = new ArrayList();
[loop] list.add(someItem); [end loop]

и т.д.
Почему? Это позволяет изменить реализацию (деталь в некоторых случаях: некоторые реализации лучше подходят для некоторых применений (очередь, связанный список, стек...), поэтому это может быть в основном проблемой скорости/памяти), сводя к минимуму влияние изменения.

Конечно, если вы используете методы, специфичные для реализации, вы должны быть более конкретными в объявлении.

Еще одно преимущество: когда метод ожидает параметр Collection, он может работать с более широким диапазоном входных данных, если ему нужно использовать только универсальные методы.

person PhiLho    schedule 09.12.2008