F # - Interfaces

As interfaces fornecem uma maneira abstrata de escrever os detalhes de implementação de uma classe. É um modelo que declara os métodos que a classe deve implementar e expor publicamente.

Sintaxe

Uma interface especifica os conjuntos de membros relacionados que outras classes implementam. Possui a seguinte sintaxe -

// 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

Observe -

  • Em uma declaração de interface, os membros não são implementados.

  • Os membros são abstratos, declarados pelo abstractpalavra-chave. No entanto, você pode fornecer uma implementação padrão usando odefault palavra-chave.

  • Você pode implementar interfaces usando expressões de objeto ou tipos de classe.

  • Na implementação de classe ou objeto, você precisa fornecer corpos de método para métodos abstratos da interface.

  • As palavras-chave interface e end, que marcam o início e o fim da definição, são opcionais.

Por exemplo,

type IPerson =
   abstract Name : string
   abstract Enter : unit -> unit
   abstract Leave : unit -> unit

Métodos de interface de chamada

Os métodos de interface são chamados por meio da interface, não por meio da instância da classe ou interface de implementação de tipo. Para chamar um método de interface, você elimina o tipo de interface usando o:> operador (operador upcast).

Por exemplo,

(s :> IPerson).Enter()
(s :> IPerson).Leave()

O exemplo a seguir ilustra o conceito -

Exemplo

type IPerson =
   abstract Name : string
   abstract Enter : unit -> unit
   abstract Leave : unit -> unit

type Student(name : string, id : int) =
   member this.ID = id
   interface IPerson with
      member this.Name = name
      member this.Enter() = printfn "Student entering premises!"
      member this.Leave() = printfn "Student leaving premises!"

type StuffMember(name : string, id : int, salary : float) =
   let mutable _salary = salary

   member this.Salary
      with get() = _salary
      and set(value) = _salary <- value

   interface IPerson with
      member this.Name = name
      member this.Enter() = printfn "Stuff member entering premises!"
      member this.Leave() = printfn "Stuff member leaving premises!"

let s = new Student("Zara", 1234)
let st = new StuffMember("Rohit", 34, 50000.0)

(s :> IPerson).Enter()
(s :> IPerson).Leave()
(st :> IPerson).Enter()
(st :> IPerson).Leave()

Quando você compila e executa o programa, ele produz a seguinte saída -

Student entering premises!
Student leaving premises!
Stuff member entering premises!
Stuff member leaving premises!

Herança de interface

As interfaces podem herdar de uma ou mais interfaces básicas.

O exemplo a seguir mostra o conceito -

type Interface1 =
   abstract member doubleIt: int -> int

type Interface2 =
   abstract member tripleIt: int -> int

type Interface3 =
   inherit Interface1
   inherit Interface2
   abstract member printIt: int -> string

type multiplierClass() =
   interface Interface3 with
      member this.doubleIt(a) = 2 * a
      member this.tripleIt(a) = 3 * a
      member this.printIt(a) = a.ToString()

let ml = multiplierClass()
printfn "%d" ((ml:>Interface3).doubleIt(5))
printfn "%d" ((ml:>Interface3).tripleIt(5))
printfn "%s" ((ml:>Interface3).printIt(5))

Quando você compila e executa o programa, ele produz a seguinte saída -

10
15
5