如何使用 F# 實現 Proxy Pattern?

栏目: ASP.NET · 发布时间: 6年前

内容简介:Proxy Pattern 是 OOP 中著名的 Design Pattern,尤其可在不改變 interface 的前提下,就能控制該物件的使用,F# 既然是 Function First Language,就讓我們以 function 的角度重新實現 Proxy Pattern。macOS High Sierra 10.13.3.NET Core SDK 2.1.101

Proxy Pattern 是 OOP 中著名的 Design Pattern,尤其可在不改變 interface 的前提下,就能控制該物件的使用,F# 既然是 Function First Language,就讓我們以 function 的角度重新實現 Proxy Pattern。

Version

macOS High Sierra 10.13.3

.NET Core SDK 2.1.101

JetBrains Rider 2017.3.1

F# 4.1

User Story

假設你在處理訂單,只有會員才能享受 全館八折 ,其他人都只能原價購買。

  • 目前已經有 MemberService.isMember() 判斷是否為會員
  • 目前已經有 OrderService.getPrice() 可根據折購計算售價
  • MemberService.isMember()OrderService.getPrice() 不修改的前提下 ( 開放封閉原則 ),計算出售價

Task

直接使用 FP 的思維完成需求。

Definition

Decorator Pattern

在不改變原有 interface 的前提下,控制 service 的使用

如何使用 F# 實現 Proxy Pattern?

首先思考 Proxy Pattern 的本質:

  1. Proxy 與 RealSubject 之間的 interface 必須相同
  2. Client 藉由 Proxy 控制 RealSubject 的使用

只要能達到這兩個目標,就算完成了 Decorator Pattern。

OOP 思考方式

  • 為了讓 Proxy 與 RealSubject 的 interface 要相同,所以必須訂出共同的 interface
  • Proxy 必須以 state 記住 RealSubject,client 才能透過 Proxy 使用 RealSubject
  • Proxy 可以加上邏輯,控制 RealSubject 的使用

FP 思考方式

  • Proxy 與 RealSubject 都是 function,不用事先定義 interface,反正只要 interface 不同,在 if … elsePattern Matchingtry catch 一定會錯
  • Proxy 與 RealSubject 都是 function,既然 interface 都相同,由 RealSubject 切換到 Proxy 就不用修改程式碼
  • Proxy function 可加上邏輯,控制 RealSubject function 的使用

Implementation

MemberService.fs

namespace MemberLibrary

module MemberService =
    let isMember account = account = "Sam"

isMember() 判斷是否為 會員

實務上判斷 是否為會員 與資料庫有關,本文主要是談 Proxy Pattern,就只簡單的判斷會員是否為 Sam 即可。

OrderService.fs

namespace OrderLibrary

module OrderService =
    let getPrice discount price = price * discount * 1.0

計算 全館八折 ,之所以加上 * 1.0 ,是為了讓 Type Inference 推導出 discountprice 的型別為 float

當使用 function pipeline 時,最後一個參數可以自動被 pipeline,所以設計 function parameter 時,將要使用 pipeline 的 value 放在最後一個 parameter,才能發揮 pipeline 的優勢

Program.fs

open MemberLibrary
open OrderLibrary
open System

[<EntryPoint>]
let main argv =
    let account = "Sam"
    let originalPrice = 800.0
    let discount = 0.8
    
    let isMember = MemberService.isMember account
    
    let orderProxy =
        match isMember with
        | true  -> OrderService.getPrice
        | false -> fun _ price -> price 
    
    originalPrice
    |> orderProxy discount
    |> printf "Real price : %0.0f"        

    0 // return an integer exit code

// Real price : 640

11 行

let isMember = MemberService.isMember account

由於會由 MemberService.isMember() 判斷是否為會員,先判斷並將結果 binding 到 isMember

13 行

let orderProxy =
    match isMember with
    | true  -> OrderService.getPrice
    | false -> fun _ price -> price

OrderProxy class 退化成 orderProxy() function,其 interface 仍然為 float -> float -> float ,Type Inference 會自動推導,若有違反,Pattern Match 就會報錯。

orderProxy() 本質為 function,由於 closure 機制,可以自然使用到 function 外面的 isMember ,因此不必使用 parameter 方式傳入。

Pattern Matching 根據 isMember 結果回傳 OrderService.getPrice() ,或者全新的 Lambda function。

| false -> fun _ price -> price

由於要 return 的 Lambda function 並沒有使用到 discount 計算,使用 _ 代表即可。

16 行

originalPrice
|> orderProxy discount
|> printf "Real price : %0.0f"

originalPrice 傳給 orderProxy() 計算,這是個已經考慮 是否為會員orderService() ,最後再傳給 printf() 顯示。

Summary

回想 Proxy Pattern 的本質:

  1. Proxy 與 RealSubject 之間的 interface 必須相同
  2. Client 藉由 Proxy 控制 RealSubject 的使用

雖然沒有特別定義 interface,但 orderProxy()OrderService.getPrice() 的 signature 都是 float -> float -> float ,若 function 的 signature 不同,在 Pattern Matching 就會編譯錯誤,與原本 Proxy Pattern 定義 interface 的本質相同。

FP 則藉由 Proxy Function 控制 RealSubject function 的使用,與原本 Proxy Pattern 藉由 Proxy 控制 RealSubject 使用的本質相同。

Conclusion

  • Proxy Pattern 本質就是 delegation,但 object 的 delegation 沒 function 簡單直覺,所以才需要搭配 interface;但若純 function,連 interface 都不需要,而且也能享受 strong type 的編譯檢查

Sample Code

完整的範例可以在我的 GitHub 上找到


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++数值算法(第二版)

C++数值算法(第二版)

William T.Vetterling、Brian P.Flannery、Saul A.Teukolsky / 胡健伟、赵志勇、薛运华 / 电子工业出版社 / 2005年01月 / 68.00

本书选材内容丰富,除了通常数值方法课程的内容外,还包含当代科学计算大量用到的专题,如求特殊函数值、随机数、排序、最优化、快速傅里叶变换、谱分析、小波变换、统计描述和数据建模、常微分方程和偏微分方程数值解、若干编码算法和任意精度的计算等。 本书科学性和实用性统一。每个专题中,不仅对每种算法给出了数学分析和比较,而且根据作者的经验对算法做出了评论和建议,并在此基础上给出了用C++语言编写的实用程......一起来看看 《C++数值算法(第二版)》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具