Обрабатывать состояние с помощью функций FP / F # way - PullRequest
0 голосов
/ 10 января 2019

Вот некоторый интерфейс IOrderSender, который определяет бизнес-операцию (отправку заказа) с некоторой реализацией KafkaOrderSender (через производителя Kafka в этом примере).

Код был переписан с C # с сохранением оригинального стиля ООП:

type CustomerId = string

type IOrderSender =
    abstract SendOrders: CustomerId -> Order list -> unit

type KafkaOrderSender(config: IConfiguration) =
    let streamConfig = config.GetSection("OrderStream")

    let producerConfig = new ProducerConfig(BootstrapServers = streamConfig.GetValue("BootstrapServers"))
    let producer = new Producer<string, string>(producerConfig)

    let ordersTopic: string = streamConfig.GetValue("Topic")

    interface IOrderSender with
        member this.SendOrders customerId orders =
            for order in orders do
                let orderJson = JsonConvert.SerializeObject<Order>(order)
                let msg = new Message<string, string>(Key = customerId, Value = orderJson)
                do producer.BeginProduce(ordersTopic, msg)

    interface IDisposable with
        member this.Dispose() =
            do producer.Flush(CancellationToken.None)
            do producer.Dispose()

Здесь мы имеем:

  • интерфейс (IOrderSender)

  • реализация (KafkaOrderSender)

  • одна внешняя зависимость (IConfiguration)

  • внутреннее состояние (producer, необходимо разделить вызовы)

  • состояние должно быть закрыто / ликвидировано (IDisposable)

Этот интерфейс и реализация зарегистрированы в некотором контейнере DI (например, ASP.NET Core с Giraffe):

let configureServices (services : IServiceCollection) =
    services.AddGiraffe() |> ignore
    services.AddSingleton<IOrderSender, KafkaOrderSender>() |> ignore

Этот объект затем разрешается через DI и используется в логике приложения:

let handleOrders (customerId: CustomerId) (orders: Orders): HttpHandler =
    fun (next : HttpFunc) (ctx : HttpContext) ->
        // Resolve
        let orderSender = ctx.GetService<IOrderSender>()
        // Use
        do orderSender.SendOrders customerId orders
        return! text "OK" next ctx

Есть ли лучший способ реализовать IOrderSender более идиоматическим функциональным способом (модуль вместо класса, частичное применение вместо зависимостей через конструктор)?

Как обрабатывать общее состояние (производитель) и как реализовать удаление общего состояния в этом случае?

...