Стоит ли делать поля защищенными?

Пример кода:

unit Foo;

  TFoo = class
  protected
    FList: TList; // Lifetime is managed by constructor and destructor
  public
    property List: TList read FList;
    constructor Create;
    destructor Destroy; override;
  end;

unit Bar;

  TBar = class(TFoo)
    procedure MyMethod;
  end;

procedure TBar.MyMethod;
begin
  // Access of FList goes here
end;

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

Должен ли я сделать FList приватным и вместо этого использовать свойство для доступа к нему из TBar?

Как вы справляетесь с такими случаями? Есть ли какие-либо соображения по производительности?


person Jens Mühlenhoff    schedule 17.01.2012    source источник
comment
Это несколько связано с stackoverflow.com/questions/8281582/ , но более конкретным.   -  person Jens Mühlenhoff    schedule 17.01.2012
comment
Бесчисленное количество раз я натыкался на что-то, что облегчило бы мою работу, если бы эта вещь не была личной. Я полагаю, что многие другие сделали то же самое, поскольку я видел разработчиков, которые полностью игнорировали private и использовали protected как самую строгую область действия. +1   -  person Sertac Akyuz    schedule 17.01.2012
comment
@Sertac Чаще всего это проблема, когда вы не можете контролировать другой код. Когда вы полностью контролируете весь код, вы можете использовать private или даже strict private, а когда это становится слишком ограничивающим, вы можете ослабить ограничения по мере необходимости.   -  person David Heffernan    schedule 17.01.2012
comment
Никаких соображений производительности. Лично я склонен использовать наиболее строгий спецификатор видимости, который позволяет вашему коду работать. Это совет, когда у вас есть полный контроль над всем кодом, который использует класс. Если вы пишете компонент или библиотеку, вы должны учитывать пользователей, которые не являются вами. Это другая игра, и я не даю советов.   -  person David Heffernan    schedule 17.01.2012
comment
@ Дэвид - я думаю, что важно иметь возможность тщательно структурировать код, прежде чем вам понадобится доступ к его частям в каждом конкретном случае. Также существует вероятность того, что кто-то, не контролирующий его, может использовать его в какой-то момент.   -  person Sertac Akyuz    schedule 17.01.2012
comment
@DavidHeffernan Так что в этом случае вы бы выбрали strict protected? Классы находятся в разных подразделениях.   -  person Jens Mühlenhoff    schedule 17.01.2012
comment
Нужен ли TBar полный контроль над унаследованным FList?   -  person OnTheFly    schedule 17.01.2012
comment
Если подклассам требуется доступ, а пользователям класса — нет, используйте protected. Если вы изучите VCL, вы увидите, что это намерение. Рассмотрим конструктор Create — он общедоступен, и это потому, что подклассы могут переопределять его и наследовать от него, но предполагаемый доступ к нему предоставляется пользователям класса.   -  person John Easley    schedule 17.01.2012
comment
@ user539484 зависит от определения полного контроля. В моем случае единственное, что делает TBar, это вызывает методы и читает свойства FList.   -  person Jens Mühlenhoff    schedule 17.01.2012


Ответы (1)


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

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

Если вам не нужен внешний доступ к определенному члену класса, возможно, это просто артефакт реализации, который не соответствует фактическому использованию класса в бизнесе. Поэтому его сложность должна быть скрыта.

В этом случае, поскольку TBar наследуется от TFoo, Protected является допустимым уровнем видимости, поскольку он зарезервирован для унаследованных классов. Кроме того, поскольку TBar унаследован от TFoo, возможно, вы думаете, что он должен иметь некоторые дополнительные привилегии для внутренней работы TFoo, потому что, в конце концов, это его дочерний класс. Почему мы должны относить TBar к такому же низкому уровню доступа, как и другие классы?

Ответ зависит от того, является ли FList фактическим членом класса TFoo, поскольку мы рассматриваем то, что представляет собой модель TFoo, или это просто деталь реализации. Кроме того, какой уровень доступа требуется? Мы просто обращаемся к нему или меняем реализацию?

Я предполагаю, что вам не нужен доступ к FList, и вы не меняете реализацию, и в этом случае, даже если бы два класса были в одном и том же модуле, я бы все равно сделал FList Private вместо Protected.

Если бы вы просто обращались к члену класса из классов-потомков в том же блоке, я бы все равно оставил его закрытым.

Однако, если бы FList был чем-то, что вам нужно переопределить в TBar (вероятно, нет, поскольку это не метод), или был разработан как нечто, что унаследованные классы должны или будут переопределять, независимо от того, находится ли он в том же модуле или нет, тогда вы бы хотите сделать его защищенным.

Вам также потребуется повысить видимость до Protected, если вам нужно получить доступ к FList из классов-потомков за пределами того же модуля.

person Marcus Adams    schedule 17.01.2012
comment
Также независимо от того, сделаете ли вы поля TFoo закрытыми или защищенными, они все равно будут видны из TBar, если TBar объявлен в том же модуле. Чтобы избежать этого, в последних версиях Delphi используется strict private. В Delphi 2007, в котором нет Strict Private, переместите TBar в отдельный модуль, чтобы предотвратить неявный дружественный статус классов в том же модуле, который ObjectPascal/Delphi встроил в свою структуру ООП. - person Warren P; 17.01.2012
comment
Если бы FList был частным (и не подвергался общедоступной области), а TFoo и TBar находились в разных файлах, использовали бы вы защищенное свойство для доступа к нему из TBar? - person Jens Mühlenhoff; 17.01.2012
comment
@ Дженс, да. С Protected унаследованные классы могли получить к нему доступ из другого модуля, но при этом скрыть его от других классов. Если бы он был в том же модуле, я бы, скорее всего, оставил его закрытым, если бы я просто обращался к нему, но если бы я изменил реализацию, я бы сделал его общедоступным. - person Marcus Adams; 17.01.2012