可重复的模式匹配 [英] Repeatable pattern matching

查看:102
本文介绍了可重复的模式匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的简单例子。

 类型PaymentInstrument = 
|检查字符串
| CreditCard的字符串* DateTime

让printInstrumentName instrument =

匹配仪器|支票号码> printfn检查
| CreditCard(number,expirationDate) - > printfncard

让printRequisites乐器=
将乐器与
匹配|支票号码 - > printfn检查%s号码
| CreditCard(number,expirationDate) - > printfncard%s%Anumber expirationDate

正如您所看到的,重复相同的模式匹配逻辑在两个功能。如果我使用OOP,我将创建接口 IPaymentInstrument ,定义两个操作:

PrintInstrumentName PrintRequisites



然后实施类 - 每个付款工具一个类。根据外部条件来实例化工具,例如工厂模式( PaymentInstrumentFactory )。

如果我需要添加新的支付工具,我只需要添加一个实现 IPaymentInstrument 接口的新类并更新工厂实例化逻辑。其他使用这些类的代码保持不变。



但是,如果我使用函数式方法,我应该更新每个函数,其中此类型的模式匹配存在。



如果使用 PaymentInstrument 类型的函数会有很多问题。



如何使用函数式方法来消除这个问题?

解决方案

到这样的设计决定。

 类型PaymentInstrument = 
|检查字符串
| CreditCard字符串* DateTime

类型操作=
{
PrintInstrumentName:单位 - >单位
PrintRequisites:单位 - >单位
}

让getTypeOperations乐器=
将乐器与
匹配|支票号码>
让printCheckNumber()= printfncheck
让printCheckRequisites()= printfncheck%s号码
{PrintInstrumentName = printCheckNumber; PrintRequisites = printCheckRequisites}
| CreditCard(number,expirationDate) - >
让printCardNumber()= printfncard
让printCardRequisites()= printfncard%s%Anumber expirationDate
{PrintInstrumentName = printCardNumber; PrintRequisites = printCardRequisites}

和用法

  let card = CreditCard(124,DateTime.Now)
let operations = getTypeOperations card
operations.PrintInstrumentName()
operations.PrintRequisites()

您可以看到 getTypeOperations 函数执行工厂模式的作用。为了聚合一组函数,我使用简单的记录类型(但是,根据F#设计准则, http: //fsharp.org/specs/component-design-guidelines/ 接口比这样的决定更受欢迎,但我有兴趣用功能性方法来做,以便更好地理解它)。



我得到了我想要的 - 模式匹配现在只有一个地方。


Consider the following simple example.

type PaymentInstrument =
    | Check of string
    | CreditCard of string * DateTime

let printInstrumentName instrument = 
    match instrument with 
    | Check number-> printfn "check"
    | CreditCard (number, expirationDate) -> printfn "card"

let printRequisites instrument =
    match instrument with 
    | Check number -> printfn "check %s" number
    | CreditCard (number, expirationDate) -> printfn "card %s %A" number expirationDate

As you can see the same pattern matching logic is repeated in two functions. If I would use OOP I would create interface IPaymentInstrument, define two operations:

PrintInstrumentName and PrintRequisites

and then implement classes - one per payment instrument. To instantiate instrument depending on some external conditions I would use (for example) the factory pattern (PaymentInstrumentFactory).

If I would need to add a new payment instrument, I just need to add a new class which implements IPaymentInstrument interface and update factory instantiating logic. Other code that uses these classes remains as is.

But if I use the functional approach I should update each function where pattern matching on this type exists.

If there will be a lot of functions using PaymentInstrument type that will be a problem.

How to eliminate this problem using functional approach?

解决方案

Using Mark Seemann's answer I came to such design decision.

type PaymentInstrument =
    | Check of string
    | CreditCard of string * DateTime

type Operations =
    { 
      PrintInstrumentName : unit -> unit
      PrintRequisites : unit -> unit
    }

let getTypeOperations instrument =
    match instrument with 
    | Check number-> 
        let printCheckNumber () = printfn "check"
        let printCheckRequisites () = printfn "check %s" number
        { PrintInstrumentName = printCheckNumber; PrintRequisites = printCheckRequisites }
    | CreditCard (number, expirationDate) -> 
        let printCardNumber () = printfn "card"
        let printCardRequisites () = printfn "card %s %A" number expirationDate
        { PrintInstrumentName = printCardNumber; PrintRequisites = printCardRequisites }

And usage

let card = CreditCard("124", DateTime.Now)
let operations = getTypeOperations card
operations.PrintInstrumentName()
operations.PrintRequisites()

As you can see the getTypeOperations function executes the role of factory pattern. To aggregate functions in a one bunch I use simple record type (however, according to F# design guidelines http://fsharp.org/specs/component-design-guidelines/ interfaces are preferred to such decision but I am interested to do it in functional approach for now to understand it better).

I got what I wanted - pattern matching is in only one place for now.

这篇关于可重复的模式匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆