Замечания о защищенных данных



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

 

Защищенные элементы данных порождают две главных проблемы. Первая  связана с тем, что объекту производного класса не требуется вызывать элемент-функцию, чтобы установить значение защищенного элемента данных базового класса. Следовательно, объект производного класса легко присвоить защищенному элементу недействительное значение, оставив объект в несогласованном состоянии. Например, если элемент grossSales класса CommissionEmployee защищенный, объект производного класса (например, BasePlusCommissionEmployee) может присвоить ему отрицательное значение. Вторая проблема с защищенными элементами состоит в том, что элемент-функции производного класса с большей вероятностью окажутся зависимыми от реализации базового класса. Производные классы должны фактически зависеть только от услуг базового

класса (т.е. его открытых элемент-функций), но не от его реализации. В случае защищенных элементов данных в базовом классе при изменении его реализации может потребоваться модифицировать все классы, производные от этого базового класса. Например, если по какой-то причине мы поменяем имена элементов данных firstName и lastName на first и last, то мы должны будем сделать это везде, где производный класс непосредственно ссылается на эти элементы базового класса. В таких случаях говорят, что программный код является хрупким, так как небольшое изменение в базовом классе «сломает» реализацию производного класса. Программист должен иметь возможность менять реализацию базового класса, предоставляя в то же время производным классам те же услуги. 

 

Иерархия наследования CommissionEmployee — BasePlusCommissionEmployee с закрытыми данными

Пример 5

Теперь мы еще раз пересмотрим нашу иерархию, подойдя к ней с позиций наилучшего стиля конструирования программного обеспечения. Класс CommissionEmployee теперь снова определяет элементы данных first Name, lastName, socialSecurityNumber, grossSales и commissionRate как private, предусматривая для манипуляции их значениями открытые элемент-функции setFirstName, getFirstName, setLastName, getLastName, setSocialSecurityNumber, getSocialSecurityNumber, setGrossSales, getGrossSales, setCommissionRate, getCommissionRate, earnings и print, если мы решим поменять имена элементов данных, определения earnings и print не потребуют модификации; модифицировать придется только определения set- и gеt-функций, непосредственно манипулирующих элементами данных. Заметьте, что эти изменения происходят исключительно в базовом классе — производные классы модифицировать не требуется. Подобная локализация эффектов изменений является правильным стилем конструирования программного обеспечения. Производный класс ВаsePlusCommissionEmployee наследует незакрытые элемент-функции CommissionEmployee и может получать через них доступ к закрытым элементам базового класса.

Обратите внимание, что в реализации конструктора класса CommissionEmployee мы используем инициализаторы элементов для установки значений элементов firstName, lastName и socialSecurityNumber. Мы показываем, что производный класс BasePlusCommissionEmployee может вызывать не-закрытые элемент-функции (setFirstName, get First Name, setLastName, getLastName, setSocialSecurityNumber и getSocialSecurityNumber) для манипуляции этими элементами данных.

В классе BasePlusCommissionEmployee (есть несколько изменений в реализации его элемент-функций отличающих его от предыдущей версии класса. Каждая из элемент-функций earnings и print для получения значения зарплаты вызывает элемент-функцию, а не обращается к baseSalary непосредственно. Это изолирует earnings и print от возможных изменений реализации элемента baseSalary. Например, если мы решим переименовать этот элемент данных или изменить его тип, изменений потребуют только функции setBaseSalary и getBaseSalary.

Функция earnings класса BasePlusCommissionEmployee переопределяет функцию earnings класса CommissionEmployee для вычисления заработка служащего с основной зарплатой и выплатой комиссионных. Версия earnings из класса BasePlusCommissionEmployee получает часть заработка служащего, относящуюся к комиссионным, вызывая функцию earnings базового класса с 

помощью выражения CommissionEmployee :: earnings() Затем функция earnings класса BasePlusCommissionEmployee прибавляет к полученному значению основную зарплату, получая общую сумму заработка служащего. Обратите внимание на синтаксис вызова переопределенной элемент-функции базового класса из производного класса — перед именем элемент-функции помещается имя базового класса с операцией разрешения области действия (::). Такой вызов соответствует правильному стилю  конструирования программ если элемент-функция объекта производит действия, необходимые другой его функции, то следует вызвать эту элемент-функцию, а не дублировать код ее тела. Вызывая в функции earnings класса BasePlusCommissionEmployee функцию earnings базового класса для расчета части заработка служащего, мы избегаем дублирования кода и проблем с его сопровождением.

Когда элемент-функция базового класса переопределяется в производном классе, функция производного класса часто вызывает функцию

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

Аналогичным образом функция print класса BasePlusCommissionEmployee переопределяет функцию print класса CommissionEmployee для вывода информации, соответствующей служащему с основной зарплатой и комиссионными. Версия класса BasePlusCommissionEmployee выводит ту информацию объекта BasePlusCommissionEmployee, что относится к комиссионным (т.е. строку "commission employee" и значения закрытых данных класса CommissionEmployee), вызывая функцию print класса CommissionEmployee по квалифицированному имени CommissionEmployee::print(). Затем print класса BasePlusCommissionEmployee выводит оставшуюся информацию объекта BasePlusCommissionEmployee (т.е. значение зарплаты).

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

 


Дата добавления: 2018-08-06; просмотров: 183; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!