Первыми языками программирования были императивные языки, или машинные инструкции (коды). Они состояли из двоичного кода, который различался в зависимости от машины. Набор возможных команд для таких низкоуровневых «языков» был небольшой, так как каждая машинная инструкция выполняла определенное действие (сложение, копирование машинного слова в регистре, переход к следующему участку кода). Конечно же, для удобства программисты разработали набор буквенных аналогов для этих машинных команд, и такой способ общения с машинным «железом» получил название язык ассемблера.
Вам будет интересно:Как в «Экселе» отсортировать по алфавиту данные?
Ассемблер
Язык ассемблера — это язык низкого уровня. Его реализация и особенности разнятся от машины к машине, от процессора к процессору, то есть он платформозависим. Но суть ассемблера на любой машине одна: команды ассемблера прямо соответствуют аналогичным командам машины или их последовательностям. Сложность в изучении программирования на ассемблере заключается в том, что программист вынужден изучать назначение директив языка индивидуально для каждой машины, что повышает порог вхождения при смене процессора.
Вам будет интересно:Три способа, как отправить сообщение с компьютера на WhatsApp
Самые известные реализации ассемблера:
- Borland Turbo Assembler (TASM).
- Microsoft Macro Assembler (MASM).
- Watcom Assembler (WASM).
- A86.
Языки высокого уровня
С развитием процессоров возникла необходимость в более универсальных и широко применимых инструментах для взаимодействия с компьютером. Со временем машинные коды стали очень длинны и неудобны для понимания, поэтому было решено оперировать командами, интуитивно понятными человеку, читающему и пишущему код. Первым высокоуровневым языком для ЭВМ, использовавшим такой подход, стал Фортран. Машинные команды превратились в читабельные: OPEN, CLOSE, PRINT, здесь впервые появляется блочный оператор IF и такие конструкции, как IF THEN — ELSE.
Более того, стоит отметить, что Фортран после ухода перфокарт на свалку истории стал поддерживать структурное программирование.
Структурное программирование
В 1960 — начале 1970 годов начинается развитие следующей парадигмы программирования — структурное программирование, еще один шаг к объектно-ориентированному подходу в проектировании ПО. После работы Эдгара Дейкстры «О вреде оператора goto» у разработчиков того времени приходит понимание, что работу любой программы можно описать, используя только три управляющие структуры:
- последовательность;
- ветвление;
- цикл.
Вам будет интересно:Как запускать приложения «Андроид» на компьютере: обзор программ
Оператор goto с тех пор признан избыточным. Это оператор, позволяющий перейти к любому блоку программы. И начинающим программистам порой кажется, что нет ничего проще, чем использовать оператор goto в определенных участках кода, чтобы не выдумывать очередные ветвления и циклы. Но на деле, использование данного оператора рано или поздно приводит к тому, что программа превращается в «спагетти-код». Такой код невозможно поддерживать, безболезненно модифицировать, и что самое плохое, он труден для восприятия других разработчиков, которые придут на смену автору кода. Это особенно опасно в бизнес-девелопменте, где проектируются большие базы данных на тысячи строк кода. Текучка есть всегда, и разбираться с плохим кодом тяжело, особенно вновь прибывшим в компанию программистам.
The C Programming Language
Расцвет структурного программирования неразрывно связан с языком программирования C. Этот язык был написан на языке ассемблера Деннисом Ритчи и Кеном Томпсоном и стал исходным языком при разработке операционной системы UNIX. Она стала основой для множества современных операционных систем, таких как GNU/Linux, FreeBSD, MacOS, Posix и многие другие.
Благодаря тому, что дизайн язык C близок к машинным командам, он получил широчайшее распространение, в основном в различном прикладном ПО для множества устройств, от видеокарт и операционных систем до ракет и суперкомпьютеров. А его синтаксис навсегда стал основой для многих современных языков программирования (С++, C#, Java, Objective-C).
Объектно-ориентированное программирование (ООП)
Программы продолжали усложняться, и на смену императивной парадигме приходит понимание необходимости объектно-ориентированного подхода к информационным технологиям. Вместо привычной работы с компьютером с помощью консоли появляются графические приложения. Компьютер теперь не узкоспециализированный аппарат для научных и военных расчетов, а инструмент, возможности которого простираются от автоматизации бизнеса до общения с друзьями.
Вам будет интересно:Как добавлять в автозагрузку программы в разных операционных системах Windows
Основной структурной единицей при разработке объектно-ориентированным подходом объявляется класс. Класс — это абстрактный тип данных, создаваемый программистом. Это схема, или контракт, описывающий поля и методы объектов, которые будут созданы по лекалам этого класса.
Например, человек, машина, департамент — это абстракция, значит, ее можно описать в виде класса. Иван Иванович, белая "Шкода" с номерами нн123, операционный департамент — это конкретные представители данных абстракций, то есть, говоря языком объектно-ориентированного подхода к программированию, это объекты данных классов. Задача разработчика — описать абстрактные и конкретные объекты реального мира языком ООП. Описание класса реализуется в описании его полей и методов.
Поля
Поля — это переменные, то есть величины, характеризующие работу данного класса. Например, если мы пишем класс «Машина» для компьютерной игры, мы можем определить для него следующие поля:
class Car { string brand = "Hunday Solaris"; string colour = "Yellow"; double speed = 0; /*...остальной код программы...*/ }
Примеры кода написаны на псевдокоде с C-подобным синтаксисом.
Инкапсуляция
Поля могут изменять свои значения в ходе выполнения программы, если это предусмотрено программистом. Если автор не хочет, чтобы поля были доступны вне класса, и какая-то другая программа (пользователь) могла изменить их значение, то он «инкапсулирует» данные, то есть делает их недоступными, используя ключевые слова private, protected. Если же поля должны быть доступны во всей программе, то перед ними ставится доступ public.
Например, можно сделать все поля класса публичными:
class Car { public string brand; public string colour; public double speed; * ...остальной код программы... * }
В таком случае доступ к этим полям не будет ограничен. В пользовательском интерфейсе можно будет случайно или намеренно поменять важные данные в таких полях, что в дальнейшем некорректно отразится на работе всей программы:
class MainClass { public static void Main() { Car car = new Car(); car.colour = "Red"; /* ...остальной код программы...*/ } }
Чтобы избежать случайного изменения данных, разработчик инкапсулирует их. В случае с цветом машины вместо public необходимо написать private. Тогда изменение цвета напрямую будет сделать невозможно.
Методы
Методы — это функции, позволяющие оперировать с полями класса или с какими-то другими данными. Как и любые функции в процедурных языках программирования, они принимают данные, и могут либо возвращать результат вычислений, либо не возвращать (например, выводить что-то на консоль). Например:
class Car { public string brand = "Hunday Solaris"; public string colour = "Yellow"; public double speed = 0;
/*ниже описан метод «Drive», в который передается булевая переменная whatIsTrafficLight (со значениями только false - красный свет, или true - зеленый свет, то есть можно ехать) public void Drive(bool whatIsTrafficLight) { if (whatIsTrafficLight == true) { speed = speed + 40; } else { speed = 0; } }
}
В итоге с помощью метода Drive мы меняем скорость класса «Машина». Но на деле, в настоящей разработке, перед программистом стоит несколько непростых задач. Во-первых, сделать код поддерживаемым.
Полиморфизм
Второй «столп» разработки объектно-ориентированным подходом — полиморфизм. Бьерн Страуструп, создатель языка C++, сформулировал определение полиморфизма так: «Один интерфейс — много реализаций». Вкратце, полиморфизм — это возможность создавать абстрактный класс, который описывает общую конструкцию структуры, а от него уже создаются производные классы, реализующие недостающие механизмы. Например, при создании персонажа компьютерной игры, с точки зрения объектно-ориентированного подхода, логично будет сначала реализовать абстрактный класс Person, и от него уже создавать конкретные классы: Archer, Healer, Warrior и так далее.
Или еще пример с машиной. Если мы оперируем одной машиной, с несколькими полями и методами, нам ничего не стоит вручную поменять несколько значений в коде. Но сколько может быть таких машин? Или, например, пользователей в социальной сети? У каждого есть имя, фамилия, семейное положение, фотоальбом, огромное количество записей, ссылок на другие страницы, на других пользователей и так далее. И если разработчики социальной сети решат сделать редизайн, и какие-то параметры пользователя поменять или убрать, то с таким подходом возникнет большое количество работы. Решает эту проблему объектно-ориентированный подход. Классы создаются не для каждого конкретного объекта, а вначале проектируется абстрактный класс, и от него создаются классы-наследники. Как и инкапсуляция, это второе важнейшее правило ООП.
Наследование
Наследование — еще одно правило при использовании объектно-ориентированного подхода. Оно заключается в способности класса-наследника использовать возможности класса-родителя. К примеру, если мы в нашем автопарке захотим иметь еще и мотоцикл, то не обязательно писать для нового класса повторяющиеся свойства. Вместо этого можно сказать, что мотоцикл является классом-наследником от машины. Тогда становится возможным использовать схожие поля и методы машины в классе мотоцикла, например, марку, цвет, скорость. В коде наследование обозначается так:
class Motocycle : Car { /*…остальной код программы...*/ }
Теперь поля и методы класса-родителя Car доступны для использования в классе-наследнике Motorcycle.
Вкратце, наследование — это механизм повторного использования кода, и нацелен на удобное и логически грамотное расширение программы. Также наследование помогает следовать принципу DRY (Do not Repeat Yourself). Согласно этому принципу в коде не должно быть повторяющихся участков, ведь это создает лишнюю нагрузку при компилировании и выполнении программы. Если в коде есть повторяющиеся участки, значит, его надо оптимизировать — вынести повторы в отдельные методы, и вызывать их по надобности; применить наследование к логически похожим объектам, в которых есть идентичные поля и методы.
Резюме
Понятию объектно-ориентированного подхода в программировании уже более сорока лет, и сейчас это наиболее востребованный способ разработки (кроме специфических областей, например, разработки ПО для контроллеров, где главенствует язык С). Важнейшие парадигмы ООП это:
Хорошо изучив эти мощнейшие инструменты, современный разработчик сможет писать быстрый, поддерживаемый, визуально приятный и модифицируемый код, который долгие годы будет поддерживать нужды бизнеса, приносить радость геймерам, решать социальные проблемы людей или обеспечивать коммуникацию во всех уголках мира.