Для начисления зарплаты, обычно на предприятии, на каждые 100-300 человек существует 1 бухгалтер. Казалось бы, почему бы не 1 бухгалтер на всё предприятие? Ведь зарплата, это просто рубли, которые выдаются пару раз в месяц, и то бывает не вовремя. При ближайшем рассмотрении оказывается, что на предприятии есть разные сотрудники: есть ответственные, а есть просто исполнители; есть уборщица, и есть главный инженер; есть дежурный электрик, который может дежурить в ночь, а есть приходящий сисадмин. У них у всех разная рабочая нагрузка, разная квалификация, разные условия труда (бывают и вредные производственные факторы). Всё это приводит к тому, что начисление зарплаты на самом деле далеко не такая тривиальная операция. И хорошо бы никого не обидеть, и не переплатить (это, конечно с точки зрения директора предприятия, я то не против получать зарплату побольше). [↑]
Для решения поставленной задачи надо определить тот базовый класс, который будут наследовать все наши сотрудники предприятия: от уборщицы до директора. Все имеют табельный номер, все имеют фамилию и имя (отчество уже не у всех), все имеют сумму зарплаты, все имеют какую-то квалификацию и опыт. Всё это должно быть отражено в сумме зарплаты (да-да, а иначе зачем учиться или повышать квалификацию?)
Итак, попробуем реализовать нашего абстрактного сотрудника:
В приведённом модуле реально мы будем использовать только абстрактный тип tpSotrudnik. Тип-потомок, реализованный в этом модуле лишь ещё раз демонстрирует технику работы с абстрактным классом и абстрактными методами (причём тип-потомок уже является финальныи и расширению не подлежит).
В выводе программы видно, что программа не исполнена до конца. Это всё потому, что не выполнено условие в методе AddPay:
ASSERT(sum>0);
Ключевое слово ASSERT контролирует ход выполнения программы, и гарантирует, что отрицательные суммы зачислены быть не могут. Если условие не выполнено, то программа будет прервана. И это лучше, чем программа начнёт портить всю базу данных по зарплатам. Собственно, на примере второго сотрудника именно это и видно (попытка зачислить -10 рублей). [↑]
Рабочий цеха — это самый многочисленный представитель предприятия. Логично начать писать реализауию типа именно для него. Про рабочего можно сказать, что у него есть разряд и какой-то стаж. Всё это должно непосредственно влиять на его зарплату.
Ну что же, приступим:
По тексту программы видно, что тип сотрудник_цеха наследует базовый тип сотрудник. Метод AddOtrab является новым по отношению к базовому. Он начисляет зарплату по отработанным часам, с учётом стажа работы и разряда. В данном случае, после отработки 168 часов рабочий получил 32133.02 рубля. Реализация абстрактного метода AddPay теперь не занимается начислением зарплаты, а занимается начислением премии без дополнительных условий. Третий метод OrderPay обязателен к реализации, так как этого требует абстрактный метод в базовом классе. По сути, он выполняет задуманную функцию. Вывод работы программы демнострирует новую логику работы.
Отдельно необходимо обратить внимание на то, что импорт модуля Sotrudnik выполняется вполне упешно. Его нет на диске или где-то ещё. Но он есть в памяти (если из предыдущей части пример был хоть один раз скомпилирован). При необходимости, можно посмотреть его интерфейсную часть (по нажатию правой кнопки мыши). Это позволяет второму модулю успешно скомпилироваться и работать.
Методы помечены на экспорт, так как они потребуются дальше (если нет необходимости, зачем экспортировать, и тем самым усложнять взаимодействие?). [↑]
Мастер цеха, в отличии от рабочего цеха является сотрудником с повышенной зарплатой. Тоже влияет стаж, разряд уже не так важен (по определению мастер должен быть мастером), но материальная ответственность, умение организовать рабочий процесс, распределить работы, осуществить контроль — накладывает дополнительную ответственность. Поэтому будем считать, что зарплата мастера цеха достойна надбавки 60% от рабочего цеха с 6-м разрядом. Но в отличии от прошлых примеров, не будем использовать наследование, а будем использовать способ «включает». Что, впрочем, не помешает определять свои методы для типа мастер_цеха.
Пример реализующий предлагаемый подход представлен ниже:
Модуль получился несколько короче, чем предыдущий. Содержание методов сводится к вызову методов типа tpSotrudnik_zeh из методов tpMaster_zeh. Исключение сделано только для метода AddOtrab — в нём внесены дополнительные изменения по расчёту зарплаты.
Если внимательно приглядется то метод AddOtrab содержит ошибку: он выводит не увеличенную зарплату мастера цеха, а рабочего цеха, и только после этого увеличивает зарплату. Предлагается самостоятельно скорректировать вывод программы.
Также код последнего модуля нельзя назвать красивым именно из-за способа использования кода «включает». Переделайте самостоятельно на «наследует».
Также стоит обратить внимание, что в примере модулей практически нигде не используются глобальные переменные. Нельзя сказать, что это такое же зло, как оператор GOTO, но по возможности такие переменные надо прятать, для избежания непреднамеренных программныз сбоев [↑]
Представленный многомодульный пример показывает, как на практике примерно можно организовать иерархию типов. Как постепенно наращивая функционал можно построить сложную программную систему. Тема ООП на столько обширна, что ради неё написаны многие десятки учебников. Толстых учебников! Поэтому лучшим способом овладеть качественным ООП — учиться, учиться и ещё раз учиться. (с) Ленин В. И.
На этом общее введение будет завершено и следующий раздел будет посвящён более специфическим ключевым словам Компонентного Паскаля. [↑]
[ ← Назад ] [ Вверх ↑ ] [ Далее → ]