Cho một ứng dụng ASP.NET MVC với các lớp sau:Khi nào cần sử dụng giao diện và khi nào cần sử dụng các chức năng bậc cao hơn?
- UI (Lượt xem, CSS, Javascript, vv)
- Controller
- Dịch vụ (Có logic kinh doanh và truy cập dữ liệu)
Lý do không có lớp truy cập dữ liệu riêng biệt, là tôi đang sử dụng nhà cung cấp loại SQL.
(Mã sau có thể không hoạt động vì nó chỉ là bản nháp thô). Bây giờ hãy tưởng tượng một dịch vụ có tên UserService
được xác định như sau:
module UserService =
let getAll memoize f =
memoize(fun _ -> f)
let tryGetByID id f memoize =
memoize(fun _ -> f id)
let add evict f name keyToEvict =
let result = f name
evict keyToEvict
result
Và sau đó trong lớp điều khiển của tôi, tôi sẽ có mô-đun khác tên UserImpl
hoặc nó có thể chỉ cũng được đặt tên UserMemCache
:
module UserImpl =
let keyFor = MemCache.keyFor
let inline memoize args =
MemCache.keyForCurrent args
|> CacheHelpers.memoize0 MemCache.tryGet MemCache.store
let getAll = memoize [] |> UserService.getAll
let tryGetByID id = memoize [id] |> UserService.tryGetByID id
let add =
keyFor <@ getAll @> [id]
|> UserService.add MemCache.evict
Các việc sử dụng điều này sẽ như sau:
type UserController() =
inherit Controller()
let ctx = dbSchema.GetDataContext()
member x.GetAll() = UserImpl.getAll ctx.Users
member x.UserNumberOne = UserImpl.tryGetByID ctx.Users 1
member x.UserNumberTwo = UserImpl.tryGetByID ctx.Users 2
member x.Add(name) = UserImpl.add ctx.Users name
Sử dụng giao diện, chúng tôi sẽ thực hiện như sau:
type UserService(ICacheProvider cacheProvider, ITable<User> db) =
member x.GetAll() =
cacheProvider.memoize(fun _ -> db |> List.ofSeq)
member x.TryGetByID id =
cacheProvider.memoize(fun _ -> db |> Query.tryFirst <@ fun z -> z.ID = ID @>)
member x.Add name =
let result = db.Add name
cacheProvider.evict <@ x.GetAll() @> []
result
Và việc sử dụng sẽ là một cái gì đó như:
type UserController(ICacheProvider cacheProvider) =
inherit Controller()
let ctx = dbSchema.GetDataContext()
let userService = new UserService(cacheProvider, ctx.Users)
member x.GetAll() = userService.GetAll()
member x.UserNumberOne = userService.TryGetByID 1
member x.UserNumberTwo = userService.TryGetByID 2
Rõ ràng việc thực hiện giao diện còn ít nhiều mã, nhưng nó không thực sự cảm thấy như mã chức năng nữa. Nếu tôi bắt đầu sử dụng giao diện trong suốt ứng dụng web của mình, khi nào tôi biết khi nào nên sử dụng các hàm bậc cao hơn thay thế? - nếu không tôi sẽ kết thúc bằng một giải pháp OOP cũ.
Vì vậy, trong ngắn hạn: Khi nào giao diện nên được sử dụng và khi nào nên sử dụng các hàm bậc cao hơn? - một số dòng đã được rút ra, hoặc tất cả sẽ là các loại và giao diện, trong đó vẻ đẹp của FP biến mất.
Tôi đã viết một vài suy nghĩ về vấn đề này trên blog của tôi, cố gắng làm rõ mối quan hệ giữa các đối tượng và chức năng bậc cao trong số những thứ khác: http://bugsquash.blogspot.com/2013/08/objects-and-functional-programming.html –