Объектно-ориентированное программирование для чайников

Главная Форумы Программирование Технология программирования Объектно-ориентированное программирование Объектно-ориентированное программирование для чайников

В этой теме 0 ответов, 1 участник, последнее обновление  Васильев Владимир Сергеевич 6 мес., 4 нед. назад.

  • Автор
    Сообщения
  • #3710

    Классы и объекты

    Начнем с самого базового понятия, — класса. Класс, он же тип, чтобы не мучить, и не сбивать с толку формулировками, можно объяснить на примере: класс это Собака, либо Кошка, либо Мышка, — всё это классы. А вот Жучка, Мурчик и Микки-Маус, — это экземпляры классов Собака, Кошка, Мышка. Экземпляры классов еще называют объектами. Итак, – Жучка это экземпляр класса Собака, Мурчик, — экземпляр класса Кошка, а Микки-Маус, — экземпляр класса Мышка, другими словами объект. Класс — единственный и неповторимый. У вас могут быть классы очень похожие, как овчарка и доберман, но это всё равно разные классы, хоть и очень похожие. Класс представляет собой набор характеристик/свойств, которые описывают его состояние и действия/методы, которые он может выполнить. Например, — нас есть класс Овчарка, к числу её свойств можно отнести «возраст» и «кличку». Экземпляр класса может выполнять действия, описанные в классе (лаять, сидеть, лежать), а также содержит значения свойств класса (класс Овчарка имеет свойство «возраст», а объект Барбос имеет значение, — 3 года). Помимо свойств и методов, объект имеет собственное имя, не путать со свойством «кличка», вот как это может выглядеть:

    МояСобака.кличка = "Барбос"

    Что означает, что у объекта «МояСобака», есть кличка, и эта кличка — Барбос. А бывает и такая ситуация:

    ХозяинСобаки.имя = "Василий"
    ХозяинСобаки.отчество = "Иванович"

    Тут у нас объект «ХозяинСобаки», у которого свойство «имя» имеет значение «Василий», а отчество равно «Иванович».
    Похожим образом работают методы (действия) объектов, например:

    МояСобака.лежать()
    МояСобака.сидеть()

    Методы могут параметризироваться, например, мы знаем что метод «лаять» заданное количество раз:

    МояСобака.лаять(3)

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

    МояСобака = new Собака()

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

    МояСобака = new Собака("Барбос")

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

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

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

    class Animal {
    	function draw() {
    		return "just animal";
    	}
     
    	function eat() {
    		return "the animal is eating";
    	}
    }
     
    class Cow extends Animal {
    	function draw() {
    		Return "something that looks like a cow";
    	}
    }

    Как видите здесь Корова (Cow) унаследовала функционал от Животного (Animal), изменив реализацию метода draw (конкретизируя как корова на самом деле выглядит), и оставив реализацию метода eat(). Это и есть наследование. Теперь инкапсуляция. Сам по себе этот термин означает «сокрытие». Инкапсуляция, это способ сделать невозможным изменения критичных для работы класса свойств или вызова внутренних методов. Например у нас есть требование: каждое животное должно иметь кличку, и кличка, в течении его жизни не должна меняться. Самое правильное в таком случае это принимать кличку в качестве параметра конструктора (метода выполняемого при создании класса), и хранить его во внутреннем, сокрытом свойстве. Например так:

    сlass Animal {
    	private $name;
     
    	function __construct($name) {
    		$this->name = $name;
    	}
     
    	function getName() {
    		return $this->name;
    	}	
    	//...
    }

    Вот это и есть инкапсуляция. Нет способа изменить кличку снаружи класса, и вы можете быть уверены, что в любом случае, кличка у экземпляра класса будет именно та, что была задана при создании. Ну а теперь полиморфизм. Это тут тоже начнем с примера. Добавим класс Sheep (овца).

    class Sheep extends Animal {
    	function draw() {
    		return 'something that looks like a sheep';
    	}		
    }

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

    $animal = rand(0,1) ? new Cow('burenka') : new Sheep('kudryashka');
    echo $animal->draw();

    Данный пример будет случайным образом генерировать экземпляр Коровы и Овцы, и рисовать их.
    Нужно сказать что данный пример не совсем «чистый» полиморфизм. Дело в том что полиморфизм подразумевает собой реализацию одного и того же интерфейса в разных классах. Объясню: если бы мы не реализовали метод draw() в одном из классов, у нас периодически возникала бы ошибка обращения к несуществующему методу, а в языках со строгой типизицией, ошибка бы возникала еще на стадии компиляции. Чтобы избежать подобных казусов, нужно использовать итерфейсы (interface):

    interface IDrawable {
     
    	function draw();
    }
     
    class Cow extends Animal implements IDrawable {
     
    	function draw() {
    		return 'something that looks like a cow';
    	}		
    }
     
    class Sheep extends Animal implements IDrawable {
    	function draw() {
    		return 'something that looks like a sheep';
    	}		
    }

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

Для ответа в этой теме необходимо авторизоваться.