Два программиста независимо друг от друга пишут компьютерную программу
Обращаем Ваше внимание, что в соответствии с Федеральным законом N 273-ФЗ «Об образовании в Российской Федерации» в организациях, осуществляющих образовательную деятельность, организовывается обучение и воспитание обучающихся с ОВЗ как совместно с другими обучающимися, так и в отдельных классах или группах.
Рабочие листы и материалы для учителей и воспитателей
Более 2 500 дидактических материалов для школьного и домашнего обучения
Столичный центр образовательных технологий г. Москва
Получите квалификацию учитель математики за 2 месяца
от 3 170 руб. 1900 руб.
Количество часов 300 ч. / 600 ч.
Успеть записаться со скидкой
Форма обучения дистанционная
- Онлайн
формат - Диплом
гособразца - Помощь в трудоустройстве
Видеолекции для
профессионалов
- Свидетельства для портфолио
- Вечный доступ за 120 рублей
- 311 видеолекции для каждого
Этапы решения задач на компьютере
Принципы программирования
Компьютер предназначен для решения разнообразных задач: научно-технических, инженерных, разработки системного программного обеспечения, обучения, управления производственными процессами и т.д. В процессе подготовки и решения на компьютере научно-технических задач можно выделить следующие этапы:
1. Постановка задачи — формулируется цель решения задачи, подробно описывается ее содержание; проводится анализ условий, при которых решается поставленная задача, выявляется область определения входных параметров задачи.
2. Формальное построение модели задачи — предполагает построение модели с характеристиками, адекватными оригиналу, на основе какого-либо его физического или информационного принципа; анализируется характер и сущность величин, используемых в задаче.
3. Построение математической модели задачи — характеризуется математической формализацией задачи, при которой существующие взаимосвязи между величинами выражаются с помощью математических соотношений. Как правило, математическая модель строится с определенной точностью, допущениями и ограничениями.
4. Выбор и обоснование метода решения — модель решения задачи реализуется на основе конкретных приемов и методов решения. В большинстве случаев математическое описание задачи трудно перевести на машинный язык. Выбор и использование метода решения позволяет свести решение задачи к конкретному набору машинных команд. При обосновании метода решения рассматриваются вопросы влияния различных факторов и условий на конечный результат, в том числе на точность вычислений, время решения задачи на компьютере, требуемый объем памяти и др.
5. Построение алгоритма — на данном этапе составляется алгоритм решения задачи, в соответствии с выбранным методом решения. Процесс обработки данных разбивается на отдельные относительно самостоятельные блоки, определяется последовательность выполнения этих блоков.
6. Составление программы — алгоритм решения переводится на конкретный язык программирования.
8. Решение задачи на компьютере и анализ результатов. Теперь программу можно использовать для решения поставленной задачи. Первоначально выполняется многократное решение задачи на компьютере для различных наборов исходных данных. Получаемые результаты анализируются специалистом, поставившим задачу. Разработанная программа поставляется заказчику. К ней прилагается документация, включающая инструкцию по эксплуатации. В задачах другого типа некоторые этапы могут отсутствовать.
Например, проектирование программного обеспечения не требует построения математической модели.
Программирование это процесс подготовки задач для решения их на ЭВМ, состоящий из следующих этапов:
алгоритмическое описание задачи;
запись алгоритма на языке программирования (составление программы);
трансляция программы с языка программирования на машинный язык (в виде последовательности команд, реализация которых техническими средствами ЭВМ и есть процесс решения задачи).
Основными технологиями разработки программного обеспечения являются:
Структурное программирование. Сутью структурного программирования является возможность разбиения программы на составляющие элементы.
Идеи структурного программирования появились в начале 70-годов в компании IBM, в их разработке участвовали известные ученые Э. Дейкстра, Х. Милс, Э. Кнут, С. Хоор.
Распространены две методики (стратегии) разработки программ, относящиеся к структурному программированию: программирование "сверху вниз" и программирование "снизу вверх".
Программирование "сверху вниз", или нисходящее программирование – это методика разработки программ, при которой разработка начинается с определения целей решения проблемы, после чего идет последовательная детализация, заканчивающаяся детальной программой.
При нисходящем проектировании задача анализируется с целью определения возможности разбиения ее на ряд подзадач. Затем каждая из полученных подзадач также анализируется для возможного разбиения на подзадачи. Процесс заканчивается, когда подзадачу невозможно или нецелесообразно далее разбивать на подзадачи.
В данном случае программа конструируется иерархически - сверху вниз: от главной программы к подпрограммам самого нижнего уровня, причем на каждом уровне используются только простые последовательности инструкций, циклы и условные разветвления.
Противоположной является методика программирования «снизу вверх». Программирование «снизу вверх», или восходящее программирование – это методика разработки программ, начинающаяся с разработки подпрограмм (процедур, функций), в то время когда проработка общей схемы не закончилась. Является противоположной методике программирования «сверху вниз».
Такая методика является менее предпочтительной по сравнению с нисходящим программированием, так как часто приводит к нежелательным результатам, переделкам и увеличению времени разработки.
Достоинства структурного программирования:
повышается надежность программ (благодаря хорошему структурированию при проектировании, программа легко поддается тестированию и не создает проблем при отладке);
повышается эффективность программ (структурирование программы позволяет легко находить и корректировать ошибки, а отдельные подпрограммы можно переделывать (модифицировать) независимо от других);
уменьшается время и стоимость программной разработки;
улучшается читабельность программ.
Модульное программирование - это организация программы как совокупности небольших независимых блоков (модулей), структура и поведение которых подчиняется определенным заранее правилам.
Модулем (в модульном программировании) называется множество взаимосвязанных подпрограмм (процедур) вместе с данными, которые эти подпрограммы обрабатывают. Единственное различие между маленькой модульной программой и большой модульной программой заключается в количестве модулей, из которых они состоят. Поскольку модули не зависят друг от друга, создание большой модульной программы не очень отличается от написания многих маленьких независимых модульных программ, хотя взаимодействие между модулями может быть весьма сложным. Работа над большой цельной программой напоминает одновременную работу со множеством маленьких взаимосвязанных программ. Кроме того, модульность позволяет применить командный способ программирования, при котором несколько программистов работают независимо друг от друга, а затем объединяют свои модули в одну программу.
Модульное программирование предназначено для разработки больших программ. Разработкой больших программ занимается коллектив программистов. Каждому программисту поручается разработка некоторой самостоятельной части программы. И он в таком случае отвечает за конструирование всех необходимых процедур и данных для этих процедур. Сокрытие данных (запрет доступа к данным из-за пределов модуля) предотвращает их случайное изменение и соответственно нарушение работы программы. Для взаимодействия отдельных частей (модулей) программы коллективу программистов необходимо продумать только интерфейс (взаимодействие) сконструированных модулей в основной программе.
Отладка большой программы может оказаться практически невыполнимой задачей.
Большое преимущество модульного подхода заключается в том, что задача отладки большой программы сводится к отладке множества маленьких подпрограмм. Начиная кодировать модуль, вы должны быть уверены, что все остальные модули закодированы правильно. Следовательно, закончив программирование модуля, вы должны внимательно проверить его, как отдельно, так и вместе с другими модулями, вызывая его с фактическими аргументами, тщательно подобранными для выявления всех возможных недостатков. Если это тестирование проведено подобающим образом, можно быть уверенным, что любая обнаруженная ошибка содержится только в модуле, который кодировался последним. Модульность позволяет изолировать ошибки.
Модульный подход не только позволяет программистам справляться со сложностями, возникающими при решении задачи, но и помогает читателям программы понять, как она работает. Модульную программу легко отследить, поскольку читатель хорошо представляет себе, что происходит, не вдаваясь в детали кода. Для того чтобы разобраться в хорошо написанной функции, достаточно лишь прочитать ее имя, начальные комментарии и имена функций, которые вызываются внутри нее.
Модифицируемость программы тесно связана с модульностью программы. Небольшое изменение в требованиях, предъявляемых к программе, должно приводить к небольшому изменению ее кода. Если это не так, значит, программа плохо написана и, в частности, не обладает свойством модульности. Чтобы учесть небольшие изменения в исходных требованиях, в модульной программе обычно достаточно изменить лишь несколько модулей, особенно если модули не зависят друг от друга и каждый модуль выполняет отдельную точно поставленную задачу.
Вносить изменения в программу нужно постепенно. При модульном подходе большие изменения разбиваются на множество маленьких и относительно простых модификаций в изолированных частях программы. Модульность позволяет изолировать модификации.
Другое преимущество модульного подхода проявляется в выявлении вычислений, которые в программе выполняются несколько раз. Такие вычисления следует реализовывать в виде функций. В этом случае код, предназначенный для таких вычислений, в программе встречается только один раз, повышая ее читабельность и модифицируемость.
В компьютере одновременно работают две независимые программы.
Вероятность того что первая программа даст сбой 0, 3, а вторая 0, 4.
Найти вероятность того что хотя бы одна программа даст сбой.
Мне кажется так : 1)0, 3 + 0, 4 = 0, 7
К программы 2, то вероятность того что одна даст сбои равняется : 2)0, 7 / 2 = 0, 35.
Два программиста пишут компьютерные программы ?
Два программиста пишут компьютерные программы .
Вероятность того, что программа, составленная первым программистом, будет работать, равна 0, 5 ; вторым 0, 7.
Сформулируйте 4 вопроса о вычисление вероятности по заданному условию и решите задачу.
Задача на вероятность :Студент знает 20 из 27 вопросов программы?
Задача на вероятность :
Студент знает 20 из 27 вопросов программы.
Найти вероятность того, что студент знает 3 вопроса, предложенные ему экзаменатором.
Вероятность попадания у первого баскетболиста 0?
Вероятность попадания у первого баскетболиста 0.
8, а у второго 0.
6. Найти вероятность, что после бросков по одному разу попадет хотя бы один.
Для сигнализации о возгорании установлены два независимо работающих датчика?
Для сигнализации о возгорании установлены два независимо работающих датчика.
Вероятности того, что при возгорании датчик сработает, для первого и второго датчика соответственно равны 0, 6 и 0, 7.
Найти вероятность того что сработает хотя бы один датчик и вероятность того, что сработает ровно один датчик.
В мастерской работают два мотора независимо от друг друга?
В мастерской работают два мотора независимо от друг друга.
Вероятность того, что первый мотору потребуется ремонт равно 0, 8 а второму 0, 7.
Найти вероятность того, что в течении дня ни один мотор не потребует ремонта, хотя бы один мотор потребует ремонта.
5. Вероятность хотя бы одного попадания при двух выстрелах (выстрелы независимые) равна 0, 96?
5. Вероятность хотя бы одного попадания при двух выстрелах (выстрелы независимые) равна 0, 96.
Найти вероятность трех попаданий при четырех выстрелах?
Студент пришел на экзамен, зная лишь 24 из 32 вопросов программы?
Студент пришел на экзамен, зная лишь 24 из 32 вопросов программы.
Экзаменатор задал ему 3 вопроса.
Найти вероятность того, что студент ответит правильно хотя бы на один вопрос.
В дисплейном классе имеется 10 персональных компьютеров первого типа и 8 второго типа?
В дисплейном классе имеется 10 персональных компьютеров первого типа и 8 второго типа.
Вероятность того, что за время работы на компьютере первого типа не произойдет сбоя, равна 0, 8 , а на компьютере второго типа 0, 75.
Найти вероятность того, что компьютер, во время работы которого не произошёл сбой - первого типа.
Испытываются четыре независимо работающих компьютера?
Испытываются четыре независимо работающих компьютера.
Вероятность выхода из строя каждого компьютера равна 0, 64.
Какова вероятность того, что при испытании выйдут из строя : а) два компьютера б) не более чем два компьютера?
Испытываются четыре независимо работающих одинаковых компьютера?
Испытываются четыре независимо работающих одинаковых компьютера.
Вероятность выхода из строя каждого компьютера равна 0, 64.
Какова вероятность того, что при испытании выйдут из строя : а) Два компьютера б) Не более чем два компьютера?
Если вам необходимо получить ответ на вопрос В компьютере одновременно работают две независимые программы?, относящийся к уровню подготовки учащихся 10 - 11 классов, вы открыли нужную страницу. В категории Математика вы также найдете ответы на похожие вопросы по интересующей теме, с помощью автоматического «умного» поиска. Если после ознакомления со всеми вариантами ответа у вас остались сомнения, или полученная информация не полностью освещает тематику, создайте свой вопрос с помощью кнопки, которая находится вверху страницы, или обсудите вопрос с посетителями этой страницы.
Если ты имеешь виду ответ на вопрос в учебнике то тебе нужно его уточнить, а есл ты имеешь в виду написать ответ на вопрос в этом приложении то тебе нужно просто нажать на кнопку "ответ".
1)2, 2х * 5 = 22 * 3, 5 11х = 77 х = 7 2)9 * 7 = 6, 3х * 5 63 = 31, 5х х = 2 3)21 * 1, 9 = 9, 5 * 0, 7х 39, 9 = 6, 65х х = 6 4)3, 4 * 4, 5 = 17х * 9 15, 3 = 153х х = 0, 1 5)7, 2 * 3, 9 = 1, 17х * 8 28, 08 = 9, 36х х = 3 6)1, 5х * 8 = 9 * 4 12х = 36 х..
1) 2, 2x * 5 = 22 * 3, 5 11x = 77 x = 77 : 11 x = 7 2) 6, 3x * 5 = 9 * 7 31, 5x = 63 x = 63 : 31, 5 x = 2 3) 0, 7x * 9, 5 = 21 * 1, 9 6, 65x = 39, 9 x = 39, 9 : 6, 65 x = 6 4) 17x * 9 = 4, 5 * 3, 4 153x = 15, 3 x = 15, 3 : 153 x = 0, 1 5) 1, 17x * 8 ..
X + 3x + 5x = 81 минута 9x = 81 Х = 9 3х - средняя свеча = 3 * 9 = 27минут.
Итс хорошо да эьют наес.
Масса 7 дынь = количество * массу 1 дыни = 7 * 5кг = 35 кг Ответ : 35кг.
∠A + ∠B + ∠D = 252° ∠A = ? ∠A + ∠B = 180° - по свойству углов параллелограмма ∠A + ∠B + ∠D = 252°⇒180° + ∠D = 252° ∠D = 252° - 180° ∠D = 72° ∠D = ∠B = 72° - по свойству углов параллелограмма ∠A + ∠B = 180°⇒∠A + 72° = 180° ∠A = 180° - 72° ∠A = 108°.
А)z1 = 2 - 5i z2 = 3 + 4i - - - при сложении - вычитании просто приводим подобные члены - реальную часть к реальной, мнимую к мнимой Z1 + Z2 = 2 - 5i + 3 + 4i = (2 + 3) + ( - 5 + 4)i = 5 - i Z1 - Z2 = 2 - 5i - (3 + 4i) = (2 - 3) + ( - 5 - 4)i = - 1 -..
Это 0, 1, 2, 3, 4, 5 вот так.
Бананы - 18 по 40 рубГруш - 7 по 47 руб1) 18 * 40 = 720 (руб) - бананы2) 7 * 47 = 329 (руб) - груш3) 720 + 329 = 1049 (руб)Ответ : 1049 рублей.
© 2000-2022. При полном или частичном использовании материалов ссылка обязательна. 16+
Сайт защищён технологией reCAPTCHA, к которой применяются Политика конфиденциальности и Условия использования от Google.
Вероятность того, что программа, составленная первым программистом, будет работать, равна 0, 5 ; вторым 0, 7.
Сформулируйте 4 вопроса о вычисление вероятности по заданному условию и решите задачу.
1)какая разница в вероятностях?
2)Какая вероятность, что программа будет работать если они составят её вместе?
3)Сколько процентов составляет вероятность первого программиста?
4)Сколько процентов составляет вероятность второго программиста?
По данному чертежу сформулируй условие задачи на кратное сравнение?
По данному чертежу сформулируй условие задачи на кратное сравнение?
Реши составленную задачу.
Вычисли и запиши ответ.
Кто написал первую программу для вычисления чисел?
Кто написал первую программу для вычисления чисел?
1. Компьютерная система содержит 50 одинаковых микрочипов?
1. Компьютерная система содержит 50 одинаковых микрочипов.
Вероятность того, что любой микрочип будет работать в заданное время, равна 0, 9.
Для выполнения некоторой операции требуется, чтобы, по крайней мере, 30 микрочипов было в рабочем состоянии.
А) Чему равна вероятность того, что операция будет выполнена успешно?
Б) Чему равна вероятность того, что будут работать 47 микрочипов?
Помогите решить задачу пж?
Помогите решить задачу пж.
Два студента при подготовке к зачету выучили соответственно : первый - 20 из 30 вопросов программы, второй - 25 из 30 вопросов программы.
Для сдачи зачета необходимо ответить на 2 случайно выбранных вопроса.
Имея эту информацию определить вероятности следующих событий : а) оба студента сдадут зачет ; б) или первый или второй студенты сдадут зачет ; в) только один студент сдаст зачет ; г) ни один студент не сдаст зачет.
Задача на вероятность :Студент знает 20 из 27 вопросов программы?
Задача на вероятность :
Студент знает 20 из 27 вопросов программы.
Найти вероятность того, что студент знает 3 вопроса, предложенные ему экзаменатором.
За два месяца программист настроил 216 компьютеров в первый месяц он работал 28 дней, а во второй 26 дней?
За два месяца программист настроил 216 компьютеров в первый месяц он работал 28 дней, а во второй 26 дней.
Сколько компьютеров настраивал программист каждый месяц.
Задача на вероятность ?
Задача на вероятность .
Рабочий обслуживает 2 станка.
Вероятность того, что первый отработает без поломок равна 0, 8 , а что второй = 0, 7 .
Найти вероятность , что оба станка отработают без поломок .
Студент пришел на экзамен, зная лишь 24 из 32 вопросов программы?
Студент пришел на экзамен, зная лишь 24 из 32 вопросов программы.
Экзаменатор задал ему 3 вопроса.
Найти вероятность того, что студент ответит правильно хотя бы на один вопрос.
В билете три задачи?
В билете три задачи.
Вероятность правильного решения первой задачи равна 0, 9, второй – 0, 6, третьей – 0, 8.
Найти вероятность того, что студент правильно решит : а) только одну задачу ; б) хотя бы одну задачу.
В компьютере одновременно работают две независимые программы?
В компьютере одновременно работают две независимые программы.
Вероятность того что первая программа даст сбой 0, 3, а вторая 0, 4.
Найти вероятность того что хотя бы одна программа даст сбой.
На этой странице сайта, в категории Математика размещен ответ на вопрос Два программиста пишут компьютерные программы ?. По уровню сложности вопрос рассчитан на учащихся 5 - 9 классов. Чтобы получить дополнительную информацию по интересующей теме, воспользуйтесь автоматическим поиском в этой же категории, чтобы ознакомиться с ответами на похожие вопросы. В верхней части страницы расположена кнопка, с помощью которой можно сформулировать новый вопрос, который наиболее полно отвечает критериям поиска. Удобный интерфейс позволяет обсудить интересующую тему с посетителями в комментариях.
Если ты имеешь виду ответ на вопрос в учебнике то тебе нужно его уточнить, а есл ты имеешь в виду написать ответ на вопрос в этом приложении то тебе нужно просто нажать на кнопку "ответ".
1)2, 2х * 5 = 22 * 3, 5 11х = 77 х = 7 2)9 * 7 = 6, 3х * 5 63 = 31, 5х х = 2 3)21 * 1, 9 = 9, 5 * 0, 7х 39, 9 = 6, 65х х = 6 4)3, 4 * 4, 5 = 17х * 9 15, 3 = 153х х = 0, 1 5)7, 2 * 3, 9 = 1, 17х * 8 28, 08 = 9, 36х х = 3 6)1, 5х * 8 = 9 * 4 12х = 36 х..
1) 2, 2x * 5 = 22 * 3, 5 11x = 77 x = 77 : 11 x = 7 2) 6, 3x * 5 = 9 * 7 31, 5x = 63 x = 63 : 31, 5 x = 2 3) 0, 7x * 9, 5 = 21 * 1, 9 6, 65x = 39, 9 x = 39, 9 : 6, 65 x = 6 4) 17x * 9 = 4, 5 * 3, 4 153x = 15, 3 x = 15, 3 : 153 x = 0, 1 5) 1, 17x * 8 ..
X + 3x + 5x = 81 минута 9x = 81 Х = 9 3х - средняя свеча = 3 * 9 = 27минут.
Итс хорошо да эьют наес.
Масса 7 дынь = количество * массу 1 дыни = 7 * 5кг = 35 кг Ответ : 35кг.
∠A + ∠B + ∠D = 252° ∠A = ? ∠A + ∠B = 180° - по свойству углов параллелограмма ∠A + ∠B + ∠D = 252°⇒180° + ∠D = 252° ∠D = 252° - 180° ∠D = 72° ∠D = ∠B = 72° - по свойству углов параллелограмма ∠A + ∠B = 180°⇒∠A + 72° = 180° ∠A = 180° - 72° ∠A = 108°.
А)z1 = 2 - 5i z2 = 3 + 4i - - - при сложении - вычитании просто приводим подобные члены - реальную часть к реальной, мнимую к мнимой Z1 + Z2 = 2 - 5i + 3 + 4i = (2 + 3) + ( - 5 + 4)i = 5 - i Z1 - Z2 = 2 - 5i - (3 + 4i) = (2 - 3) + ( - 5 - 4)i = - 1 -..
Это 0, 1, 2, 3, 4, 5 вот так.
Бананы - 18 по 40 рубГруш - 7 по 47 руб1) 18 * 40 = 720 (руб) - бананы2) 7 * 47 = 329 (руб) - груш3) 720 + 329 = 1049 (руб)Ответ : 1049 рублей.
© 2000-2022. При полном или частичном использовании материалов ссылка обязательна. 16+
Сайт защищён технологией reCAPTCHA, к которой применяются Политика конфиденциальности и Условия использования от Google.
Разбор решения задачи
Эта задач очень похожа на другую, разобранную нами в качестве примера на тему «Динамическое программирование».
На этот раз от нас требуют найти минимальную стоимость прохождения по платформам. При этом есть добраться до любой платформы можно двумя способами:
Тут f(n) — минимальная стоимость попадания на платформу с номером n , d(a, b) — расстояние между платформами a и b .
Видно, что для вычисления f(n) нам нужно вычислить f(n-1) и f(n-2) , попробуем сделать это рекурсивно:
Мы начинаем с последней платформы — f(n) , нам нужны f(n-1) и f(n-2) . Они вычисляются рекурсивно:
Это очень простое решение и оно прекрасно работает для небольшого числа платформ. В самом деле, обратите внимание, что f(n-2), f(n-3) и все остальные значения платформ нам потребуются дважды. Однако, каждое обращение к ним будет приводить к вызову функции и объемным вычислениям.
На картинке показаны зависимости по данным для платформ с номерами k+1 , k+2 и k+3 . Dидно, что процесс поиска по-сути линейный, однако наша функция каждый раз производит вычисления заново, т.е. работает примерно так:
Она работает не в 2 раза медленее, а примерно в 2^n — обратите внимание, что f(k) для обработки трех последних платформ будет вызван уже трижды.
Мы можем запрограммировать линейную схему, показанную на первом рисунке. Для этого нам нужно сохранить промежуточные результаты — минимальную стоимость для уже обработанных платформ. Для этого заведем структуру платформы, которая, помимо высоты, будет содержать минимальное количество энергии и флаг готовности:
В этом и заключается суть динамического программирования — вместо повторного вычисления мы проверяем «было ли это вычисленно раньше» и «если да» — берем готовые данные:
Однако, если мы пришли к линейному процессу вычисления, то зачем нам рекурсия? — Мы вполне можем обойтись циклом если будем обрабатывать не с последней платформы, а с первой. То есть, мы знаем, что стоимость попадания на первую платформу равна нулю, на вторую мы можем попасть только одним способом. Для третьей платформы — нам потребуются данные (уже готовые) от первух двух платформ:
Последние два решения являются наиболее хорошими с точки зрения чистоты кода — алгоритм хорошо читается. Однако, мы можем уменьшить объем потребляемой памяти. Посмотрите еще раз на рисунок — для обработки i-той платформы нужны данные только двух предыдущих, а не всех, значит и хранить достаточно только два последних числа (вместо n):
Это решение тоже можно улучшить по памяти — в самом деле, зачем нам хранить информацию о высотах всех платформ, когда нужны лишь две последние?
Почти все популярные языки программирования являются объектно-ориентированными. В таблице приведены данные о популярности языков (рейтинг TIOBE) за сентябрь 2019 года [1]:
Не являются объектно-ориентированными лишь 20% — это языки программирования аппаратуры (Си, Assembly language), декларативный язык программирования баз данных (SQL) и визуальный язык MATLAB. Не удивительно, что почти в каждом описании вакансии программиста требуется что-то типа «Понимание ООП» или «Понимание принципов SOLID» [2] (что очень близко).
ООП строится лишь на паре ключевых слов и синтаксических конструкций. Однако, понять ООП сложно уже потому, что его очень часто неправильно преподают в ВУЗах — об этом, в частности, можно прочитать там [3]. Еще сложнее правильно пользоваться объектно-ориентированным программированием — помимо синтаксических конструкций оно подразумевает ряд принципов, призванных решить проблемы и обеспечить ценности.
В этой статье-учебнике:
-
развития языков программирования, объясняющие существующую систему ценностей;
- на примерах показаны механизмы ООП и их роль в обеспечении ценностей;
- приведены аннотации на материалы для дальнейшего изучения.
Для освоения материала, читатель должен иметь базовые навыки программирования на любом языке программирования и практику (хотя бы неудачную) применения классов.
1 Тенденции и ценности
Синтаксические конструкции языков программирования (в том числе, связанные с ООП) появились не случайно — любая из них была призвана решить определенные проблемы.
1.1 Повышение уровня абстракции. Инкапсуляция
— Программа исполняется на процессоре, имеющем ограниченный набор регистров, нужно ли нам беспокоиться о том, как переменные программы будут распределяться по этим регистрам в процессе выполнения?
— Нужно ли нам думать о том, как на низком уровне происходит передача параметров в функцию и возвращается значение?
Примерами абстракций для программиста являются процессор (черный ящик, который умеет выполнять программу), отдельная синтаксическая конструкция (нас редко интересует как «внутри» реализовано ветвление или механизм исключений), функция, … класс.
Абстракция является ценностью. Одни абстракции реализовали за нас разработчики языков программирования, операционных систем и библиотек, а другие — должны реализовывать мы сами в процессе разработки программы. Введенные в ООП конструкции, при правильном использовании, должны обеспечивать построение хороших абстракций.
Пример хорошей абстрации приведен в докладе «Память – идеальная абстракция» с конференции С++ Russia 2018 [4]:
Любой программист на С++ знает, что в этих строчках по указателю выделяется память под объект целого типа, в эту память пишется число 42, а затем — память освобождается. Из доклада мы можем узнать, что внутри оператор new устроен совсем не так просто (за 40 минут мы узнаем о 9 структурах данных, обеспечивающих работу этого оператора, включая кэш страниц процессора).
Множество хороших абстракций предоставляет нам операционная система и библиотеки. Открывая файл мы не задумываемся о файловых системах (FAT/NTFS), создавая поток (thread) — о размещении его в памяти и т.д.
Говоря о том, что оператор new , файл, сокет или поток является хорошей абстракцией мы имеет ввиду, что он обеспечивает хорошую инкапсуляцию.
Инкапсуляция — это сокрытие данных о реализации. В ООП под этим часто имеют ввиду объединение данных и кода в классе, однако сам факт такого объединения не гарантирует хорошей инкапсуляции, кроме того — хорошей инкапсуляции можно достичь и другими методами. В частности, абстракции операционной сиситемы не являются классами.
Итак: абстракция является ценностью в программировании, а инкапсуляция — методом достижения этой ценности. Нужно стремиться создавать такие же хорошие абстракции, как оператор new , полностью скрывающие детали реализации от обычного программиста.
1.2 Безопасность и расширяемость
При программировании на безопасном языке программирования (не Си и ассемблер) сложно отстрелить себе ногу. Функция безопасна если ее сложно использовать неправильным образом — это также справедливо для модулей и классов. Возможность расширения (доработки) вашего собственного кода напрямую связаны с его безопасностью.
Безопасность осуществляется за счет предоставления хороших абстракций. В качестве примера давайте сравним функцию создания окна, предоставляемую Windows API и библиотекой Qt:
void CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
Функцию CreateWindowA очень сложно использовать (от нас требуют 11 параметров), при этом легко допустить ошибку, например:
- lpClassName — строка с нулевым символом в конце или целочисленный атом, заранее созданный обращением к функции GlobalAddAtom. Если передать неправильную строку или некорректное число — программа будет вести себя непредасказуемо.
- hMenu и hInstance являются идентификаторами (тип int), которые должны быть заранее созданы. Легко выстрелить себе в ногу передав неправильный идентификатор;
QWidget::QWidget(QWidget *parent, Qt::WindowFlags f);
Худшее, что можно сделать с классом QWidget — передать ему нулевой указатель, при этом программа будет нормально работать, но если виджет создавался на куче (оператором new ) — то он не будет автоматически уничтожен при уничтожении родительского виджета. Это не так критично, как неопределенное поведение. Итог — виджеты библиотеки Qt являютсяы хорошей и относительно безопасной абстракцией.
1.3 Ослабление зависимостей — повторное использование и тестируемость
Вы прониклись описанными выше идеями и, в процессе работы над некоторым проектом, создали нечто хорошее — удобную и безопасную библиотеку функций или такой же хороший элемент пользовательского интерфейса (виджет). Ценность вашей работы будет значительно выше если эту библиотеку или виджет можно будет легко применить в других проектах — это и называется «повторным использованием». Очевидно, без особых усилий «вырвать» отдельный компонент из нашего проекта не получится если он использует другие компоненты, т.е. зависит от них. Лучший случай — это полное отсутствие зависимостей от других компонент, однако такое встречается редко.
Каждый язык программирования предоставляет программисту некоторый набор доступных отношений (зависимостей), в процессе разработки нужно задумываться об их «силе» и по возможности использовать наиболее слабые. Закончив читать статью, обратие внимание на принцип инверсии зависимостей [2], который не только декларирует «не должно существовать прямых зависимостей между конкретными модулями», но и предлагает пути решения проблемы.
Для тестирования функции нам скорее всего придется проверить все комбинации ее входных аргументов — если функция принимает N аргументов логического типа, нам потребуется \(2^N\) тестовых наборов данных (для любых других типов входных параметров ситуация гораздо хуже). Функция является компонентом и зависит от своих аргументов; очевидно, что затраты на тестирование резко возврастают при увеличении числа зависимостей. Это справедливо и для других видов компонент — модулей и классов.
2 Механизмы
2.1 Модульность
Проектирование программного обеспечения — это о декомпозиции. Взявшись решать более или менее сложную задачу, нельзя сразу приступать к написанию кода, нужно постараться разделить эту задачу на части (выполнить декомпозицию). Обычно сделать это можно различными способами — вам нужно выбрать наилучший, исходя из приведенных выше критериев. Для решения каждой позадачи в вашей программе должен быть создан модуль:
- предоставляющий удобный интерфейс, максимально скрывающий (инкапсулирующий) детали реализации;
- максимально независимый от других модулей. Позволяющий повторное использование (по возможности).
Модульность является базовым принципом в программировании (не является особенностью ООП).
Модульное программирование — это организация программы как совокупности небольших независимых блоков …, структура и поведение которых подчиняются определённым правилам (Википедия)
Почти во всех языках программирования, в том или ином виде, поддерживаются специальные механизмы модулей или пакетов (Java, Python, Паскаль, С++20). Модуль представляет собой набор типов данных и функций, часть из которых экспортируется — доступна другим модулям.
Класс является центральной частью объектно-ориентированного подхода, при этом — он, по сути, задает отдельный модуль в вашей программе. Класс задает пространство имен (считай, имя модуля), в котором объединяются структуры данных и функции. Все содержимое класса обычно делится на секции:
- public — аналогична секции export модулей, описывает часть класса, доступную всем остальным компонентам;
- protected — содержимое секции доступно классам-наследникам (рассмотрено ниже);
- private — в нее помещаются детали реализации класса (функции и стуктуры данных, недоступные извне).
Видим, что классы расширяют классический механизм модулей секцией protected , что улучшает инкапсуляцию — подумайте «почему?».
2.2 Композиция и наследование
Между модулями программы можно организовать отношение «включения» (композиции):
- вы делаете окошко авторизации — оно включает в себя два поля ввода и одну кнопку. Эти элементы управления должны создаваться в функции какого-то модуля и где-то обрабатываться;
- вы пишите программу для рисования (аналог MS Paint) — помимо прочего, в ней должен быть модуль открытия файла с картинкой, который включает в себя модуль работы с файлами и модуль, выполняющий «разбор» данных изображения, в соответствии с форматом (png/jpg).
В обоих случаях между модулями появляется отношение включения, отражающее отношение «реализуется посредством«.
Объектно-ориентированное программирование предложило дополнительный вид отношений между модулями — наследование. Очень подробно этот механизм рассматривается Б. Мейером — он выделяет 12 видов наследования [5], однако, на практике чаще всего применяют наследование, реализующее отношения «является» (is-a, открытое наследование) … [6]. Мак-Колм рассматривает наследование как базовый шаблон проектирования, при этом имеет ввиду is-a-наследование [7].
Принцип подстановки (LSP) изначально сформулирован Барбарой Лисков и регламентирует правильное использование механизма наследования. Выделяются некоторый базовый тип и его подтип (класс-наследник). Согласно LSP, программы должны быть написаны таким образом, чтобы в любом месте вместо базового типа мог быть подставлен подтип. Это означает, что классы наследники должны реализовывать интерфейс согласованно с интерфейсом базового класса. [2]
При выборе отношений между своими классами можно руководствоваться следующим базовым правилом:
- если один класс реализует свои функции за счет использования функций другого — применяйте отношение включения;
- если же класс является разновидностью другого — применяйте открытое наследование.
Нужно учитывать, что наследование обеспечивает лучшую инкапсуляцию (за счет секции protected ), однако является более сильным видом отношения, т.к. такая зависимость устанавливается при компиляции и ее нельзя изменить, в то время как зависимость по включению одного класса может быть заменено на зависимость от другого (см. композиция и аргегация [8]).
2.3 Полиморфизм
Вы пишите компьютерную игру в жанре RPG — в ней будут строения и юниты, при этом некоторые строения должны уметь «производить» юнитов. Пусть, у нас будет казарма, не простая, а двух типов — 18 и 19 века. Казарма производит воинов — тоже 18 и 19 века. Воин должен уметь ударять другого воина (сила зависит от его типа).
Без использования полиморфизма можно накидать примерно такой код:
Автор этого кода, наверное, попытался выделить сущности и как-то увязать их друг с другом. Базовый класс Unit хранит количество здоровья, тут правильно используется наследование — ведь все воины являются юнитами.
При увеличении количества воинов, которые могут бить друг друга мы получим резкий рост числа функций hit — для 10 типов воинов нам придется написать 100 функций. В самом деле, функции hit достаточно знать, что у поступившего на вход аргумента есть поле health . Объектно-ориентированные языки программирования позволяют выполнить преобразование конкретного класса к типу базового класса.
На вход функции hit , под видом указателя на базовый класс, могут поступать любые Unit-ы (наследники), но это еще не совсем полиморфизм. Используется наш код так:
В этом примере будет вызвана функция Unit18::hit и это известно уже в момент компиляции программы. Однако, если юзер выберет мышью нашего юнита и скажет кого-то ударить — то нельзя заранее сказать какая функция должна сработать. Выбор функции теперь зависит от типа объекта, выбранного пользователем в момент выполнения программы. Именно такого рода проблему призван решить механизм полиморфизма.
Полиморфизм — способность программы выбирать различные реализации, при вызове операций с одним и тем же названием.
Мы хотим прописать интерфейс (набор функций) для базового класса и по-разному реализовать его в классах-наследниках. Мы уже знаем, что любой объект (например, выбранный пользователем с помощью мыши) мы можем привести к типу базового класса. Полиморфизм позволяет нам вызвать для нашего объекта функцию, определенную в этом интерфейсе, да так, что выполнится функция в соответствии с реальным типом объекта. То есть:
В этом примере компилятор знает, что переменная barracks имеет тип Barracks , который должен предоставлять функцию build . Выбор реального типа казармы зависит от ключа key — его, например, может вводить пользователь. Если пользователь ввел 18 — то должна быть вызвана функция Unit18::hit .
Для реализации такого поведения в процедурных языках (типа Си и Паскаля) применяли указатели на функции и страшные switch -и, объектно-ориентированный подход предлагает более красивое решение — механизм виртуальных функций.
Полиморфизм = наследование + виртуальные функции.
В итоге мы выделили интерфейс класса казармы, через который и будет работать с нашими объектами пользователь — основной код теперь зависит только от интерфейсов. Обратите внимание, что поле health класса Unit теперь можно поместить в секцию protected — доступ к нему получат только классы наследники (улучшилась инкапсуляция). Соответствующая диаграмма классов:
Читайте также: