Полиморфизм

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РФ 
Федеральное государственное бюджетное образовательное учреждение 
высшего профессионального образования

«Московский государственный университет 
приборостроения и информатики»

 

 

 

 

 

 

 

Реферат по дисциплине 
«Объектно-ориентированное программирование»

  • «Полиморфизм»

 

 

 

 

 

 

 

 

 

 

Ф.И.О:

Леонов С. В.

Группа:

ИТ7-1331

Курс:

1

Специальность:

230400.62

Руководитель:

Прудкин В. Е


 

 

 

 

 

Москва, 2013 г.


 

Оглавление

ВВЕДЕНИЕ………………………………………………………………………….3

Полиморфизм………………………………………………………………………..4

Формы полиморфизма……………………………………………………………...8

ЗАКЛЮЧЕНИЕ……………………………………………………………………..13

СПИСОК ИСПОЛЬЗОВАННОЙ ЛИТЕРАТУРЫ………………………………...14 

Введение

 

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

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

      Кратко  смысл полиморфизма можно выразить фразой: «Один интерфейс, множество реализаций».

 

      Цели  и задачи:

 

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

 

Полиморфизм

 

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

   Полиморфизм позволяет  писать более абстрактные программы  и повысить коэффициент повторного использования кода.

   Общие свойства объектов объединяются в систему, которую могут называть по-разному — интерфейс, класс. Общность имеет внешнее и внутреннее выражение:

    ▪ внешняя  общность проявляется как одинаковый  набор методов с одинаковыми именами и сигнатурами (именем методов и типами аргументов и их количеством);

    ▪ внутренняя  общность — одинаковая функциональность методов. Её можно описать интуитивно или выразить в виде строгих законов, правил, которым должны подчиняться методы. Возможность приписывать разную функциональность одному методу (функции, операции) называется перегрузкой метода (перегрузкой функций, перегрузкой операций).

 

Примеры

 

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





5

public class Shape { 
    public void draw() { 
       //ничего не делаем 
    } 
}


После этого мы создаем  различные классы-наследники: Square (квадрат), Сircle (круг) и Triangle:










10 
11 
12 
13 
14 
15 
16 
17

public class Square extends Shape { 
    public void draw() { 
        System.out.println("Квадрат"); 
    } 

 
public class Сircle extends Shape { 
    public void draw() { 
        System.out.println("Круг"); 
    } 

 
public class Triangle extends Shape { 
    public void draw() { 
        System.out.println("Треугольник"); 
    } 
}


Как вы могли заметить в наследниках у нас переопределен  метод draw. 
Теперь увидим, в чем заключается удивительная возможность полиморфизма:





5

Shape[] a = new Shape[]{new Shape(), new Triangle(), new Square(), new Сircle()}; 
 
for(int i = 0; i < a.length; i++) { 
    a[i].draw(); 
}


Выведет: 
Треугольник 
Квадрат 
Круг 
Таким образом каждый класс наследник вызвал именно свой метод draw, вместо того, чтобы вызвать пустой метод draw из класса Shape. В следующих уроках мы поймем зачем может понадобится такой подход.

 

В объектно-ориентированных  языках

 

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

      Класс-потомок  сам может быть родителем. Это  позволяет строить сложные схемы  наследования — древовидные или сетевидные.

      Абстрактные  (или чисто виртуальные) методы  не имеют реализации вообще (на  самом деле некоторые языки,  например C++, допускают реализацию  абстрактных методов в родительском  классе). Они специально предназначены для наследования. Их реализация должна быть определена в классах-потомках.

      Класс  может наследовать функциональность  от нескольких классов. Это  называется множественным наследованием. Множественное наследование создаёт известную проблему (в C++), когда класс наследуется от нескольких классов-посредников, которые в свою очередь наследуются от одного класса (так называемая «Проблема ромба»): если метод общего предка был переопределён в посредниках, неизвестно, какую реализацию метода должен наследовать общий потомок. Решается эта проблема путём отказа от множественного наследования для классов и разрешением множественного наследования для полностью абстрактных классов (то есть интерфейсов) (C#, Delphi, Java), либо через виртуальное наследование (C++).

В функциональных языках

 

      Полиморфизм  в функциональных языках будет рассмотрен на примере языка Haskell.

      В Haskell существует два вида полиморфизма — параметрический (чистый) и специальный, (на основе классов). Специальный называют еще ad hoc (от лат. ad hoc — специально).

 

      Их можно  отличить следующим образом:

 

Параметрический полиморфизм

 

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

 

Специальный полиморфизм

 

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

      В Haskell есть деление  на классы и экземпляры (instance), которого нет в ООП. Класс определяет набор и сигнатуры методов (возможно, задавая для некоторых или всех из них реализации по умолчанию), а экземпляры реализуют их. Таким образом, автоматически отпадает проблема множественного наследования. Классы не наследуют и не переопределяют методы других классов — каждый метод принадлежит только одному классу. Такой подход проще, чем сложная схема взаимоотношений классов в ООП. Некоторый тип данных может принадлежать нескольким классам; класс может требовать, чтобы каждый его тип обязательно принадлежал к другому классу, или даже нескольким; такое же требование может выдвигать экземпляр. Это аналоги множественного наследования. Есть и некоторые свойства, не имеющие аналогов в ООП. Например, реализация списка, как экземпляра класса сравнимых величин, требует, чтобы элементы списка также принадлежали к классу сравнимых величин.

      Программистам, переходящим  от ООП к ФП, следует знать важное отличие их системы классов. Если в ООП класс «привязан» к объекту, т. е. к данным, то в ФП — к функции. В ФП сведения о принадлежности к классу передаются при вызове функции, а не хранятся в полях объекта. Такой подход, в частности, позволяет решить проблему метода нескольких объектов (в ООП метод вызывается у одного объекта). Пример: метод сложения (чисел, строк) требует двух аргументов, причем одного типа.

 

Неявная типизация

 

      В некоторых  языках программирования (например, в Python и Ruby) применяется так называемая утиная типизация (другие названия: латентная, неявная), которая представляет собой разновидность сигнатурного полиморфизма. Таким образом, например, в языке Python полиморфизм не обязательно связан с наследованием.

 

Формы полиморфизма

 

      Статический  и динамический полиморфизм (упоминается  в классической книге Саттера  и Александреску, которая является источником).

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

      В одном случае  конкретный смысл фрагмента зависит от того, в каком окружении код был построен. Это т.н. статический полиморфизм. Шаблоны в Си++ реализуют именно статический полиморфизм. Если в коде шаблонного класса вызвана, например, std::sort, то реальный смысл вызова зависит от того, для каких именно типовых параметров будет развернут данный шаблон - вызовется одна из std::sort.

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

 

Полиморфизм включения

 

      Этот  полиморфизм называют чистым  полиморфизмом. Применяя такую  форму полиморфизма, родственные объекты можно использовать обобщенно. С помощью замещения и полиморфизма включения можно написать один метод для работы со всеми типами объектов TPerson. Используя полиморфизм включения и замещения можно работать с любым объектом, который проходит тест «is-A». Полиморфизм включения упрощает работу по добавлению к программе новых подтипов, так как не нужно добавлять конкретный метод для каждого нового типа, можно использовать уже существующий, только изменив в нем поведение системы. С помощью полиморфизма можно повторно использовать базовый класс; использовать любого потомка или методы, которые использует базовый класс.

 

Параметрический полиморфизм

 

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

Параметрические методы

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

 

Параметрические типы

 

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

Полиморфизм переопределения

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

 

Полиморфизм-перегрузка

 

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

      Сравнение  полиморфизма в функциональном и объектно-ориентированном программировании

      Система  классов в ФП и в ООП устроены по-разному, поэтому к их сравнению следует подходить очень осторожно.

Полиморфизм является довольно обособленным свойством языка программирования. Например, классы в C++ изначально были реализованы как препроцессор для C. Для Haskell же существует алгоритм трансляции программ, использующих специальный полиморфизм, в программы с исключительно параметрическим полиморфизмом.

      Несмотря  на концептуальные различия систем классов в ФП и ООП, реализуются они примерно одинаково — с помощью таблиц виртуальных методов. Используется часто в Java.

 

 

Постановка задачи

 

Предположим, на сайте  нужны три вида публикаций — новости, объявления и статьи. В чем-то они похожи — у всех них есть заголовок и текст, у новостей и объявлений есть дата. В чем-то они разные — у статей есть авторы, у новостей — источники, а у объявлений — дата, после которой оно становится не актуальным. 
 
          Самые простые варианты, которые приходят в голову — написать три отдельных класса и работать с ними. Или написать один класс, в которым будут все свойства, присущие всем трем типам публикаций, а задействоваться будут только нужные. Но ведь для разных типов аналогичные по логике методы должны работать по-разному. Делать несколько однотипных методов для разных типов (get_news, get_announcements, get_articles) — это уже совсем неграмотно. Тут нам и поможет полиморфизм.

 

Програмный код

 

abstract class Publication 

    // таблица, в которой хранятся данные по элементу 
    protected $table; 
     
    // свойства элемента нам неизвестны 
    protected $properties = array(); 
     
    // конструктор 
    public function __construct($id) 
    { 
        // обратите внимание, мы не знаем, из какой таблицы нам нужно получить данные 
        $result = mysql_query ('SELECT * FROM `'.$this->table.'` WHERE `id`="'.$id.'" LIMIT 1'); 
        // какие мы получили данные, мы тоже не знаем 
        $this->properties = mysql_fetch_assoc($result); 
    } 
     
    // метод, одинаковый для любого типа публикаций, возвращает значение свойства 
    public function get_property($name) 
    { 
        if (isset($this->properties[$name])) 
            return $this->properties[$name]; 
             
        return false; 
    } 
     
    // метод, одинаковый для любого типа публикаций, устанавливает значение свойства 
    public function set_property($name, $value) 
    { 
        if (!isset($this->properties[$name])) 
            return false; 
             
        $this->properties[$name] = $value; 
         
        return $value; 
    } 
     
    // а этот метод должен напечатать публикацию, но мы не знаем, как именно это сделать, и потому объявляем его абстрактным 
    abstract public function do_print(); 

 

Производные классы

 

Теперь можно перейти к созданию производных классов, которые и реализуют недостающую функциональность. 
 
class News extends Publication 

    // конструктор класса новостей, производного от класса публикаций 
    public function __construct($id) 
    { 
        // устанавливаем значение таблицы, в которой хранятся данные по новостям 
        $this->table = 'news_table'; 
        // вызываем конструктор родительского класса 
        parent::__construct($id); 
    } 
     
    // переопределяем абстрактный метод печати 
    public function do_print() 
    { 
        echo $this->properties['title']; 
        echo '<br /><br />'; 
        echo $this->properties['text']; 
        echo '<br />Источник: '.$this->properties['source']; 
    } 

 
class Announcement extends Publication 

    // конструктор класса объявлений, производного от класса публикаций 
    public function __construct($id) 
    { 
        // устанавливаем значение таблицы, в которой хранятся данные по объявлениям 
        $this->table = 'announcements_table'; 
        // вызываем конструктор родительского класса 
        parent::__construct($id); 
    } 
     
    // переопределяем абстрактный метод печати 
    public function do_print() 
    { 
        echo $this->properties['title']; 
        echo '<br />Внимание! Объявление действительно до '.$this->properties['end_date']; 
        echo '<br /><br />'.$this->properties['text']; 
    } 

 
class Article extends Publication 

    // конструктор класса статей, производного от класса публикаций 
    public function __construct($id) 
    { 
        // устанавливаем значение таблицы, в которой хранятся данные по статьям 
        $this->table = 'articles_table'; 
        // вызываем конструктор родительского класса 
        parent::__construct($id); 
    } 
     
    // переопределяем абстрактный метод печати 
    public function do_print() 
    { 
        echo $this->properties['title']; 
        echo '<br /><br />'; 
        echo $this->properties['text']; 
        echo '<br />&copy; '.$this->properties['author']; 
    } 
}

 

Теперь об использовании

 
Суть в том, что один и тот же код используется для объектов разных классов. 
 
// наполняем массив публикаций объектами, производными от Publication 
$publications[] = new News($news_id); 
$publications[] = new Announcement($announcement_id); 
$publications[] = new Article($article_id); 
 
foreach ($publications as $publication) { 
    // если мы работаем с наследниками Publication 
    if ($publication instanceof Publication) { 
        // то печатаем данные 
        $publication->do_print();  
    } else { 
        // исключение или обработка ошибки 
    }

}

 

Основная выгода полиморфизма — легкость, с которой можно создавать новые классы, «ведущие себя» аналогично родственным, что, в свою очередь, позволяет достигнуть расширяемости и модифицируемости. В данном случае показан всего лишь примитивный пример, но даже в нем видно, насколько использование абстракций может облегчить разработку. Мы можем работать с новостями точно так, как с объявлениями или статьями, при этом нам даже не обязательно знать, с чем именно мы работаем! В реальных, намного более сложных приложениях, эта выгода еще ощутимей. 
Заключение

 

      Объектно-ориентированные языки в полной мере поддерживают парадигму ООП, а именно, инкапсуляцию, наследование и полиморфизм. Типичными представителями таких языков являются C++, Java, C#.

      К объектным  языкам относят языки как минимум  поддерживающие инкапсуляцию. Они  позволяют создавать пользовательские  объекты, но, обычно не поддерживают  наследование или полиморфизм,  или же поддерживают, но не  в полной мере. Типичными представителем объектных языков являются Visual Basic до шестой версии включительно и Ada.

 

 

Список использованной литературы:

 

   1. Буч Г. Объектно-ориентированный  анализ и проектирование с  примерами приложений на C++. Пер.  с англ. М.: Бином, СПб.: Невский  диалект, 2008.208с.

   2. Буч Грейди, Рамбо  Джеймс, Джекобсон Айвар. Язык UML. Руководство пользователя. Пер. с  англ. М.: ДМК, 2008.312с.

   3. Гамма Э., Хелм  Р., Джексон Р., Влиссидес Дж. Приемы  объектно-ориентированного проектирования. Паттерны проектирования. Пер. с англ. СПб.: Питер, 2009.413с.

   4. Ларман К.  Применение UML и шаблонов проектирования / Пер. с англ. М.: Виль-ямс, 2009.295с.

  5.   Интернет источники:

 

http://az.stu.cn.ua/files/lecture/3_Polymorphism.pdf

http://humbio.ru/humbio/tarantul_sl/000010e3.htm

 


Полиморфизм