DESIGN PATTERNS IN RUBY
Bài đăng này đã không được cập nhật trong 9 năm
Khái quát
Trong phát triển phần mềm hiện đại, kiến trúc tổng thể của dự án đóng một vai trò quan trọng, đặc biệt với bộ khung (framework) và mẫu thiết kế (design pattern). Bài viết này sẽ giúp các bạn hiểu được một cách tổng quan về pattern cũng như cách thức thiết kế một số pattern tiêu biểu.
Pattern là gì?
Pattern mô tả một giải pháp chung đối với một vấn đề nào đó trong thiết kế thường được “lặp lại” trong nhiều dự án. Nói một cách khác, một pattern có thể được xem như một “khuôn mẫu” có sẵn áp dụng được cho nhiều tình huống khác nhau để giải quyết một vấn đề cụ thể. Trong bất kỳ hệ thống phần mềm hướng đối tượng nào chúng ta cũng có thể bắt gặp các vấn đề lặp lại.
- Đặc điểm chung:
Pattern được hiểu theo nghĩa tái sử dụng ý tưởng hơn là mã lệnh. Pattern cho phép các nhà thiết kế có thể cùng ngồi lại với nhau và cùng giải quyết một vấn đề nào đó mà không phải mất nhiều thời gian tranh cãi.
Trong rất nhiều trường hợp, dự án phần mềm thất bại là do các nhà phát triển không có được sự hiểu biết chung trong các vấn đề về kiến trúc phần mềm. Ngoài ra, pattern cũng cung cấp những thuật ngữ và khái niệm chung trong thiết kế. Nói một cách đơn giản, khi đề cập đến một pattern nào đấy, bất kỳ ai biết pattern đó đều có thể nhanh chóng hình dung ra “bức tranh” của giải pháp.
Và cuối cùng, nếu áp dụng pattern hiệu quả thì việc bảo trì phần mềm cũng được tiến hành thuận lợi hơn, nắm bắt kiến trúc hệ thống nhanh hơn.
Pattern hỗ trợ tái sử dụng kiến trúc và mô hình thiết kế phần mềm theo quy mô lớn. Cần phân biệt design pattern với framework. Framework hỗ trợ tái sử dụng mô hình thiết kế và mã nguồn ở mức chi tiết hơn. Trong khi đó, design pattern được vận dụng ở mức tổng quát hơn, giúp các nhà phát triển hình dung và ghi nhận các cấu trúc tĩnh và động cũng như quan hệ tương tác giữa các giải pháp trong quá trình thiết kế ứng dụng đối với một chuyên khu riêng biệt.
Pattern đa tương thích. Pattern không phụ thuộc vào ngôn ngữ lập trình, công nghệ hoặc các nền tảng lớn như J2EE của Sun hay Microsoft .NET Framework.
Tiềm năng ứng dụng của pattern là rất lớn. Các thiết kế dựa trên pattern được sử dụng khá nhiều ở các phần mềm mã nguồn mở, trong nền tảng J2EE hoặc .NET…
Trong các dạng ứng dụng này, có thể dễ dàng nhận ra một số tên lớp chứa các tiền tố hoặc hậu tố như Factory, Proxy, Adapter… PHÂN LOẠI PATTERN Pattern được phân loại ra làm 3 nhóm chính sau đây:
• Nhóm cấu thành (Creational Pattern): Gồm Factory, Abstract Factory, Singleton, Prototype,Builder… Liên quan đến quá trình khởi tạo đối tượng cụ thể từ một định nghĩa trừu tượng (abstract class, interface).
• Nhóm cấu trúc tĩnh (Structural Pattern): Gồm Proxy, Adapter, Wrapper, Bridge, Facade, Flyweight, Visitor… Liên quan đến vấn đề làm thế nào để các lớp và đối tượng kết hợp với nhau tạo thành các cấu trúc lớn hơn.
• Nhóm tương tác động (Behavioral Pattern): Gồm Observer, State, Command, Iterator… Mô tả cách thức để các lớp hoặc đối tượng có thể giao tiếp với nhau.
Do Patterns không phụ thuộc vào Ngôn ngữ nên Việc ứng dụng các Partterns trong Ruby cũng khá dễ dàng Với ruby thì một số Pattern đã được xây dựng sẵn trong lớp thư viện của ruby nên chúng ta khá dễ dàng để sử dụng
ví Dụ đối với Singletton Pattern. là một pattern khá là quan trọng trong việc tạo ra một object duy nhất của một class trong suốt quá trình thực thi của một ứng dụng
require 'singleton'
class AppConfig
include Singleton
attr_accessor :data
def version
'1.0.0'
end
end
AppConfig.instance.data = {enabled: true}
=> {:enabled=>true}
AppConfig.instance.version
=> "1.0.0"
second = AppConfig.instance
second.data = {enabled: false}
=> {:enabled=>false}
AppConfig.instance.data
=> {:enabled=>false}
Và một ví dụ khác về Observe Patterns. một patterns thiết kế cho solution cho việc thông báo cho các objects reference khác khi có sự thay đổi từ object subject
require "observer"
class Ticker ### Periodically fetch a stock price.
include Observable
def initialize(symbol)
@symbol = symbol
end
def run
lastPrice = nil
loop do
price = Price.fetch(@symbol)
print "Current price: #{price}\n"
if price != lastPrice
changed # notify observers
lastPrice = price
notify_observers(Time.now, price)
end
sleep 1
end
end
end
class Price ### A mock class to fetch a stock price (60 - 140).
def Price.fetch(symbol)
60 + rand(80)
end
end
class Warner ### An abstract observer of Ticker objects.
def initialize(ticker, limit)
@limit = limit
ticker.add_observer(self)
end
end
class WarnLow < Warner
def update(time, price) # callback for observer
if price < @limit
print "--- #{time.to_s}: Price below #@limit: #{price}\n"
end
end
end
class WarnHigh < Warner def update(time, price) # callback for observer if price > @limit
print "+++ #{time.to_s}: Price above #@limit: #{price}\n"
end
end
end
ticker = Ticker.new("MSFT")
WarnLow.new(ticker, 80)
WarnHigh.new(ticker, 120)
ticker.run
KL. nói chung trong ngôn ngữ ruby hầu hết các patterns đã được design sẵn trong thư viện chúng ta chủ yếu là chỉ cần học cách sử dụng chúng để phục vụ cho nhu cầu xây dựng mô hình hệ thống theo cách dễ dàng sửa chữa nâng cấp và giải quyết các yêu cầu bài toán một cách nhanh chóng nhất có một số trang web tham khảo về design pattern khá hay chia sẻ với mọi ngừoi
và có một cuốn sách về design pattens trong ruby cũng khá hay là “Design patterns in Ruby” của tác giả Russ Olsen
All rights reserved