Объектно ориентированная программа на php. ООП в PHP: Введение. Важные термины руководства по ООП на PHP

PHP один из самых популярных скриптовых языков программирования. Почти 60% веб серверов используют PHP.Миллионы веб-сайтов и веб-приложений разрабатываются на PHP каждый месяц.

PHP изначально разрабатывался как простая замена языку Perl, и уже спустя пару лет он стал чрезвычайно мощным и популярным. Язык PHP, сам по себе очень похож на ANSI C.
Одна из причин почему PHP стал таким популярным это его короткий период обучения.

Изучение PHP абсолютно не тяжёлое занятие, особенно если вы хорошо знакомы с синтаксисом Java или C.

Так как писать PHP скрипты достаточно просто, любой может написать PHP код без соблюдения каких-либо соглашений и смешивая уровень представления с бизнес логикой (это одна из основных причин существования большого количества неуправляемых проектов). Потому что в PHP не обязательно строгое соответствие соглашений написания кода, с годами когда проект становится всё больше и больше, он превращается в громадное неуправляемое приложение.

ООП или Объе́ктно-ориенти́рованное программи́рование хорошо применяется в практике программирования для более лёгкого создания управляемых проектов.
Процедурный подход подразумевает написание программного кода без использования объектов. Процедурное программирование заключается в написании кода с или без подпрограмм.

ООП обучает любой язык программирования более хорошему программному коду и используется, для получения более высокой производительности и написания больших проектов, не боясь запутаться в их управлении. ООП даёт вам возможность создавать объекты которые можно будет использовать многократно, для того что бы вы или другие разработчики могли использовать их в своих проектах не переделывая их снова и снова. ООП убирает барьеры и сложности в написании и управлении большими приложениями.

PHP позволяет нам писать приложения 2мя разными способами, первый - процедурный, а второй объектно ориентированный. Если вы до сих пор не поняли разницу между этими двумя подходами, давайте посмотрим на эти куски кода - один и тот же пример написанный разными подходами.

Процедурный:

$user_input = $_POST[‘field‘];
$filtered_content = filter($user_input); //user input filtering
mysql_connect(«dbhost»,«dbuser»,«dbpassword»); //database
mysql_select_db(«dbname»);
$sql = «some query»;
$result = mysql_query($sql);
while ($data = mysql_fetch_assoc())
{
process ($data);
}
process_user_input($filtered_content);

А вот тот же кусок кода с использованием ООП:

$input_filter = new filter();
$input_filter->filter_user_input(); //filter the user inputs
$db = new dal(«mysql»); //data access layer
$db->connect($dbconfig);//we wre using mysql
$result = $db->execute($sql);
ReportGenerator::makereport($result); //process data
$model = new Postmodel($filter->get_filtered_content());
$model->insert();

Если внимательно посмотреть на эти 2 куска кода то можно заметить, что код с использованием ООП более читабельный и легче для восприятия.

Код с ООП организован лучше потому что в нём понятно какой объект чем обрабатывается. Большие приложения написанные на процедурном подходе становится практически не возможно воспринимать уже после выхода нескольких версий. Конечно вы можете следовать жёстким правилам написания программного кода, но они утверждены миллионами разработчиков которые знают что это не даст вам в конечном итоге управляемости и юзабилити проекта, если вы не используете в своей программе ООП.
Почти все большие приложения написаны с использованием Объектно ориентированного
подхода.

Исходя из изложенного выше, можно вынести преимущества использования ООП:

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

ООП может быть рассмотрен лучше с разных сторон, особенно когда вам важно время разработки и последующее развитие приложения.
Основные преимущества использования ООП можно выразить как:

* Повторное использование : Объект это логический объект у которого есть комплект свойств и методов и он может взаимодействовать с другими объектами.. Объект может быть абсолютно независимым или может зависеть от других объектов. Объект обычно создают для решения специфических поставленных проблем. Следовательно когда другие разработчики сталкиваются с похожими проблемами, они могут подключить ваш класс к своему проекту и использовать его не боясь что он нарушит процесс их разработки. Это позволяет избежать DRY, что расшифровывается как Don’t Repeat Yourself (не повторяйся). В процедурном или модульном программировании, повторное использование возможно только в совокупности.

* Рефакторинг : Когда вам необходимо в проекте использовать рефакторинг, ООП предоставляем вам максимум преимуществ, так как все объекты это маленькие элементы и содержат свои свойства и методы как часть себя. По этому использовать рефакторинг относительно легко.

* Расширяемость : Если вам необходимо расширять функциональность вашего проекта, вы можете достичь лучших результатов при помощи ООП. Одна из основных функциональностей ООП это расширяемость. Вы можете использовать рефакторинг объектов что бы добавить функциональность. Работая над этим, вы по прежнему можете сохранить
прежнюю совместимость объекта - следовательно вы можете прекрасно работать и с прежним кодом. Или же вы можете расширить объект и создать абсолютно новый, который будет содержать все необходимые свойства и методы родительского объекта от которого происходит новый, а потом уже добавить в него новые функции. Это называется “наследование” и это очень важная возможность ООП.

* Поддержка : объектно-ориентированный код легче поддерживать так как
он следует весьма жёстким соглашениям написания кода и пишется в самопоясняющейся форме.
К примеру, когда разработчик дополняет, перерабатывает код, или отлаживает его, он может легко найти внутреннюю структуру кода и поддерживать код время от времени. Более того, когда в вашем окружении работает команда разработчиков ООП может быть лучшим решением так как вы можете распределять ваш код между членами команды, после разбития его на маленькие части. Эти маленькие части могут быть разработаны как отдельные объекты, следовательно разработчики могут работать практически независимо друг от друга. В конечном итоге объеденить все части в одно приложение не составит большого труда.

* Эффективность : Идея ООП в действительности была разработана для повышения эффективности и облегчения процесса разработки. Несколько шаблонов проектирования разработаны что бы создавать более эффективный и хороший код.
Более того в ООП вы можете вы можете размышлять над вашими решениями в более удобной форме чем в процедурном подходе. Поскольку вы разбиваете вашу проблему на несколько маленьких проблем и вы находите решение для каждой из них отдельно, большая проблема решается сама по себе.

P.S мой первый хабратопик, если понравится буду переводить книгу дальше, как по мне довольно интересная и содержательная

Наверное, в половине вакансий(если не больше), требуется знание и понимание ООП. Да, эта методология, однозначно, покорила многих программистов! Обычно понимание ООП приходит с опытом, поскольку годных и доступно изложенных материалов на данный счет практически нет. А если даже и есть, то далеко не факт, что на них наткнутся читатели. Надеюсь, у меня получится объяснить принципы этой замечательной методологии, как говорится, на пальцах.

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

ООП (или объектно-ориентированное программирование) представляет собой способ организации кода программы, когда основными строительными блоками программы являются объекты и классы, а логика работы программы построена на их взаимодействии.


Об объектах и классах

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

Допустим, нам нужно написать программу, рассчитывающую периметр и площадь треугольника, который задан двумя сторонами и углом между ними. Для написания такой программы используя ООП, нам необходимо будет создать класс (то есть структуру) Треугольник. Класс Треугольник будет хранить три поля (три переменные): сторона А, сторона Б, угол между ними; и два метода (две функции): посчитать периметр, посчитать площадь. Данным классом мы можем описать любой треугольник и вычислить периметр и площадь. Так вот, конкретный треугольник с конкретными сторонами и углом между ними будет называться экземпляром класса Треугольник. Таким образом класс - это шаблон, а экземпляр - конкретная реализация шаблона. А вот уже экземпляры являются объектами, то есть конкретными элементами, хранящими конкретные значения.

Одним из самых распространенных объектно-ориентированных языков программирования является язык java. Там без использования объектов просто не обойтись. Вот как будет выглядеть код класса, описывающего треугольник на этом языке:

/** * Класс Треугольник. */ class Triangle { /** * Специальный метод, называемый конструктор класса. * Принимает на вход три параметра: * длина стороны А, длина стороны Б, * угол между этими сторонами(в градусах) */ Triangle(double sideA, double sideB, double angleAB) { this.sideA = sideA; this.sideB = sideB; this.angleAB = angleAB; } double sideA; //Поле класса, хранит значение стороны А в описываемом треугольнике double sideB; //Поле класса, хранит значение стороны Б в описываемом треугольнике double angleAB; //Поле класса, хранит угла(в градусах) между двумя сторонами в описываемом треугольнике /** * Метод класса, который рассчитывает площадь треугольника */ double getSquare() { double square = this.sideA * this.sideB * Math.sin(this.angleAB * Math.PI / 180); return square; } /** * Метод класса, который рассчитывает периметр треугольника */ double getPerimeter() { double sideC = Math.sqrt(Math.pow(this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos(this.angleAB * Math.PI / 180)); double perimeter = this.sideA + this.sideB + sideC; return perimeter; } }

Если мы внутрь класса добавим следующий код:

/** * Именно в этом месте запускается программа */ public static void main(String args) { //Значения 5, 17, 35 попадают в конструктор класса Triangle Triangle triangle1 = new Triangle(5, 17, 35); System.out.println("Площадь треугольника1: "+triangle1.getSquare()); System.out.println("Периметр треугольника1: "+triangle1.getPerimeter()); //Значения 6, 8, 60 попадают в конструктор класса Triangle Triangle triangle2 = new Triangle(6, 8, 60); System.out.println("Площадь треугольника1: "+triangle2.getSquare()); System.out.println("Периметр треугольника1: "+triangle2.getPerimeter()); }

то программу уже можно будет запускать на выполнение. Это особенность языка java. Если в классе есть такой метод

Public static void main(String args)

то этот класс можно выполнять. Разберем код подробнее. Начнем со строки

Triangle triangle1 = new Triangle(5, 17, 35);

Здесь мы создаем экземпляр triangle1 класса Triangle и тут же задаем ему параметры сторон и угла между ними. При этом, вызывается специальный метод, называемый конструктор и заполняет поля объекта переданными значениями в конструктор. Ну, а строки

System.out.println("Площадь треугольника1: "+triangle1.getSquare()); System.out.println("Периметр треугольника1: "+triangle1.getPerimeter());

выводят рассчитанные площадь треугольника и его периметр в консоль.

Аналогично все происходит и для второго экземпляра класса Triangle .

Понимание сути классов и конструирования конкретных объектов - это уверенный первый шаг к пониманию методологии ООП.

Еще раз, самое важное:

ООП - это способ организации кода программы;

Класс - это пользовательская структура данных, которая воедино объединяет данные и функции для работы с ними(поля класса и методы класса);

Объект - это конкретный экземпляр класса, полям которого заданы конкретные значения.


Три волшебных слова

ООП включает три ключевых подхода: наследование, инкапсуляцию и полиморфизм. Для начала, приведу определения из wikipedia :

Инкапсуляция - свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе. Некоторые языки (например, С++) отождествляют инкапсуляцию с сокрытием, но большинство (Smalltalk, Eiffel, OCaml) различают эти понятия.

Наследование - свойство системы, позволяющее описать новый класс на основе уже существующего с частично или полностью заимствующейся функциональностью. Класс, от которого производится наследование, называется базовым, родительским или суперклассом. Новый класс - потомком, наследником, дочерним или производным классом.

Полиморфизм - свойство системы, позволяющее использовать объекты с одинаковым интерфейсом без информации о типе и внутренней структуре объекта.

Понять, что же все эти определения означают на деле достаточно сложно. В специализированных книгах, раскрывающих данную тему на каждое определение, зачастую, отводится целая глава, но, как минимум, абзац. Хотя, сути того, что нужно понять и отпечатать навсегда в своем мозге программиста совсем немного.
А примером для разбора нам будут служить фигуры на плоскости. Из школьной геометрии мы знаем, что у всех фигур, описанных на плоскости, можно рассчитать периметр и площадь. Например, для точки оба параметра равны нулю. Для отрезка мы можем вычислить лишь периметр. А для квадрата, прямоугольника или треугольника - и то, и другое. Сейчас же мы опишем эту задачу в терминах ООП. Также не лишним будет уловить цепь рассуждений, которые выливаются в иерархию классов, которая, в свою очередь, воплощается в работающий код. Поехали:


Итак, точка - это самая малая геометрическая фигура, которая является основой всех прочих построений (фигур). Поэтому именно точка выбрана в качестве базового родительского класса. Напишем класс точки на java:

/** * Класс точки. Базовый класс */ class Point { /** * Пустой конструктор */ Point() {} /** * Метод класса, который рассчитывает площадь фигуры */ double getSquare() { return 0; } /** * Метод класса, который рассчитывает периметр фигуры */ double getPerimeter() { return 0; } /** * Метод класса, возвращающий описание фигуры */ String getDescription() { return "Точка"; } }

У получившегося класса Point пустой конструктор, поскольку в данном примере мы работаем без конкретных координат, а оперируем только параметрами значениями сторон. Так как у точки нет никаких сторон, то и передавать ей никаких параметров не надо. Также заметим, что класс имеет методы Point::getSquare() и Point::getPerimeter() для расчета площади и периметра, оба возвращают 0. Для точки оно и логично.


Поскольку у нас точка является основой всех прочих фигур, то и классы этих прочих фигур мы наследуем от класса Point . Опишем класс отрезка, наследуемого от класса точки:

/** * Класс Отрезок */ class LineSegment extends Point { LineSegment(double segmentLength) { this.segmentLength = segmentLength; } double segmentLength; // Длина отрезка /** * Переопределенный метод класса, который рассчитывает площадь отрезка */ double getSquare() { return 0; } /** * Переопределенный метод класса, который рассчитывает периметр отрезка */ double getPerimeter() { return this.segmentLength; } String getDescription() { return "Отрезок длиной: " + this.segmentLength; } }

Class LineSegment extends Point

означает, что класс LineSegment наследуется от класса Point . Методы LineSegment::getSquare() и LineSegment::getPerimeter() переопределяют соответствующие методы базового класса. Площадь отрезка всегда равняется нулю, а площадь периметра равняется длине этого отрезка.

Теперь, подобно классу отрезка, опишем класс треугольника(который также наследуется от класса точки):

/** * Класс Треугольник. */ class Triangle extends Point { /** * Конструктор класса. Принимает на вход три параметра: * длина стороны А, длина стороны Б, * угол между этими сторонами(в градусах) */ Triangle(double sideA, double sideB, double angleAB) { this.sideA = sideA; this.sideB = sideB; this.angleAB = angleAB; } double sideA; //Поле класса, хранит значение стороны А в описываемом треугольнике double sideB; //Поле класса, хранит значение стороны Б в описываемом треугольнике double angleAB; //Поле класса, хранит угла(в градусах) между двумя сторонами в описываемом треугольнике /** * Метод класса, который рассчитывает площадь треугольника */ double getSquare() { double square = (this.sideA * this.sideB * Math.sin(this.angleAB * Math.PI / 180))/2; return square; } /** * Метод класса, который рассчитывает периметр треугольника */ double getPerimeter() { double sideC = Math.sqrt(Math.pow(this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos(this.angleAB * Math.PI / 180)); double perimeter = this.sideA + this.sideB + sideC; return perimeter; } String getDescription() { return "Треугольник со сторонами: " + this.sideA + ", " + this.sideB + " и углом между ними: " + this.angleAB; } }

Тут нет ничего нового. Также, методы Triangle::getSquare() и Triangle::getPerimeter() переопределяют соответствующие методы базового класса.
Ну а теперь, собственно, тот самый код, который показывает волшебство полиморифзма и раскрывает мощь ООП:

Class Main { /** * Именно в этом месте запускается программа */ public static void main(String args) { //ArrayList - Это специальная структура данных в java, // позволяющая хранить объекты определенного типа в массиве. ArrayList figures = new ArrayList(); //добавляем три разных объекта в массив figures figures.add(new Point()); figures.add(new LineSegment(133)); figures.add(new Triangle(10, 17, 55)); for (int i = 0; i

Мы создали массив объектов класса Point , а поскольку классы LineSegment и Triangle наследуются от класса Point , то и их мы можем помещать в этот массив. Получается, каждую фигуру, которая есть в массиве figures мы можем рассматривать как объект класса Point . В этом и заключается полиморфизм: неизвестно, к какому именно классу принадлежат находящиеся в массиве figures объекты, но поскольку все объекты внутри этого массива принадлежат одному базовому классу Point , то все методы, которые применимы к классу Point также и применимы к его классам-наследникам.


Теперь о инкапсуляции. То, что мы поместили в одном классе параметры фигуры и методы расчета площади и периметра - это и есть инкапсуляция, мы инкапсулировали фигуры в отдельные классы. То, что у нас для расчета периметра используется специальный метод в классе - это и есть инкапсуляцию, мы инкапсулировали расчет периметра в метод getPerimiter() . Иначе говоря, инкапсуляция - это сокрытие реализции (пожалуй, самое короткое, и в то же время емкое определением инкапсуляции).


Полный код примера:

Import java.util.ArrayList; class Main { /** * Именно в этом месте запускается программа */ public static void main(String args) { //ArrayList - Это специальная структура данных в java, // позволяющая хранить объекты определенного типа в массиве. ArrayList figures = new ArrayList(); //добавляем три разных объекта в массив figures figures.add(new Point()); figures.add(new LineSegment(133)); figures.add(new Triangle(10, 17, 55)); for (int i = 0; i

16 апреля 2008 в 12:15

PHP - ООП или процедурный подход

  • PHP

PHP один из самых популярных скриптовых языков программирования. Почти 60% веб серверов используют PHP.Миллионы веб-сайтов и веб-приложений разрабатываются на PHP каждый месяц.

PHP изначально разрабатывался как простая замена языку Perl, и уже спустя пару лет он стал чрезвычайно мощным и популярным. Язык PHP, сам по себе очень похож на ANSI C.
Одна из причин почему PHP стал таким популярным это его короткий период обучения.

Изучение PHP абсолютно не тяжёлое занятие, особенно если вы хорошо знакомы с синтаксисом Java или C.

Так как писать PHP скрипты достаточно просто, любой может написать PHP код без соблюдения каких-либо соглашений и смешивая уровень представления с бизнес логикой (это одна из основных причин существования большого количества неуправляемых проектов). Потому что в PHP не обязательно строгое соответствие соглашений написания кода, с годами когда проект становится всё больше и больше, он превращается в громадное неуправляемое приложение.

ООП или Объе́ктно-ориенти́рованное программи́рование хорошо применяется в практике программирования для более лёгкого создания управляемых проектов.
Процедурный подход подразумевает написание программного кода без использования объектов. Процедурное программирование заключается в написании кода с или без подпрограмм.

ООП обучает любой язык программирования более хорошему программному коду и используется, для получения более высокой производительности и написания больших проектов, не боясь запутаться в их управлении. ООП даёт вам возможность создавать объекты которые можно будет использовать многократно, для того что бы вы или другие разработчики могли использовать их в своих проектах не переделывая их снова и снова. ООП убирает барьеры и сложности в написании и управлении большими приложениями.

PHP позволяет нам писать приложения 2мя разными способами, первый - процедурный, а второй объектно ориентированный. Если вы до сих пор не поняли разницу между этими двумя подходами, давайте посмотрим на эти куски кода - один и тот же пример написанный разными подходами.

Процедурный:

$user_input = $_POST[‘field‘];
$filtered_content = filter($user_input); //user input filtering
mysql_connect(«dbhost»,«dbuser»,«dbpassword»); //database
mysql_select_db(«dbname»);
$sql = «some query»;
$result = mysql_query($sql);
while ($data = mysql_fetch_assoc())
{
process ($data);
}
process_user_input($filtered_content);

А вот тот же кусок кода с использованием ООП:

$input_filter = new filter();
$input_filter->filter_user_input(); //filter the user inputs
$db = new dal(«mysql»); //data access layer
$db->connect($dbconfig);//we wre using mysql
$result = $db->execute($sql);
ReportGenerator::makereport($result); //process data
$model = new Postmodel($filter->get_filtered_content());
$model->insert();

Если внимательно посмотреть на эти 2 куска кода то можно заметить, что код с использованием ООП более читабельный и легче для восприятия.

Код с ООП организован лучше потому что в нём понятно какой объект чем обрабатывается. Большие приложения написанные на процедурном подходе становится практически не возможно воспринимать уже после выхода нескольких версий. Конечно вы можете следовать жёстким правилам написания программного кода, но они утверждены миллионами разработчиков которые знают что это не даст вам в конечном итоге управляемости и юзабилити проекта, если вы не используете в своей программе ООП.
Почти все большие приложения написаны с использованием Объектно ориентированного
подхода.

Исходя из изложенного выше, можно вынести преимущества использования ООП:

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

ООП может быть рассмотрен лучше с разных сторон, особенно когда вам важно время разработки и последующее развитие приложения.
Основные преимущества использования ООП можно выразить как:

* Повторное использование : Объект это логический объект у которого есть комплект свойств и методов и он может взаимодействовать с другими объектами.. Объект может быть абсолютно независимым или может зависеть от других объектов. Объект обычно создают для решения специфических поставленных проблем. Следовательно когда другие разработчики сталкиваются с похожими проблемами, они могут подключить ваш класс к своему проекту и использовать его не боясь что он нарушит процесс их разработки. Это позволяет избежать DRY, что расшифровывается как Don’t Repeat Yourself (не повторяйся). В процедурном или модульном программировании, повторное использование возможно только в совокупности.

* Рефакторинг : Когда вам необходимо в проекте использовать рефакторинг, ООП предоставляем вам максимум преимуществ, так как все объекты это маленькие элементы и содержат свои свойства и методы как часть себя. По этому использовать рефакторинг относительно легко.

* Расширяемость : Если вам необходимо расширять функциональность вашего проекта, вы можете достичь лучших результатов при помощи ООП. Одна из основных функциональностей ООП это расширяемость. Вы можете использовать рефакторинг объектов что бы добавить функциональность. Работая над этим, вы по прежнему можете сохранить
прежнюю совместимость объекта - следовательно вы можете прекрасно работать и с прежним кодом. Или же вы можете расширить объект и создать абсолютно новый, который будет содержать все необходимые свойства и методы родительского объекта от которого происходит новый, а потом уже добавить в него новые функции. Это называется “наследование” и это очень важная возможность ООП.

* Поддержка : объектно-ориентированный код легче поддерживать так как
он следует весьма жёстким соглашениям написания кода и пишется в самопоясняющейся форме.
К примеру, когда разработчик дополняет, перерабатывает код, или отлаживает его, он может легко найти внутреннюю структуру кода и поддерживать код время от времени. Более того, когда в вашем окружении работает команда разработчиков ООП может быть лучшим решением так как вы можете распределять ваш код между членами команды, после разбития его на маленькие части. Эти маленькие части могут быть разработаны как отдельные объекты, следовательно разработчики могут работать практически независимо друг от друга. В конечном итоге объеденить все части в одно приложение не составит большого труда.

* Эффективность : Идея ООП в действительности была разработана для повышения эффективности и облегчения процесса разработки. Несколько шаблонов проектирования разработаны что бы создавать более эффективный и хороший код.
Более того в ООП вы можете вы можете размышлять над вашими решениями в более удобной форме чем в процедурном подходе. Поскольку вы разбиваете вашу проблему на несколько маленьких проблем и вы находите решение для каждой из них отдельно, большая проблема решается сама по себе.

P.S мой первый хабратопик, если понравится буду переводить книгу дальше, как по мне довольно интересная и содержательная

11 марта 2010 в 11:37

ООП с примерами (часть 1)

  • Учебный процесс в IT

Волею судьбы мне приходится читать спецкурс по паттернам проектирования в вузе. Спецкурс обязательный, поэтому, студенты попадают ко мне самые разные. Конечно, есть среди них и практикующие программисты. Но, к сожалению, большинство испытывают затруднения даже с пониманием основных терминов ООП.

Для этого я постарался на более-менее живых примерах объяснить базовые понятия ООП (класс, объект, интерфейс, абстракция, инкапсуляция, наследование и полиморфизм).

Первая часть, представленная ниже, посвящена классам, объектам и интерфейсам.
иллюстрирует инкапсуляцию, полиморфизм и наследование

Основные понятия ООП

Класс
Представьте себе, что вы проектируете автомобиль. Вы знаете, что автомобиль должен содержать двигатель, подвеску, две передних фары, 4 колеса, и т.д. Ещё вы знаете, что ваш автомобиль должен иметь возможность набирать и сбавлять скорость, совершать поворот и двигаться задним ходом. И, что самое главное, вы точно знаете, как взаимодействует двигатель и колёса, согласно каким законам движется распредвал и коленвал, а также как устроены дифференциалы. Вы уверены в своих знаниях и начинаете проектирование.

Вы описываете все запчасти, из которых состоит ваш автомобиль, а также то, каким образом эти запчасти взаимодействуют между собой. Кроме того, вы описываете, что должен сделать пользователь, чтобы машина затормозила, или включился дальний свет фар. Результатом вашей работы будет некоторый эскиз. Вы только что разработали то, что в ООП называется класс .

Класс – это способ описания сущности, определяющий состояние и поведение, зависящее от этого состояния, а также правила для взаимодействия с данной сущностью (контракт).

С точки зрения программирования класс можно рассматривать как набор данных (полей, атрибутов, членов класса) и функций для работы с ними (методов).

С точки зрения структуры программы, класс является сложным типом данных.

В нашем случае, класс будет отображать сущность – автомобиль. Атрибутами класса будут являться двигатель, подвеска, кузов, четыре колеса и т.д. Методами класса будет «открыть дверь», «нажать на педаль газа», а также «закачать порцию бензина из бензобака в двигатель». Первые два метода доступны для выполнения другим классам (в частности, классу «Водитель»). Последний описывает взаимодействия внутри класса и не доступен пользователю.

В дальнейшем, несмотря на то, что слово «пользователь» ассоциируется с пасьянсом «Косынка» и «Microsoft Word», мы будем называть пользователями тех программистов, которые используют ваш класс, включая вас самих. Человека, который является автором класса, мы будем называть разработчиком.

Объект
Вы отлично потрудились и машины, разработанные по вашим чертежам, сходят с конвейера. Вот они, стоят ровными рядами на заводском дворе. Каждая из них точно повторяет ваши чертежи. Все системы взаимодействуют именно так, как вы спроектировали. Но каждая машина уникальна. Они все имеют номер кузова и двигателя, но все эти номера разные, автомобили различаются цветом, а некоторые даже имеют литьё вместо штампованных дисков. Эти автомобили, по сути, являются объектами вашего класса.

Объект (экземпляр) – это отдельный представитель класса, имеющий конкретное состояние и поведение, полностью определяемое классом.

Говоря простым языком, объект имеет конкретные значения атрибутов и методы, работающие с этими значениями на основе правил, заданных в классе. В данном примере, если класс – это некоторый абстрактный автомобиль из «мира идей», то объект – это конкретный автомобиль, стоящий у вас под окнами.

Интерфейс
Когда мы подходим к автомату с кофе или садимся за руль, мы начинаем взаимодействие с ними. Обычно, взаимодействие происходит с помощью некоторого набора элементов: щель для приёмки монеток, кнопка выбора напитка и отсек выдачи стакана в кофейном автомате; руль, педали, рычаг коробки переключения передач в автомобиле. Всегда существует некоторый ограниченный набор элементов управления, с которыми мы можем взаимодействовать.

Интерфейс – это набор методов класса, доступных для использования другими классами.

Очевидно, что интерфейсом класса будет являться набор всех его публичных методов в совокупности с набором публичных атрибутов. По сути, интерфейс специфицирует класс, чётко определяя все возможные действия над ним.
Хорошим примером интерфейса может служить приборная панель автомобиля, которая позволяет вызвать такие методы, как увеличение скорости, торможение, поворот, переключение передач, включение фар, и т.п. То есть все действия, которые может осуществить другой класс (в нашем случае – водитель) при взаимодействии с автомобилем.

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

Примером простого интерфейса может служить машина с коробкой-автоматом. Освоить её управление очень быстро сможет любая блондинка, окончившая двухнедельные курсы вождения. С другой стороны, чтобы освоить управление современным пассажирским самолётом, необходимо несколько месяцев, а то и лет упорных тренировок. Не хотел бы я находиться на борту Боинга, которым управляет человек, имеющий двухнедельный лётный стаж. С другой стороны, вы никогда не заставите автомобиль подняться в воздух и перелететь из Москвы в Вашингтон.

». Она будет полезна как совсем зелёным новичкам, так и тем, кто уже достаточно хорошо умеет писать не объектно-ориентированный код и хочет узнать для чего же всё-таки нужно ООП.

Написать про ООП в php несколько статей меня заставило то, что я не нашёл удовлетворивших меня статей по этой теме. Есть сухие и скучные официальные мануалы или статьи, где излагаются, по сути, те же мануалы только с более подробными примерами, так же в сети очень много устаревшей информации по этой теме.

Зачем нужно ООП?

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

Иллюстрация из книги «Чистый код» — Роберт Мартин

Так в чём же дело? Почему задуманный вами проект при расширении столь быстро может превратиться в кучу запутанного кода с тучей багов? Дело в том, что новички пишут код, который делает только то, что от него требуется в одной конкретной ситуации и не предусматривает внесение каких-либо изменений. Такой подход не приемлем, особенно для веб-приложений, которые неизбежно должны будут расти и развиваться если, конечно, будут популярны. Рано или поздно вам, а может и другим разработчикам, будет необходимо возвращаться к написанному ранее коду и вносить в него изменения и чем проще это будет сделать, тем быстрее ваше приложение будет развиваться и набирать популярность.

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

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

Основные понятия

ООП – это методология (способ, подход) программирования согласно которой программный продукт представляется в виде взаимодействующих объектов. Я не согласен с тем, что ООП всегда подразумевает использование классов – js, например объектно-ориентированный язык, но в нём нет классов. Однако в применении к php ООП всегда подразумевает использование классов.

Под объектом обычно понимается некая именованная сущность, хранящая в себе данные и имеющая своё собственное поведение. Поведение объекта и структуру данных, которые он хранит, а также способы доступа к этим данным, описывает класс, к которому этот объект принадлежит. Класс это описание чем-то похожих, родственных объектов, которые обычно хранят одинаковый набор данных и имеют одинаковое поведение. Объект, который принадлежит какому-то конкретному классу, называют его экземпляром . В качестве примера можно привести класс, описывающий пользователя. Этот класс описывает структуру данных, которые будет хранить в себе каждый экземпляр этого класса. Пусть этими данными будут логин и пароль. Объект класса, хранящий конкретные значения логина и пароля будет экземпляром этого класса.

Три кита ООП


ООП основано на трёх принципах, которые часто называют тремя китами ООП, это:

  • инкапсуляция
  • полиморфизм
  • наследование

Инкапсуляция – это принцип, согласно которому данные объединяются и хранятся в объектах, а так же защищаются от неверного использования.

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

Наследование – это процесс приобретения одним типом объектов (классом) некоторых свойств другого типа объектов.

Очень часто бывает, что описание одного типа объектов то есть класс, полностью попадает под описание другого типа объектов. Например, класс, описывающий админа, может описать и пользователя, за исключением того, что у пользователя нет прав доступа. В этом случае имеет смысл сделать класс, описывающий админов, потомком класса, описывающего пользователей. При этом в классе, который описывает админов, не придётся описывать данные и поведение, которые уже описаны в классе «пользователь», нам необходимо только описать данные, которые будут отвечать за предоставления прав доступа. В этом случае класс «пользователь» будет предком класса «админ», который может иметь своего потомка, а тот своего и т.д. Цепочка наследования может быть сколь угодно длинной. Кроме того у одного предка может быть несколько потомков, каждый из которых полностью приобретёт свойства своего предка и добавит в них что-то своё, иначе наследование бессмысленно.

Полиморфизм – это использование одного и того же имени метода для решения нескольких похожих задач.

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

На этом хватит скучной теории. В следующий раз я напишу о том как описывать классы, создавать экземпляры класса, обращаться к данным (полям) и методам экземпляра.