Объектно-ориентированное программирование

Классы

Вкратце посмотрим на структуру классов в 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 файле, или делайте вспомогательные классы приватными, помните о возможном конфликте имен.

«« Определение типа - Параметры классов »»

version #10151, modified 2011-02-11 11:53:00 by Scythian