Спецификаторы доступа к полям класса
   
Зададимся вопросом: "Когда объявлять данные общими (Public), когда - частными (Private), а когда защищенными (Protected, если эта возможность поддерживается компилятором)?"

Прежде, чем высказать свою точку зрения на этот вопрос, я хотел бы напомнить, что означает каждый из перечисленных методов доступа:
  1. Public (общий доступ) - поля и методы, описанные в этой секции становятся доступны вне модуля, в котором описан сам класс (объект)

    По умолчанию подразумевается именно этот метод доступа, так что если метод не указан, то поля/метода будут именно общими...

  2. Private (частный доступ) - поля и методы из этой секции доступны только из того модуля, где описывается сам класс (объект). Извне они невидимы

    Внимание !!! Механизм доступа к полям/методам реализован на уровне модулей !!! Поэтому будет ошибкой считать, что
      type
        T = object
        private
          X: integer;
        end;
      var obj: T;
      begin
        obj.X := 10;    { <--- Здесь ...       }
        writeln(obj.X); { <--- ... или вот тут }
      end.
    внешний код не получит доступа к "частному" полю X... Доступ получен, и приведенная выше программа прекрасно работает. А вот если вынести описание типа T в отдельный модуль, и попытаться из другого модуля обратиться к T.X, то произойдет ошибка.

  3. Protected (защищенный доступ, 32-битные компиляторы) - действует подобно частному (Private) доступу, за исключением того, что защищенные члены класса доступны из всех наследников этого класса, даже описанных в других модулях.

    (Private скрывает доступ от наследников из других модулей)
Вернемся, однако, к заданному в начале вопросу: "Когда использовать различные метода доступа к полям класса (объекта)?"

Herb Sutter утверждает, что использование полей класса с методами доступа, отличными от Private - есть зло, и я не могу с ним в этом не согласиться...

из двух вариантов написания:
  1. type
      T = object
        X, Y: integer;
        ...
      end;
  2. type
      T = object
       private
         X, Y: integer;
       public
         procedure SetX(value: integer);
         procedure SetY(value: integer);
         
         function GetX: integer;
         function GetY: integer;
         
        ...
      end;
    (для Турбо Паскаля)
    type
      T = object
      private
        _X, _Y: integer;
        procedure PutX(value: integer);
        procedure PutY(value: integer);
    
      public
    
        property X: integer read _X write PutX;
        property Y: integer read _Y write PutY;
      end;
    (для FPC)
я бы выбрал именно второй, хотя кажется, что с первым вариантом работать проще...

Почему второй? Очень просто... Объектно-ориентированное программирование основывается на принципе инкапсуляции, а что такое инкапсуляция? Это защита данных... Данные оборачиваются в защитную капсулу, предотвращающую (или, по крайней мере, делающую попытку предотвратить) их порчу... Ведь если работать с первым вариантом, то никто не помешает пользователю передать некорректные данные моему объекту, значит надо делать одно из двух:
  1. или довериться пользователю, и работать с теми данными, которые он передаст;
  2. проверять данные, введенные пользователем, на предмет "не навредят ли они моему классу?"
Перед тем, как выбрать один из пунктов, поставьте себя (да, да, именно себя - человек - тоже объект, правда?) на место объекта... Вам дают закрытую бутылку с какой-то жидкостью, и предлагают (закрыв глаза, и зажав нос) выпить ее содержимое. Будете это делать, или попробуете хотя бы с помощью обоняния/зрения определить, не принесет ли эта жидкость вреда Вашему организму? Я бы выбрал второй вариант и здесь... Что полностью соответствует второму варианту при ответе на предыдущий вопрос, и все тому же второму варианту при выборе варианта написания кода...

(продолжение следует...)



Free Web Hosting