Перейти к основному содержимому

5.08. ООП

Разработчику Архитектору

ООП

Почему ST «чистое ООП»? Потому что нет функций, операторов, процедур. Только объекты. Поэтому и ОБЪЕКТНО-ориентированное программирование.

Помните основы ООП?

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

Класс — это шаблон для создания объектов.

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

Создание класса:

Object subclass: #Person
instanceVariableNames: 'name age'
classVariableNames: ''
package: 'MyApp'

Здесь:

  • Object — родительский класс.
  • #Person — имя нового класса.
  • 'name age' — экземплярные переменные (приватные).
  • package: 'MyApp' — пространство имён.

Создание объекта (экземпляра):

| person |
person := Person new.

new — это сообщение, отправленное классу Person.

Причем, класс Person — это объект, экземпляр своего метакласса. Вы можете:

Person class                "→ Metaclass of Person"
Person superclass "→ Object"
Person methods "→ список всех методов"
Person numberOfInstances "→ сколько объектов создано"

Именно так и можно в идеале реализовывать паттерны вроде Singleton, фабрики, рефлексию — прямо в языке. И всё что есть у класса, можно посмотреть прямо в инспекторе, как мы видели в Pharo.

Метод — это реализация ответа на сообщение.

Пример метода:

getName
^ name
setName: aName
name := aName
introduceYourself
^ 'Hi, I am ', name, ' and I am ', age printString, ' years old.'

^ — возврат значения (аналог return). Мы именно так и создали наш метод, который выводил (возвращал) Hello World!

setName: aName — ключевое сообщение с одним параметром.

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

Говоря о наследовании. Smalltalk поддерживает одиночное наследование. Нет множественного наследования — но и не нужно.

Object subclass: #Animal
instanceVariableNames: 'name'
...

Animal subclass: #Dog
instanceVariableNames: 'breed'
...

Теперь Dog наследует все переменные и методы от Animal.

Помните про переопределение? В ST тоже есть переопределение метода:

Dog >> makeSound
^ 'Woof!'

Вызов родительского метода:

Dog >> introduce
^ super introduce, ' I am a dog.'

super — специальное ключевое слово, указывающее на родительский класс.

Вместо этого — композиция, делегирование, поведение через блоки.

А как с инкапсуляцией?

В Smalltalk экземплярные переменные — приватны. Доступ только через методы. Методы — публичные, если не помечены иначе (в некоторых реализациях можно указать private). Нет ключевых слов private, protected, public — но дисциплина поддерживается соглашениями.

Person >> name
^ name

Person >> name: aName
name := aName

Код за пределами класса не должен напрямую читать или менять name — только через геттер и сеттер. Инкапсуляция достигается договорённостью и культурой, а не синтаксисом.

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

Object subclass: #Shape
...

Shape subclass: #Circle
...

Shape subclass: #Rectangle
...

Оба класса реализуют:

Circle >> area
^ 3.14 * radius * radius

Rectangle >> area
^ width * height

Теперь можно писать:

| shapes total |
shapes := { Circle new. Rectangle new }.
total := 0.
shapes do: [ :each | total := total + each area ].

Никаких интерфейсов, аннотаций, типов.

Полиморфизм — duck typing: «если крякает как утка, плавает как утка — значит, это утка».

Интерфейсов и абстрактных классов в ST нет, ибо нет понятий interface или abstract class, как в Java или C#. Потому что они не нужны. Вместо интерфейсов — соглашения о сообщениях. Если объект отвечает на draw, move, area — он "реализует" этот «интерфейс». Это динамический полиморфизм, более гибкий, чем статические интерфейсы.

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

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