Как реализовать шаблон посетителя в F #, не ограничиваясь одним файлом? - PullRequest
3 голосов
/ 25 июня 2019

Следующий пример кода демонстрирует реализацию шаблона посетителя в F #

module VisitorPattern

    type IVisitor =
        abstract Visit : ObjectA -> unit
        abstract Visit : ObjectB -> unit

    and IVisitable =
        abstract InvokeVisit : IVisitor -> unit

    and ObjectA =
        interface IVisitable with
            member this.InvokeVisit (visitor: IVisitor) =
                visitor.Visit(this)

    and ObjectB =
        interface IVisitable with
            member this.InvokeVisit (visitor: IVisitor) =
                visitor.Visit(this)

    type MyVisitor =
        member this.Visit (a : ObjectA) =
            printfn "Visited object A"

        member this.Visit (b : ObjectB) =
            printfn "Visited object B"

Это прекрасно компилируется, но мы ограничены тем, что все типы, реализующие IVisitable в одном файле, из-за использования ключевого слова and. Это ключевое слово, по-видимому, необходимо для учета взаимных ссылок типов.

Есть ли способ реализовать этот шаблон таким образом, чтобы мы не были ограничены одним файлом?

(я не спрашиваю мнения о том, следует ли использовать этот шаблон в F #)

РЕДАКТИРОВАТЬ: я задаю этот вопрос, потому что шаблон посетителей имеет отношение при взаимодействии с кодом C #.

Ответы [ 2 ]

6 голосов
/ 25 июня 2019

Сопоставление с образцом должно достигать той же цели с долей сложности и накладных расходов. По моему личному опыту, это лучший способ реализовать шаблон посетителя в F #.

type Visitor = A of int | B of int

match a with 
| A x -> 1 * x
| B x -> 2 * x

тогда для некоторого возможного C #

private static void Main()
{
    Visitor a = Visitor.A(7)
    switch(a){
        case Visitor.A x:
            x.Item * 1;
            break;
        case Visitor.B x:
            x.Item * 2;
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }
}
0 голосов
/ 27 июня 2019

Если вам действительно нужно использовать ОО-шаблоны для взаимодействия C #, я считаю, что лучший способ отделить типы - это использовать дженерики:

module VisitorPattern =

    type IVisitor<'T> =
        abstract Visit : 'T -> unit

    type IVisitable<'T> =
        abstract InvokeVisit : IVisitor<'T> -> unit

module Visitors =

    open VisitorPattern

    type ObjectA () =
        interface IVisitable<ObjectA> with
            member this.InvokeVisit (visitor : IVisitor<ObjectA>) =
                visitor.Visit this

    type ObjectB () =
        interface IVisitable<ObjectB> with
            member this.InvokeVisit (visitor : IVisitor<ObjectB>) =
                visitor.Visit this
...