Implementing the MVVM pattern (Part 1)

Mẫu thiết kế MVVM đưa ra cách tách biệt rõ rệt giữa UI, presentation logic, business logic và dữ liệu của ứng dụng bằng cách tách thành các lớp riêng biệt. Các tương tác giữa View và ViewModel là phần quan trọng nhất để tìm hiểu, nhưng các tương tác giữa các model class và ViewModel cũng quan trọng không kém. Nội dung trình bày sau đây mô tả các pattern khác cho các tương tác này và mô tả cách thiết kế chúng khi bạn thực thi mẫu thiết kế MVVM trong các ứng dụng của bạn.

Data Binding

Kết buộc dữ liệu đóng một vai trò quan trọng trong MVVM. Cả WPF và Silverlight đề cung cấp những khả năng kết buộc dữ liệu mạnh mẽ. ViewModel và các model class của bạn có thể được thiết kế để hỗ trợ việc kết buộc dữ liệu để chúng có thể tận dụng những khả năng này của chúng. Thông thường, điều này có nghĩa là chúng phải thực thi đúng các interface.

Kết buộc dữ liệu của Silverlight và WPF hỗ trợ  nhiều chế độ kết buộc dữ liệu. Với việc kiết buộc “1 chiều” (one-way), các UI control có thể giới hạn cho một ViewModel để chúng có thể “phản chiếu” giá trị của dữ liệu bên dưới khi việc hiển thị được render. Kết buộc “2 chiều” (two-way) cũng sẽ tự động cập nhật dữ liệu bên dưới khi người dùng định nghĩa nó trong UI.

Để đảm bảo UI luôn được cập nhật khi dữ liệu thanh đối trong ViewModel, nó phải thực thi interface thông báo thay đổi tương ứng. Nếu nó định nghĩa các thuộc tính có thể là giới hạn dữ liệu, nó sẽ thực thi INotifyPropertyChanged interface. Nếu ViewModel mô tả một collection, nó sẽ thực thi INotifyCollectionChanged interface hoặc chuyến hóa từ lớp ObservableCollection<T> cung cấp cách thực thi của interface này. Cả hai interface này đều định nghĩa một sự kiện được đưa ra bất kể khi nào dữ liệu bên dưới thay đổi. Bất kì control giới hạn dữ liệu nào cũng sẽ được tự động cập nhật khi các sự kiện này được tạo ra.

Trong nhiều trường hợp, một ViewModel sẽ định nghĩa các thuộc tính trả về các đối tượng. Khả năng kết buộc dữ liệu trong WPF và Silverlight hỗ trợ kết buộc các thuộc tính lồng nhau thông qua thuộc tính Path. Hơn nữa, việc ViewModel của View trả về các tham chiếu đến ViewModel hoặc các model class khác là rất thường xuyên. Tất cả ViewModel và các model class có khả năng truy xuất đến View sẽ thực thi các interface INotifyPropertyChanged hoặc INotifyCollectionChanged tương ứng.

Implementing INotifyPropertyChanged

Việc thực thi INotifyPropertyChanged interface trong ViewModel hoặc các model class cho phép chúng cung cấp các thông báo thay đổi (change notification) đến bất kì control giới hạn dữ liệu nào (data-bound control) trong View khi giá trị của thuộc tính bên dưới thay đổi. Ví dụ (xem Questionnaire class trong demo)

questionnaire-class

Việc thực thi INotifyPropertyChanged interface trên nhiều ViewModel class có thể lăp lại và error-prone bởi việc cần thiết xác định tên thuộc tính trong tham số của sự kiện. Prism Library cung cấp một lớp cơ sở mà bạn có thể chuyển hóa các ViewModel class thực thi iNotifyPeropersyChanged interface

INotifyPropertyChanged

Một ViewModel class được kế thừa có thể tạo ra sự kiện thay đổi thuộc tính bằng việc thực thi RaisePropertyChanged với tên thuộc tính được xác định hoặc sử dụng một lamda expression để chỉ ra thuộc tính

RaisePropertyChanged

Thông thường, Model và ViewModel của bạn sẽ bao gồm các thuộc tính mà các giá trị của chúng được tính toán từ những thuộc tính khác trong Model hoặc ViewMode. Khi xử lý những thay đổi đối với các thuộc tính này phải đảm bảo rằng các sự kiện thông báo cũng phải được tạo ra cho bất kì thuộc tính được tính toán nào.

Implementing INotifyCollectionChanged

ViewModel hoặc Model class của bạn có thể mô tả một collection của các item, hoặc nó có thể định nghĩa một hoặc nhiều thuộc tính trả về một collection của các item. Trong các trường hợp này, bạn sẽ muốn hiển thị collection trong một ItemControl như ListBox hoặc DataGrid control trong View. Những control này có thể giới hạn dữ liệu cho một ViewModel mà mô tả một collection hoặc một thuộc tính trả về một collection thông qua thuộc tính ItemSource.

ItemSource-DataGrid

Để hỗ trợ các yều cầu thông báo thay đổi tức khắc, ViewModel hoặc Model class, nếu nó mô tả một collection, nên thực thi INotifyCollectionChanged interface (trong trường hợp khác có thể là INotifyPropertyChanged interface). Nếu ViewModel hoặc Model class xác định một thuộc tính mà trả về một tham chiếu đến một collection, collection class được trả về nên thực thi INotifyCollectionChanged interface.

Tuy nhiên, việc thực thi INotifyCollectionChanged interface có thẩ là thách thức vì nó cung cấp các notification khi các item được thêm vào, xóa (hủy) hoặc bị thay đổi trong collection. Thay vì thực thi trực tiếp interface này, nó thường dễ dàng sử dụng hoặc chuyển hóa từ một collection class thực thi nó rồi. ObservableCollection<T> class cung cấp một sự thực thi cho interface này và được sử dụng phổ biến như một lớp cơ sở hoặc thực thi các thuộc tính mô tả một collection của các item.

ObservableCollection

Nếu bạn có một tham chiếu đến một collection class (chẳng hạn như từ thành phần khác hoặc service không thực thi INotifyCollectionChanged), thông thường bạn có thể “gói’” trong một đối tượng ObservableCollection<T> sử dụng một trong các hàm dựng lấy một tham số IEnumerable<T> hoặc List<T>.

Implementing ICollectionView

Đoạn code trước cho thấy cách thực thi một thuộc tính ViewModel đơn giản trả về một collection các item có thể được hiển thị thông qua các control giới hạn dữ liệu trong View. Vì ObservableCollection<T> class thực thi INotifyCollectionChanged interface, các control trong View sẽ được tự động cập nhật để “chiếu’” danh sách các item trong collection khi các item được thêm vào hay bị xóa đi.

Tuy nhiên, thông thường bạn sẽ cần nhiều sự kiểm soát hơn về cách collection các item được hiển thị trong View, hoặc theo dõi sự tương tác của người dùng với collection các item được hiển thị trong bản thân ViewModel. Ví dụ, bạn có thể cần phải cho phép collection các item được chọn lọc hoặc sắp xếp theo presentation logic được thực thi trong View, hoặc bạn có thể cần theo dõi item được chọn hiện thời trong View để các câu lệnh được thực thi trong ViewModel có thể thực thi trên item được chọn đó.

WPF và Silverlight hỗ trợ những trường hợp này bằng việc cung cấp các class khác nhau thực thi ICollectionView interface. interface này cung cấp các thuộc tính và phương thức cho phép một collection được chọn lọc, sắp xếp hoặc gom nhóm lại, và cho phép item được chọn hiện tại được thay đổi hoặc được theo dõi. Cả WPF và Silverlight cung cấp các implementation cho interface này – Silverlight cung cấp PagedCollectionView class, WPF cung cấp ListCollectionView class.

Các collection view class có thể được sử dụng bởi ViewModel để theo dõi thông tin trạng thái quan trọng cho collection bên dưới, trong khi việc bảo trì một sự tách biệt rõ ràng của các mối quan tâm giữa UI trong View và dữ liệu bên dưới trong Model. Để hiệu quả, các CollectionView là các ViewModel được thiết kế đặc biệt để hỗ trợ các collection.

Hơn nữa, nếu bạn cần thực thi việc chọn lọc, sắp xếp, gom nhóm hoặc theo dõi các item được chọn trong ViewModel của bạn, ViewModel của bạn nên tạo ra một đối tượng của một view collection class cho mỗi collection được đưa đến View. Sau đó bạn có thể đăng kí các selection changed event chẳng hạn như CurrentChanged event, hoặc điều khiển việc chọn lọc, sắp xếp hoặc gom nhóm bằng cách sử dụng các phương thức được cung cấp bởi collection view class trong ViewModel của bạn.

ViewModel nên thực thi một thuộc tính chỉ đọc trả về một ICollectionView reference để các control trong View có thể kết buộc dữ lêệu vào collection view object và tương tác với nó. Tất cả control của WPF và Silverlight mà chuyển hóa từ ItemsControl base class có thể tự động tương tác với các ICollectionView class.

Đoạn code sau minh họa cho việc sử dụng PagedCollectionChanged trong Silverlight để theo dõi customer được chọn hiện tại.

PageCollectionChanged

Trong View, bạn có thể kết buộc một ItemsControl, chẳng hạn như ListBox, vào thuộc tính Customers trên ViewModel thông qua thuộc tính ItemsSource của nó.

Customers-ItemsSource

Khi người dùng chọn một customer trong UI, ViewModel sẽ được thông báo để nó có thể thực thi các câu lệnh liên quan đến customer được chọn hiện tại. ViewModel cũng có thể thay đổi theo như lập trình chọn lựa hiện tại trong UI bằng việc gọi các phương thức trên collection view object.

customer-next

Khi selection thay đổi trong collection view, UI tự động cập nhật để mô tả trạng thái được chọn của item. Việc thực thi cũng tương tự đối với WPF mặc dù PagedCollectionChanged trong ví dụ trước thông thường sẽ bị thay thế bằng một ListCollectionView hoặc BindingListCollectionView class.

customers-binding

MVVM Pattern (Lý thuyết)

Mẫu thiết kế Model-View-ViewModel (MVVM) giúp tách biệt lớp business và presentation của ứng dụng khỏi phần giao diện (UI) của nó. Việc duy trì phần tách biệt giữa lớp ứng dụng và UI giúp chỉ ra những vấn đề trong việc phát triển và thiết kế và có thể giúp ứng dụng của bạn trở nên dễ dàng để kiểm thử, bảo trì và phát triển hơn.

Bằng việc sử dụng mẫu thiết kế MVVM, phần giao diện (UI) của ứng dụng, presentation và business được tách thành 3 lớp riêng biệt: View bao hàm UI và UI logic (code behind); View Model bao hàm presentation và state; Model bao hàm business và data.

Các lớp trong MVVM và sự tương tác giữa chúng

IC448690

Tương tự như những mẫu thiết kế có sự tách biệt phần presentation khác, điểm mấu chốt trong việc sử dụng mẫu MVVM hiệu quả nằm ở việc hiểu cách thích hợp để tác động mã nguồn của chương trình vào đúng những lớp cần thiết, và hiểu những cách thức mà những lớp này tương tác trong những ngữ cảnh khác nhau.

View Class

Chịu trách nhiệm xác định cấu trúc và thể hiện những gì mà người dùng thấy trên màn hình. Trong trường hợp lý tưởng, phần code-behind của lớp View chỉ cần duy nhất một constructor gọi phương thức InitializeComponent. Trong một số trường hợp, code-behind có thể bao gồm đoạn mã UI logic thực thi visual behavior khó hoặc không hiệu quả để thể hiện trong XAML, chẳng hạn như các chuyển động phức tạp, hoặc khi mã nguồn cần tính toán một cách chính xác các thành phần hiển thị của view.

Trong Silverlight và WPF, các expression cho việc kết buộc dữ liệu (data bingding) trong view được thực hiện thông qua data context của nó. Trong MVVM, data context của nó được đặt cho view model. View model thực thi các thuộc tính (property) và các dòng lệnh (command) mà view có thể kết buộc và thông báo cho view biết mỗi khi có thay đổi thông qua các sự kiện thông báo thay đổi. Đó hoàn toàn là mối quan hệ một-một giữa view và view model của nó.

Nhìn chung, view là những lớp dẫn xuất Control (Control-derived classes) hoặc lớp dẫn xuất UserControl (UserControl-derived classes). Tuy nhiên, trong một số trường hợp, view có thể được đại diện bởi một mẫu dữ liệu (data template) xác định các thành phần giao diện (UI elements) được sử dụng để đại diện cho một đối tượng khi nó được hiển thị. Bằng việc sử dụng các mẫu dữ liệu (data template), người thiết kế (designer) có thể định nghĩa cách một view model được vẽ ra (render) như thế nào hoặc có thể chỉnh sửa phần mặc định của nó mà không phải thay đổi đối tượng bên dưới, hoặc hành vi của control được sử dụng để hiển thị.

Những mấu dữ liệu (data template) có thể xem như là các view mà không có phần code-behind. Chúng được thiết kế để kết buộc cho một kiểu view model xác định bất kể khi nào một view model được yêu cầu hiển thị ra giao diện bên ngoài. Vào thời điểm thực thi, view, đã được định nghĩa bởi mẫu dữ liệu, sẽ tự động được tạo và data context của nó được đưa vào view model tương ứng.

Trong WPF, bạn có thể liên kết một mẫu dữ liệu với một kiểu view model ở mức ứng dụng (application level). WPF sau đó sẽ tự động đưa mẫu dữ liệu này vào bất kì đối tượng view model của kiểu đã được định nghĩa bất kể khi nào chúng được hiển thị trên giao diện. Trong Silverlight, bạn phải định nghĩa rõ ràng mẫu dữ liệu cho một đối tượng view model bên trong control dùng để hiển thị nó.

Tóm lại, view có những đặc trưng chính sau:

– View là một thành phần tể hiện, như là cửa số window, page, user control hoặc mẫu dữ liệu. View định nghĩa những control được chứa trong view và khung hiển thị và kiểu của chúng.

– View tham chiếu view model thông qua thuộc tính DataContext của nó. Những control trong view là dữ liệu ràng buộc các thuộc tính và dòng lệnh được thực thi bởi view model.

– View có thể điều chính việc kết buộc dữ liệu giữa view và view model. Ví dụ, view có thể sử dụng các bộ chuyển đổi giá trị để định dạng dữ liệu được hiển thị trên giao diện, hoặc nó có thể sử dụng luật kiểm tra (validation rules) để kiểm tra dữ liệu người dùng nhập vào.

– View xác định và xử lý các hành vi (behavior) như là chuyển động hoặc chuyển tiếp được kích hoạt từ một sự thay đổi trạng thái trong view model hoặc thông qua sự tương tác giữa người dùng và giao diện.

– Code-behind của view có thể định nghĩa lớp giao diện để thực thi

ViewModel Class

ViewModel trong MVVM thực hiện việc tham chiếu các các” đối tượng” cần thiết cho View từ presentation logic và data. Không có bất kì tham chiếu trực tiếp nào đến View hoặc bất kì thông tin gì về việc implement cụ thể của View. ViewModel thực thi các câu lệnh và các thuộc tính mà View có thể kết buộc dữ liệu được và thông báo về sự thay đổi trạng thái cho View thông qua các sự kiện. Các câu lệnh và thuộc tính mà ViewModel cung cấp xác định chức năng được đề nghị bởi UI, nhưng View sẽ xác định cách chức năng đó được render như thế nào.

ViewModel chịu trách nhiệm phối hợp tương tác của View với các model class được yêu cầu. Thông thường, có một mối quan hệ 1-nhiều giữa các lớp các lớp ViewModel và Model. View có thể chọn để đưa ra các model class trực tiếp đến View để các control trong View có thể kết buộc dữ liệu trực tiếp đến chúng. Trong trường hợp này, các model class cần được thiết kế để hỗ trợ việc kết bôộc dữ liệu và các sự kiện thông báo sự thay đổi có liên quan.

ViewModel có thể chuyển đổi hoặc tính toán model data để nó có thể được View sử dụng dễ dàng. ViewModel có thể xác định các thuộc tính boe63 sung để hỗ trợ đặc biệt cho View; những thuộc tính này có thể được thêm vào một cách linh hoạt. Ví dụ: ViewModel có thể giá trị của hai trường để View có thể dễ dàng thể hiện hơn, hoặc nó có thể tính số kí tự còn lại trong phần input đối với những trường có độ dài kí tự giới hạn. ViewModel cũng có thể thực thi việc kiểm tra dữ liệu bnan đầu (data validation logic) để đảm bảo tính nhất quán của dữ liệu.

ViewModel cũng có thể xác định trạng thái logic mà View có thể sử dụng để đưa ra những sự thay đổi đồ họa trong UI. View có thể xác định những thay đổi về layout hoặc style có thể ảnh hưởng đến trạng thái của ViewModel. Thông thường, ViewModel sẽ xác định các câu lệnh và hành động có thể được mô tả trong UI và người dùng có thể thực thi. Một ví dụ phổ biến đó là khi ViewModel cung cấp câu lệnh Submit cho phép người dùng gửi dữ liệu đến một web service hoặc một nơi lưu trữ dữ liệu. View có thể chọn để mô tả câu lệnh bằng một nút nhấn (button) để người dùng có thể nhấn vào để gửi dữ liệu đi. Thông thường, khi câu lệnh ở trạng thái “unavailable”, các thành phần UI có liên quan của nó cũng bị vô hiệu hóa. Các câu lệnh là một cách để đóng gói các hành động của người dùng và tách biệt rõ ràng chúng khỏi phần UI.

Tóm lại, ViewModel có những đặc điểm chính sau:

– ViewModel không phải là lớp có tính chất đồ họa (non-visual class) và không chuyển hóa từ WPF hay Silverlight base class. Nó đóng gói phần representaion logic được yêu cầu để hỗ trợ cho một use case hoặc user task trong ứng dụng. ViewModel có thể kiểm thử độc lập với View và Model.

– Thông thường ViewModel không tham chiếu trực tiếp đến View. Nó thực thi các thuộc tính và câu lệnh để View có thể kết buộc dữ liệu. Nó thông báo cho View khi có bất kì sự thay đổi trạng thái nào thông qua các sự kiện (thông qua các interface INotifyPropertyChangedINotifyCollectionChaged).

– ViewModel phối hợp sự tương tác của View với Model. Nó có thể chuyển đổi hoặc tính toán dữ liệu để nó có thể dễ dàng được sử dụng bởi View và có thể thực thi các thuộc tính bổ sung mà không thể mô tả trên Model. Nó cũng có thể thực thi việc kiểm tra dữ liệu thông qua các interface IDataErrorInfo hoặc INotifyDataError.

– ViewModel có thể xác định các trạng thái logic mà View có thể mô tả cho người dùng.

Model Class

Model trong MVVM đóng gói business logic và data. Business logic được định nghĩa như bất kì application logic nào liên quan đến việc lấy và quản lý dữ liệu của ứng dụng và đảm bảo rằng bất kì business rule nào mà đảm bảo sự thống nhất của dữ liệu và việc kiểm tra chúng là bắt buộc. Để tối ưu hóa việc tái sử dụng, các model không nên chứa bất kì use case-specific hoặc user task-specific behavior hoặc application logic nào.

Thông thường, Model mô tả client-side domain model cho ứng dụng. Nó có thể định nghĩa các cấu trúc dữ liệu dựa trên data model của ứng dụng và bất kì business và valication logic nào hỗ trợ. Model cũng có thể bao gồm code để hỗ trợ việc truy xuất dữ liệu và caching, Thông thường, Model và data access layer được tạo ra như một phần của một data access hoặc service strategy, chẳng hạn như ADO.NET Entity Framework, WCF Data Service, hoặc WCF RIA Service.

Thông thường, Model thực thi các thành phần mà nó có thể dễ dàng kết buộc cho View. Điều này có nghĩa là nó hỗ trợ thông báo thuộc tính và collection bị thay đổi thông qua các interface INotifyPropertyChangedINotifyCollectionChanged. Thông thường các model class mô tả các collection của các đối tượng chuyển hóa từ lớp ObservableCollection<T> cung cấp việc thực thi INotifyCollectionChanged interface.

Model cũng có thể hỗ trợ việc kiểm tra dữ liệu và thông báo lỗi thông qua các interface IDataErrorInfo (hoặc INotifyDataErroInfo). Những interface này cho phép việc kết buộc dữ liệu của WPF và Silverlight được thông báo khi các giá trị thay đổi để UI có thể được cập nhật. Chúng cũng hỗ trợ việc kiểm tra dữ liệu và thông báo lỗi trong UI layer.

Tóm lại, Model có những đặc điểm chính sau:

– Các model class là những lớp non-visual đóng gói dữ liệu và business logic của ứng dụng. Chúng chịu trách nhiệm quản lý dữ liệu của ứng dụng và đảm bảo tính thống nhất của nó và kiểm tra bằng việc đóng gói các business rule và data valication logic được yêu cầu.

– Các model class không tham chiếu trực tiếp đến View và các ViewModel class và không có sự phụ thuộc vào cách chúng được thực thi.

– Thông thường các model class cung cấp các sự kiện thông báo thay đổi thuộc tính và collection thông qua các interface INotifyPropertyChangedINotifyCollectionChanged. Điều này cho phép chúng dễ dàng kiểm soát dữ liệu trong View. Các model class mô tả các tập hợp của các đối tượng thường chuyển hóa từ lớp ObservableCollection<T>.

– Thông thường các model class cung cấp việc kiểm tra dữ liệu và thông báo lỗi thông qua các interface IDataErrorInfo hoặc INotifyDataErrorInfo

– Thông thường các model class được sử dụng trong việc kết hợp với một dịch vụ hoặc nơi lưu trữ thực hiện việc truy xuất dữ liệu và caching.

 Sự tương tác giữa các lớp

Mẫu thiết kế MVVM đưa ra cách tách biệt rõ rệt giữa UI, presentation logic, business logic và dữ liệu của ứng dụng bằng cách tách thành các lớp riêng biệt. Các tương tác giữa View và ViewModel là phần quan trọng nhất để tìm hiểu, nhưng các tương tác giữa các model class và ViewModel cũng quan trọng không kém. Nội dung trình bày sau đây mô tả các pattern khác cho các tương tác này và mô tả cách thiết kế chúng khi bạn thực thi mẫu thiết kế MVVM trong các ứng dụng của bạn.

P/s: trong bài viết kế tiếp sẽ đi sâu vào phần thực thi mẫu thiết kế MVVM như thế nào, khi đó các bạn sẽ nắm rõ hơn cách thức hoạt động bên trong của mẫu thiết kế này, đồng thời sẽ có demo ứng dụng mẫu để các bạn dễ hình dung ứng dụng thực tế nó như thế nào.

Observer

Khái niệm:

Định nghĩa một sự phụ thuộc 1-nhiều giữa các đối tượng để khi một đối tượng thay đổi trạng thái, tất cả phụ thuộc của nó được thông báo và cập nhật một cách tự động

Mức độ sử dụng: cao

UML Class Diagram

observer_class_diagram

Những lớp và/hoặc đối tượng trong mẫu thiết kế này:

Subject (Stock):

     + biết các observer của nó. Bất kì đối tượng Observer nào cũng có thể quan sát chủ thế của nó.

     + cung cấp một interface để đính kèm và gỡ đính kèm các đối tượng Observer.

ConcreteSubject (IBM):

     + lưu trữ trạng thái mối quan tâm vào ConcreteObserver

     + gửi một thông báo đến các observer của nó khi nó thay đổi trạng thái

– Observer (IInvestor): định nghĩa một interface đang cập nhật cho các đối tượng nên được thông báo khi có thay đổi trong một subject.

ConcreteObserver (Investor):

     + bảo trì một tham chiếu đến một đối tượng ConcreteSubject

     + lưu trữ trạng thái luôn nhất quán với trạng thái của subject

     + thực thi interface cập nhật của Observer để giữ trạng thái của nó đồng nhất với trạng thái của subject

Observer: khi nào sử dụng và sử dụng ở đâu

Observer là một trong hai mẫu thiết kế của Gang-of-Four (mẫu thiết kế khác là Iterator) được dùng không chỉ trong các thư viện .NET framework, mà còn trong bản thân các ngôn ngữ .NET. Khi lập trình một ứng dụng Web hoặc một ứng dụng Windows, bạn thường làm việc với các event và event handler. Các event và Delegate,, hoạt động như Subject và các Observer như được định nghĩa một cách tương ứng trong mẫu thiết kế Observer.

Mẫu thiết kế Observer là cơ sở cho các thiết kế hướng đối tượng tốt vì nó hỗ trợ kiểu loose coupling. Các observer đăng kí và gỡ đăng kí bản thân chúng cũng các subject duy trì một danh sách các observer được quan tâm. Subject này không phụ thuộc vào bất kì observer riêng biệt nào miễn là các delegate là của đúng kiểu dành cho event đó.

Demo

ObserverClassDiagramRealWorld

http://cid-d0e5ddf023bf4324.office.live.com/embedicon.aspx/.Public/Design%20Pattern/ObserverRealWorld.zip

Iterator

Khái niệm:

Cung cấp một cách để truy xuất các thành phần của một đối tượng hợp nhất một cách tuần tự mà không cho thấy representation bên dưới của nó

Mức độ sử dụng: cao

UML Class Diagram

iterator_class_diagram

Những lớp và/hoặc đối tượng trong mẫu thiết kế này:

– Iterator (AbstractIterator): định nghĩa một interface để truy xuất và đi qua các thành phần.

– ConcreteIterator (Iterator):

     + thực thi Iterator interface

     + theo dõi vị trí hiện tại trong phần giao nhau của tập hợp

– Aggregate (AbstractCollection): Định nghĩa một interface để tạo một đối tượng Iterator.

– ConcreteAggregate (Collection): thực thi interface tạo lập Iterator để trả về một đối tượng của ConcreteIterator riêng.

Iterator: khi nào sử dụng và sử dụng ở đâu

Công việc thường được thực hiện khi lập trình đó là xem xét và tính toán tập hợp các đối tượng. Các tập hợp này có thể được lưu trữ bằng mảng (array), danh sách (list) hoặc gì đó phức tạp hơn chẳng hạn như cấu trúc cây hoặc đồ thị. Ngoài ra, bạn có thể cần truy xuất các item trong tập hợp theo lệnh, chẳng hạn như từ trước ra sau, từ sau ra trước, duyệt theo chiều sâu… Mẫu thiết kế Iterator giải quyết vấn đề này bằng cách tách biệt tập hợp các đối tượng từ phần giao nhau của các đối tượng này bằng việc thực thi một lớp iterator được chuyên biệt hóa.

Không những thế, bạn có thể tìm thấy mẫu thiết kế Interator sâu trong các thư việc .NET, nó là một trong 2 mẫu thiết kế mà là một phần của bản thân ngôn ngữ C# và VB (mẫu thiết kế khác là Observer). Cả hai ngôn ngữ đều có một kiến trúc được xây dựng sẵn tạo điều kiện đổi các tập hợp: foreach trong C# và For Each trong VB

iterator_ex_c#

iterator_ex_vb

Các đối tượng được tham chiếu trong “in” expression phải thực thi IEnumerable interface để tập hợp các đối tượng có thể được truy xuất.

Demo

IteratorRealWorldClassDiagram

http://cid-d0e5ddf023bf4324.office.live.com/embedicon.aspx/.Public/Design%20Pattern/IteratorRealWorld.zip

Command

Khái niệm:

Đóng gói một request như một đối tượng, bằng cách đó cho phép bạn tham số hóa các client với các request khác nhau, các queue và log request, và hỗ trợ các hoạt động (operation) có thể “undo”.

Mức độ sử dụng: khá cao

UML Class Diagram

command_class_diagram

Những lớp và/hoặc đối tượng trong mẫu thiết kế này:

Command (Command): khai báo một interface cho việc thực thi một operation.

ConcreteCommand (CalculatorCommand):

+ định nghĩa một sự kết buộc giữa một đối tượng Receiver và một hành động.

+ thực thi Excute bằng việc gọi (các) operation đang hoãn trên Receiver.

Client (CommandApp): tạo ra một đối tượng ConcreteCommand và thiết lập receiver của nó.

Invoker (User): yêu cầu thực hiện request.

Receiver (Calculator): biết cách thực thi các operation liên quan đến việc thực hiện request.

Command: khi nào sử dụng và sử dụng ở đâu

Mẫu thiết kế Command đóng gói một hành động hoặc một request như một đối tượng. Ứng dụng kinh điển là hệ thống trình đơn nơi mỗi đối tượng command mô tả một hành động và một hành động có thể “undo” có liên quan. Các hành động của trình đơn bao gồm các menu item như File | Open, File | Save, Edit | Copy… mỗi menu item được gắn với đối tượng command của nó.

Tất cả Command thực thi cùng interface, vì thế chúng có thể được xử lý một cách đa hình. Thông thường, interface của chúng gồm các phương thức chẳng ạn như Do và Undo (hoặc Execute và Undo). Những nơi mà bạn có thể mẫu thiết kế Command: menu command system và trong các ứng dụng yêu cầu chức năng “undo”.

Demo

CommandRealWorldClassDiagram

http://cid-d0e5ddf023bf4324.office.live.com/embedicon.aspx/.Public/Design%20Pattern/CommandRealWorld.zip

Proxy

Khái niệm:

Cung cấp một đối tượng thay thế hoặc placeholder cho một đối tượng khác để truy xuất đến nó.

Mức độ sử dụng: khá cao

UML Class Diagram

proxy_class_diagram

Những lớp và/hoặc đối tượng trong mẫu thiết kế này:

Proxy (MathProxy):

     + bảo trì một tham chiếu để cho proxy truy xuất đối tượng thật. Proxy có thể nhắm vào một đối tượng nếu các interface RealSubject và Subject giống nhau.

     + cung cấp một interface giống hệt với interface của Subject để một proxy có thể được thay thế cho đối tượng thật.

     + điều khiển việc truy xuất đến đối tượng thật và có thể chịu trách nhiệm trong việc tạo ra và hủy nó.

     + những nhiệm vụ khác tùy thuộc vào loại proxy:

        * remote proxy: chịu trách nhiệm mã hóa một request và các đối số của nó và gửi các request được mã hóa cho đối tượng thật trong vùng địa chỉ khác.

        * virtual proxy: có thể bắt (cache) thông tin bổ sung về đối tượng thật để chúng có thể hoãn việc truy xuất nó. Ví dụ, ImageProxy trong Motivation bắt giới hạn của các hình ảnh thật.

        * protection proxy: kiểm tra “người gọi” có quyền truy xuất được yêu cầu để thực thi một request hay không.

Subject (IMath): định nghĩa interface chung cho Realsubject và Proxy để một Proxy có thể được sử dụng bất kì đâu mà một RealSubject được mong đợi.

RealSubject (Math): định nghĩa một đối tượng thật mà proxy mô tả.

Proxy: khi nào sử dụng và sử dụng ở đâu

Trong các ngôn ngữ hướng đối tượng, các đối tượng thực hiện công việc mà chúng được cho biết thông qua public interface của chúng. Những client của các đối tượng này mong muốn công việc này được thực hiện nhanh chóng và hiệu qủa. Tuy nhiên, có các tình huống nơi một đối tượng bị hạn chế và không thể tiếp tục thực hiện nhêệm vụ của nó. Thông thường, việc này xảy ra khi có một dependency trên một remote resource (một lời gọi đến máy tính khác chẳng hạn) hoặc khi một đối tượng mất nhiều thời gian để load. Trong những trường hợp tương tự như thế này, bạn chọn mẫu thiết kế Proxy và tạo một đối tượng proxy mà “đối tượng đóng thể” (stand-in) cho một đối tượng gốc. Proxy chuyển request đến đối tượng đích. Interface của đối tượng Proxy này giống như đối tượng gốc và các client không thể biết rằng họ đang xử lý với một proxy hơn là một đối tượng thật.

Có 3 mẫu proxy khác nhau:

+ Remote proxy: chịu trách nhiệm mã hóa một request và chuyển request được mã hóa cho một đối tượng thật trong một không gian địa chỉ khác (app domain, process hoặc machine).

+ Virtual proxy: có thể bắt thông tin bổ sung về một đối tượng thật để chúng có thể hoãn việc truy xuất nó (chẳng hạn như just-in-time loading, on-demand loading hoặc lazy loading).

+ Protection proxy: kiểm tra “người gọi” có các quyền truy xuất riêng để thực hiện request.

Thực tế, còn có kiểu proxy khác được gọi là Smart Reference. Một Smart Reference là một proxy cho một pointer, nhưng vì có ít ứng dụng cho các pointer trong .NET và bạn ít khi nào sử dụng loại proxy này.

Demo

ProxyRealWorldClassDiagram

http://cid-d0e5ddf023bf4324.office.live.com/embedicon.aspx/.Public/Design%20Pattern/ProxyRealWorld.zip

Flyweight

Khái niệm:

Sử dụng việc chia sẻ để hỗ trợ số lượng lớn các đối tượng fine-grained một cách hiệu quả.

Mức độ sử dụng: thấp

UML Class Diagram

flyweight_class_diagram

Những lớp và/hoặc đối tượng trong mẫu thiết kế này:

Flyweight (Character): khai báo một interface thông qua các flyweight có thể nhận và thực hiện trên trạng thái ngoại.

ConcreteFlyweight (CharacterA, CharacterB, …, CharacterZ): thực thi Flyweight interface và thêm vào phần lưu trữ cho trạng thái ngoại nếu có. Một đối tượng ConcreteFlyweight phải có khả năng chia sẻ được. Bất kì trạng thái nào mà nó lưu trữ phải là ngoại, nghĩa là nó phải độc lập với bối cảnh của đối tượng ConcreteFlyweight.

UnsharedConcreteFlyweight: không phải tất cả các lớp con đều cần được chia sẻ. Flyweight interface cho phép chia sẻ, nhưng nó không ép buộc.

Flyweight: khi nào dử dụng và sử dụng ở đâu

Mục tiêu của mẫu thiết kế Flyweight là để chia sẻ nhiều đối tượng fine-grained một cách hiệu quả. Các đối tượng flyweight được chia sẻ là bất biến, chúng không thể bị thay đổi vi chúng mô tả các tính chất được chia sẻ với các đối tượng khác. Một số ví dụ như các kí tự và line-style trong word processor hoặc các digit receiver trong một các ứng dụng mạng điện thoại chuyển đổi công cộng. Flyweight hiếm khi nào được sử dụng trong các ứng dụng nghiệp vụ hướng dữ liệu (data-driven business type application).

Demo

FlyweightRealWorldClassDiagram

http://cid-d0e5ddf023bf4324.office.live.com/embedicon.aspx/.Public/Design%20Pattern/FlyweightRealWorld.zip