Facade design pattern trong Ruby on Rails
Bài đăng này đã không được cập nhật trong 6 năm
Cung cấp một Interface thống nhất cho một tập hợp các Interfaces trong một hệ thống con. Facade định nghĩa một Interface cấp cao hơn làm cho hệ thống con dễ sử dụng hơn Và nó là 1 phần của nhóm Structural Design Pattern.
Mình cũng mới tìm hiểu nó, và thấy khá hay ho, nên chia sẽ cùng mọi người !
Đặt ra vấn đề trong ROR:
Ruby On Rails được xây dựng và hoạt động dựa trên mô hình MVC ( Model-View-Controller ). Và ở đây View có trách nhiệm hiển thị dữ liệu. Model chịu trách nhiệm thao tác dữ liệu, và xử lý Logic, Cuối cùng Controller chịu trách nhiệm kết nối mọi thứ.
Nhưng chúng ta có thể thay trong nhiều dự án ROR thì Controller vẫn khá là yếu vì nó chuẩn bị khá là nhiều dữ liệu để show ra ở View mặc dù chúng ta đã có áp dụng Services để perform một vài hoạt động, hay cấu trúc lại Model để dễ thể hiện ở View hơn. Nhưng đôi khi từng đó là chưa đủ và Controller của chúng ta vẫn Béo lên theo từng ngày. Chẵng hạn như sau (code lượm lặt)
class UsersController < ApplicationController
def index
@user = User.new
@last_active_users = User.active.order(created_at: :desc).limit(10)
@vip_users_presenter = VipUsersPresenter.new(User.active.vip)
@messages = current_user.messages
end
end
Như thế rất là nhiều object được khởi tạo. để có thể được show hay xử lý ở View
Giải pháp của Facade là gì?
Chúng ta có thể sử dụng Facade Desgin Pattern để loại bỏ việc chuẩn bị nhiều data cho tầng View và tạo ra một khuôn mẫu thống nhất và ẩn các thành phần đó đi.
Hãy thử là nhé: tạo 1 folder trong Project như sau app/facades
:
# app/facades/users_facade.rb
class UsersFacade
attr_reader :current_user, :vip_presenter
def initialize(current_user, vip_presenter=VipUsersPresenter)
@current_user = current_user
@vip_presenter = vip_presenter
end
def new_user
User.new
end
def last_active_users
@last_active_users ||= active_users.order(created_at: :desc).limit(10)
end
def vip_users
@vip_users ||= vip_presenter.new(active_users.vip).users
end
def messages
@messages ||= current_user.messages
end
private
def active_users
User.active
end
end
Như thế các bạn có thể nhìn thấy rằng:
- Chúng ta đã chuyển các data chuẩn bị cho View và trong UsersFacade
- Chúng ta đã có caching một số data trong trường hợp view muốn sử dụng lại.
- Chúng ta áp dụng một vài cơ chế như includes và ** Dependency injection** với VipUsersPresenter
Và giờ đây Controller của chúng ta lại suy dinh dưỡng như thế này đây:
class UsersController < ApplicationController
def index
@user_facade = UsersFacade.new(current_user)
end
end
và áp dụng nó ở View thế này:
<%= render @user_facade.last_active_users %>
<%= render @user_facade.messages %>
<%= render 'users/form', user: @user_facade.new_user %>
<%= render @user_facade.vip_users %>
Tóm lại nó là gì? và để làm gì?
Facade pattern có thể giúp chúng ta là đơn giản cái Controller trong trường hợp nó ngày càng béo ra vì dự án ngày càng lớn dần. Nó dễ hơn trong việc Test vì dữ liệu được đóng gói lại theo 1 chuẩn.
Bên cạnh đó nó cũng có một số hạn chế Facade của bạn không được quá lớn. Bạn không nên chỉ sử dụng một Facade vì nó quá lớn sẽ khó tái sử dụng. Vì thế bạn nên thiết kế riêng từ Facade cho từng Controller
All rights reserved