Объектно-ориентированное программирование
Классы
Вкратце посмотрим на структуру классов в Haxe. Если раньше вы сталкивались с ООП, у вас может возникнуть легкое дежавю :
package my.pack; /* определяем класс my.pack.MyClass */ class MyClass { // .... }
У класса могут быть переменные и методы.
package my.pack; class MyClass { var id : Int; static var name : String = "MyString"; function foo() : Void { } static function bar( s : String, v : Bool ) : Void { } }
Переменные и методы могут иметь следующие флаги :
- static : поле принадлежит классу, а не его экземплярам. Внутри класса, статические идентификаторы могут быть использованы как есть, снаружи они должны использоваться вместе с именем класса (например :
my.pack.MyClass.name). - dynamic: поле можно связать динамически (во время выполнения)
- override: поле переопределяется в дочернем классе
- public : поле доступно извне
- private : доступ к полю ограничен самим классом и его дочерними классами (подробнее ниже). Это гарантирует, что внутреннее состояния класса недоступно (инкапсуляция).
По умолчанию - все поляprivate. Оно соответствует ключевому слову protected в большинстве других языков, как, например, в Java или PHP
Все переменные класса должны быть объявлены вместе с типом (можно использовать Dynamic, если вы не знаете, какой тип использовать). Типы аргументов функций и тип возвращаемого значения опциональны, но все равно строго проверяются, как мы увидим в разделе вывод типов.
Нестатические переменные не могут иметь инициализируещее (начальное) значение. Статические переменные могут, но не обязаны иметь инициализируещее значение.
Конструктор
У класса может быть единственный конструктор, нестатическая функция под названием new. Хотя это ключевое слово, им можно назвать функцию класса :
class Point { public var x : Int; public var y : Int; public function new() { this.x = 0; this.y = 0; } }
Параметры и перегрузка конструкторов :
public function new( x : Int, ?y : Int ) { this.x = x; this.y = (y == null) ? 0 : y; // "y" is optional }
Наследование
При объявлении класса можно унаследовать его от родительского с помощью ключевого слова extends, либо объявить что класс реализует некоторые классы или интерфейсы с помощью ключевого слова implements. Это означает, что класс унаследует несколько типоводновременно, и с ним может будет обращаться как с этими типами. К примеру:
class D extends A, implements B, implements C { }
Каждый экземпляр D будет иметь тип D, но его можно использовать там, где требуется экземпляр типа A, B или C. Значит любой экземпляр D также имеет типы A , B и C.
Extends
Когда для класса задан extends, он наследуется от всех нестатических public и private полей. Вы можете их использовать в своем классе, как если бы они были в нем объявлены. Вы также можете переопределить метод с помощью override, объявив его с тем же количеством и типами аргументов, как в родительском классе. Класс не может унаследовать статические поля.
Когда метод переопределен (перекрыт), вы можете обратиться к методу родительского класса, используя ключевое слово super :
class B extends A { override function foo() : Int { return super.foo() + 1; } }
Используя ''super', в конструкторе класса вы можете вызвать конструктор родительского класса :
class B extends A { function new() { super(36,""); } }
Implements
Когда вы реализуете (implements класс или интерфейс, ваш класс обязан реализовать все поля, объявленные или унаследованные реализуемым классом, с тем же типом и именем - если поле уже не унаследовано от родительского.
Интерфейсы
Интерфейс - абстрактный тип данных. Он объявляется с помощью ключевого слова interface. Все поля интерфейса по умолчанию public. Интерфейсы нельзя инстанцировать (нельзя создать экземпляр).
interface PointProto { var x : Int; var y : Int; function length() : Int; }
Интерфейс может в свою очередь реализовать (implements) один или несколько интерфейсов :
interface PointMore implements PointProto { function distanceTo( p : PointProto ) : Float; }
Вспомогательные классы (Helpers)
В Haxe возможно в одном файле класса создать несколько определений класса:
// оба определения находятся в файле Foo.hx class Foo { ... } class FooHelper { ... }
Это довольно обычно для объектно-ориентированных языков (например Java). Однако, в отличие от других языков, Haxe позволяет этим внутренним классам быть доступными публично вне основного класса. При импорте основного класса, вспомогательный становится доступен извне:
// в файле Bar.hx import Foo; class Bar{ var b:FooHelper; }
Этот вспомогательный класс также можно сделать доступным с помощью расширенного синтаксиса объявления пакетов:
// в файле Bar.hx class Bar{ var b:Foo.FooHelper; }
Во многих языках, использование публичных вспомогательных классов обычно не рекомендуется. Так как вспомогательному классу не соответствует имя файла .hx, его сложнее найти в дереве исходного кода.
HaXe дает возможность пометить вспомогательный класс как private:
// оба объявления в Foo.hx class Foo { ... } private class FooHelper { ... }
Это закроет вспомогательный класс от доступа вне основного класса.
Если у вас нет особых причин, размещайте каждое публичное определение класса в отдельном .hx файле, или делайте вспомогательные классы приватными, помните о возможном конфликте имен.
«« Определение типа - Параметры классов »»