Интерфейсы (F#)
Интерфейсы задают наборы связанных членов, реализуемых в других классах.
// Interface declaration:
[ attributes ]
type interface-name =
[ interface ]
[ inherit base-interface-name ...]
abstract member1 : [ argument-types1 -> ] return-type1
abstract member2 : [ argument-types2 -> ] return-type2
...
[ end ]
// Implementing, inside a class type definition:
interface interface-name with
member self-identifier.member1 argument-list = method-body1
member self-identifier.member2 argument-list = method-body2
// Implementing, by using an object expression:
[ attributes ]
let class-name (argument-list) =
{ new interface-name with
member self-identifier.member1 argument-list = method-body1
member self-identifier.member2 argument-list = method-body2
[ base-interface-definitions ]
}
member-list
Заметки
Объявление интерфейса похоже на объявление класса, с той лишь разницей, что в нем не реализуются члены.Все члены являются абстрактными, о чем указывает ключевое слово abstract.Для абстрактных методов не предоставляется основная часть метода.Впрочем, можно добавить реализацию по умолчанию, дополнительно указав отдельное определение члена как метода с ключевым словом default.Этот прием аналогичен созданию виртуального метода в базовом классе в других языках .NET.Этот виртуальный метод нельзя переопределять в классах, реализующих интерфейс.
Существует два способа реализации интерфейсов: с помощью выражений объектов и с помощью типов классов.И в том и в другом случае тип класса или выражение объекта содержит основные части методов для абстрактных методов интерфейса.Способ реализации зависит от типа, в котором реализуется интерфейс.Поэтому методы интерфейса, реализованные в различных типах, могут отличаться друг от друга.
При использовании упрощенного синтаксиса можно опустить ключевые слова interface и end, отмечающие начало и конец определения.При отсутствии этих ключевых слов компилятор пытается определить, является ли тип классом или интерфейсом, анализируя языковые конструкции.Если имеется определение члена или другой прием из синтаксиса класса, тип определяется как класс.
Стиль написания кода .NET предписывает начинать имена интерфейсов с заглавной буквы I.
Реализация интерфейсов с помощью типов классов
Можно реализовать один или насколько интерфейсов в типе класса, указав ключевое слово interface, имя интерфейса и ключевое слово with, затем указав определения членов интерфейса, как показано в следующем коде.
type IPrintable =
abstract member Print : unit -> unit
type SomeClass1(x: int, y: float) =
interface IPrintable with
member this.Print() = printfn "%d %f" x y
Реализации интерфейсов наследуются, поэтому их не нужно заново реализовывать в производных классах.
Вызов методов интерфейса
Методы интерфейса можно вызывать только через сам интерфейс, а не через объекты или типы, в которых они реализованы.Поэтому для вызова этих методов может потребоваться выполнить приведение к типу интерфейса (с повышением по иерархии) с помощью оператора :> или upcast.
Чтобы вызвать метод интерфейса для объекта типа SomeClass, необходимо привести этот объект к типу интерфейса, как показано в следующем коде.
let x1 = new SomeClass1(1, 2.0)
(x1 :> IPrintable).Print()
Или же можно объявить метод, приводящий объект к требуемому типу и вызывающий метод интерфейса, как показано в следующем примере.
type SomeClass2(x: int, y: float) =
member this.Print() = (this :> IPrintable).Print()
interface IPrintable with
member this.Print() = printfn "%d %f" x y
let x2 = new SomeClass2(1, 2.0)
x2.Print()
Реализация интерфейсов с помощью выражений объектов
Выражения объектов обеспечивают простой способ реализации интерфейсов.Их удобно использовать при отсутствии именованного типа, когда требуется только получить объект, поддерживающий методы интерфейса (без дополнительных методов).Пример использования выражения объекта показан в следующем коде.
let makePrintable(x: int, y: float) =
{ new IPrintable with
member this.Print() = printfn "%d %f" x y }
let x3 = makePrintable(1, 2.0)
x3.Print()
Наследование интерфейса
Интерфейсы способны наследовать от одного или нескольких базовых интерфейсов.
type Interface1 =
abstract member Method1 : int -> int
type Interface2 =
abstract member Method2 : int -> int
type Interface3 =
inherit Interface1
inherit Interface2
abstract member Method3 : int -> int
type MyClass() =
interface Interface3 with
member this.Method1(n) = 2 * n
member this.Method2(n) = n + 100
member this.Method3(n) = n / 10