Giới thiệu thư viện MvpPattern dùng xây dựng mô hình ứng dụng dựa trên kiến trúc MVP
bởi Nguyễn Thành Mãn vào 8 tháng 1 2013 lúc 17:20 ·
Giới thiệu thư viện MvpPattern dùng để xây dựng mô hình ứng dụng dựa trên kiến trúc Model – View – Presenter
1 Giới thiệu
Trong quá trình thực hiện dự án Phần mềm quản lý tư liệu và Website Nhã nhạc cung đình Huế, từ kinh nghiệm của các dự án trước và qua tìm hiểu tham khảo trên Internet, nhóm thực hiện dự án đã học hỏi, cải tiến và tổ chức lại thành thư viện MvpPattern chạy trên nền tảng .NET, với mục tiêu nâng cao tính tái sử dụng, giảm bớt khối lượng mã cần viết cho các thao tác thường gặp khi xây dựng phần mềm áp dụng theo mô hình Model-View-Presenter (MVP). Mô hình MVP đã khá quen thuộc với giới lập trình nên việc giới thiệu nằm ngoài phạm vi bài viết này. Đây là phiên bản đầu tiên, bước đầu chỉ mới khái quát hóa vấn đề ở mức độ cơ bản, nên có một số điểm vẫn chưa được hoàn thiện, chưa được như mong muốn. Trong quá trình ứng dụng thực tiễn, thư viện sẽ tiếp tục được cải tiến cho phù hợp và tiện lợi hơn. Chúng tôi chia sẻ một số kinh nghiệm và mong nhận được ý kiến đóng góp.
Các ví dụ sử dụng theo cách lập trình truyền thống, chưa đáp ứng hoàn toàn nguyên lý đảo ngược phụ thuộc (Dependency Inversion Principle – DIP[*], cách gọi khác là Inversion of Control – IoC), việc áp dụng nguyên lý này làm giảm bớt sự kết nối (decoupling) chặt chẽ giữa các đối tượng trong phần mềm, tăng độ linh hoạt và giúp phần mềm có tính module hóa cao. Trong khuôn khổ bài viết không thể trình bày đầy đủ, xin tham khảo mã nguồn ví dụ áp dụng thư viện Unity Application Block (phiên bản 2.1) để cài đặt mẫu thiết kế (design pattern) dependency injection.
2 Cấu trúc gói
2.1 Biểu đồ gói
Các giao diện và lớp của thư viện.
Vị trí của thư viện trong mô hình MVP.
Ghi chú: Các giao diện và lớp có màu đen là mã ví dụ, không thuộc thành phần của thư viện.
2.2 Tổng quan
Áp dụng thư viện MvpPattern cho phát triển mô hình phần mềm dựa theo kiến trúc ba tầng Model – View – Presenter(MVP). MvpPattern theo cơ chế Passive View, tất cả các tương tác từ tầng giao diện (View) đi xuống và tầng dữ liệu (Model) trở lên đều thông qua tầng trung gian nghiệp vụ (Presenter).
Tầng dữ liệu sử dụng LINQ (LINQ được Microsoft tích hợp vào Visual Studio từ phiên bản 2008. tuy nhiên vẫn có thể dùng trong phiên bản 2005, lưu ý là LINQ chỉ dùng được cho hệ quản trị cơ sở dữ liệu MS SQL Server) và kết hợp với thư viện Dynamic LINQ để tạo các câu truy vấn có điều kiện tương tự câu lệnh truy vấn SQL quen thuộc.
2.2.1 Tầng Business
2.2.1.1 Giao diện IGenericView
Giao diện gốc, với mục đích cho các giao diện khác kế thừa.
public interface IGenericView
{
}
2.2.1.2 Giao diện IListManipulationView
Định nghĩa các thuộc tính và sự kiện thao tác cơ bản là thêm mới, chỉnh sửa, xóa bỏ và lựa chọn khi xử lý dữ liệu trên một danh sách, dẫn xuất từ IGenericView.
public interface IListManipulationView : IGenericView
{
// Trả về hoặc thiết lập danh sách các đối tượng của view
IList ListItem { set; get; }
// Trả về đối tượng được tạo mới trên view
TEntity NewItem { get; }
// Trả về đối tượng hiện hành trên danh sách của view
TEntity CurrentItem { get; }
// Trả về danh sách các đối tượng được lựa chọn trên view
IList SelectedItems { get; }
// Sự kiện phát sinh khi thêm một hạng mục dữ liệu mới
event EventHandler OnAddEventHandler;
// Sự kiện phát sinh khi lưu trữ thông tin của hạng mục dữ liệu
event EventHandler OnSaveEventHandler;
// Sự kiện phát sinh khi xóa bỏ các hạng mục dữ liệu
event EventHandler OnDeleteEventHandler;
// Sự kiện phát sinh khi các hạng mục dữ liệu được lựa chọn
event EventHandler OnSelectEventHandler;
}
Ví dụ: Form danh sách người dùng có các thao tác thêm mới, cập nhật và xóa bỏ. Định nghĩa giao diện IUserView kế thừa từ giao diện IListManipulationView, định nghĩa thêm một số thuộc tính cần thiết khác và thi hành giao diện này cho form.
public interface IUserView : IListManipulationView
Thi hành giao diện mới cho form:
public partial class frmUser : Form, IUserView
2.2.1.3 Giao diện IListSelectionView
Định nghĩa các thuộc tính và sự kiện khi lựa chọn các hạng mục dữ liệu trên một danh sách, dẫn xuất từ IGenericView.
public interface IListSelectionView : IGenericView
{
// Trả về hoặc thiết lập danh sách các đối tượng của view
IList ListItem { set; get; }
// Trả về danh sách các đối tượng được lựa chọn trên view
IList SelectedItems { get; }
// Sự kiện phát sinh khi các hạng mục dữ liệu được lựa chọn
event EventHandler OnSelectEventHandler;
}
Người phát triển có thể định nghĩa ra các giao diện mới tùy theo nhu cầu hoặc kế thừa từ các giao diện trên.
Ví dụ: Có một form danh sách người dùng và sử dụng để lựa chọn ra một số người dùng từ danh sách đó, ta định nghĩa giao diện IUserSelectionView kế thừa từ giao diện IListSelectionView, định nghĩa thêm một số thuộc tính cần thiết khác và thi hành giao diện này cho form.
public interface IUserSelectionView : IListSelectionView
Thi hành giao diện cho form:
public partial class dlgUser : Form, IUserSelectionView
2.2.1.4 Lớp tổng quát GenericPresenter
Lớp chứa các phương thức phổ biến khi thực hiện các thao tác xử lý trên danh sách. Người phát triển có thể override các phương thức này tùy theo nhu cầu sử dụng.
Ví dụ tạo presenter kế thừa từ GenericPresenter, mỗi presenter gắn với view mà nó điều khiển:
public class UserPresenter : GenericPresenter
Khởi tạo đối tượng UserPresenter từ view như sau:
public partial class frmUser : Form, IUserView
{
private UserPresenter presenter;
private void frmUser_Load(object sender, EventArgs e)
{
// Khởi tạo đối tượng presenter
presenter = new UserPresenter();
// Gắn tham chiếu của form thực thi giao diện cho presenter
presenter.View = this;
2.2.1.4.1 Thuộc tính View
Mô tả: Trả về hoặc thiết lập tham chiếu đến view gắn với presenter. Thao tác gán giá trị cho thuộc tính View gọi phương thức OnViewSet.
Cú pháp:
TView View { get; set; }
Ví dụ: Thiết lập giá trị View cho presenter.
presenter = new UserSelectionPresenter();
presenter.View = this;
2.2.1.4.2 Phương thức OnViewSet
Mô tả: Phương thức được gọi khi thuộc tính view của presenter được gán giá trị (xem 2.2.1.4.1).
Cú pháp: public abstract void OnViewSet();
Ví dụ:
public override void OnViewSet()
{
// Khởi tạo dịch vụ xử lý dữ liệu
service = UserGroupService.Instance;
// Đăng ký hàm nhận thông báo mỗi khi dữ liệu có sự thay đổi
service.DataChanged += new DataChangeHandler(FillData);
// Đăng ký các hàm xử lý sự kiện
RegisterEvents();
// Điền thông tin vào giao diện trong lần đầu chạy ứng dụng
FillData();
}
2.2.1.4.3 Phương thức RegisterEvents
Mô tả: Đăng ký các phương thức xử lý sự kiện xảy ra trên view. Có sẵn bốn sự kiện thường gặp là tạo mới, chỉnh sửa, xóa bỏ và lựa chọn hạng mục dữ liệu, thông thường với view dẫn xuất từ IListManipulationView thì sử dụng cả bốn sự kiện trên, còn view dẫn xuất từ IListSelectiontionView thì chỉ đăng ký sự kiện OnSelectEventHandler.
Cú pháp: public virtual void RegisterEvents();
Ví dụ:
public override void RegisterEvents()
{
View.OnAddEventHandler += new EventHandler(OnAddEventHandler);
View.OnSaveEventHandler += new EventHandler(OnSaveEventHandler);
View.OnDeleteEventHandler += new EventHandler(OnDeleteEventHandler);
View.OnSelectEventHandler += new EventHandler(OnSelectEventHandler);
}
2.2.1.4.4 Phương thức OnAddEventHandler
Mô tả: Xử lý sự kiện tạo hạng mục dữ liệu mới trên view.
Cú pháp: public virtual void OnAddEventHandler;
Ví dụ:
public override void OnAddEventHandler(object sender, EventArgs e)
{
userService.Insert(View.NewItem);
}
2.2.1.4.5 Phương thức OnSaveEventHandler
Mô tả: Xử lý sự kiện lưu thông tin hạng mục trên view.
Cú pháp: public virtual void OnSaveEventHandler;
Ví dụ:
public override void OnSaveEventHandler(object sender, EventArgs e)
{
userService.Update(View.CurrentItem, “UserID=” + View.CurrentItem.UserID);
}
2.2.1.4.6 Phương thức OnDeleteEventHandler
Mô tả: Xử lý sự kiện xóa bỏ hạng mục dữ liệu trên view.
Cú pháp: public virtual void OnDeleteEventHandler;
Ví dụ:
public override void OnDeleteEventHandler(object sender, EventArgs e)
{
userService.Delete(View.SelectedItems);
}
2.2.1.4.7 Phương thức OnSelectEventHandler
Mô tả: Xử lý sự kiện lựa chọn hạng mục dữ liệu trên view
Cú pháp: public virtual void OnSelectEventHandler;
Ví dụ:
public override void OnSelectEventHandler(object sender, EventArgs e)
{
userService.AddToGroup(View.CurrentGroup, View.SelectedItems);
}
2.2.2 Tầng Data
2.2.2.1 Giao diện IGenericService
Giao diện gốc, với mục đích cho các giao diện khác dẫn xuất.
public interface IGenericService
{
}
2.2.2.2 Giao diện IGenericDataAccessService
Định nghĩa các phương thức xử lý dữ liệu thông dụng, dẫn xuất từ IGenericService. Gồm các phương thức cơ bản như truy vấn, các thao tác thêm mới, cập nhật, xóa bỏ đối tượng và gửi thông báo mỗi khi dữ liệu có sự thay đổi.
2.2.2.3 Lớp tổng quát GenericDataAccessService
Lớp tổng quát này thi hành từ giao diện IGenericDataAccessService.
2.2.2.3.1 Phương thức khởi tạo đối tượng GenericDataAccessService
Mô tả: Phương thức khởi tạo đối tượng (constructor).
Cú pháp: GenericDataAccessService(System.Data.Linq.DataContext dataContext)
Tham số: Đối tượng Linq.LINQ.DataContext. Thông báo biệt lệ ArgumentNullException nếu tham số bằng Null. Tham số của đối tượng LINQ.DataContext là chuỗi kết nối tới cơ sở dữ liệu.
Trả về: Đối tượng GenericDataAccessService
Ví dụ:
public class UserService : GenericDataAccessService, IUserService
{
// Constructor (strConnectionString là chuỗi kết nối tới cơ sở dữ liệu)
public UserService() : base(new MvpExampleDataContext(strConnectionString)) { }
2.2.2.3.2 Thuộc tính DataContext
Mô tả: Trả về tham chiếu DataContext của đối tượng GenericDataAccessService.
Trả về: Đối tượng LINQ.DataContext
Ví dụ:
// Viết ra chuỗi kết nối đến cơ sở dữ liệu
Console.WriteLine(DataContext.Connection.ConnectionString);
2.2.2.3.3 Phương thức SelectAll
Mô tả: Trả về tất cả đối tượng của một lớp.
Cú pháp: virtual IList SelectAll(string orderByExpression)
Tham số:
orderByExpression: Thứ tự sắp xếp kết quả truy vấn, gồm tên trường và thứ tự sắp xếp ASC hoặc DESC, hoặc để chuỗi rỗng nếu không cần sắp xếp.
Trả về: Danh sách các đối tượng.
Ví dụ: IList users = SelectAll(“UserName ASC”);
2.2.2.3.4 Phương thức SelectBy
Mô tả: Truy vấn đối tượng theo điều kiện lọc.
Cú pháp:
virtual IList SelectBy(string searchCondition, string orderByExpression)
Tham số:
– searchCondition: Điều kiện lọc.
– orderByExpression: Thứ tự sắp xếp kết quả truy vấn, gồm tên trường và thứ tự sắp xếp ASC hoặc DESC, hoặc để chuỗi rỗng nếu không cần sắp xếp.
Ví dụ: userService.SelectBy(“GroupID = 1″, “UserName ASC”);
2.2.2.3.5 Phương thức SelectBy
Mô tả: Truy vấn đối tượng theo điều kiện lọc.
Cú pháp:
IList SelectBy(int fromItemNumber, int numberOfItems, string searchCondition, string orderByExpression)
Tham số:
– fromItemNumber: Bắt đầu chọn từ đối tượng thứ fromItemNumber.
– numberOfItems: Trả về số lượng numberOfItems đối tượng.
– searchCondition: Điều kiện lọc.
– orderByExpression: Thứ tự sắp xếp kết quả truy vấn, gồm tên trường và thứ tự sắp xếp ASC hoặc DESC, hoặc để chuỗi rỗng nếu không cần sắp xếp.
Ví dụ: userService.SelectBy(1, 20, “GroupID Null”, “UserName DESC”);
2.2.2.3.6 Phương thức Delete
Mô tả: Xóa bỏ đối tượng theo điều kiện lọc.
Cú pháp: virtual void Delete(string searchCondition)
Tham số:
searchCondition: Điều kiện lọc.
Ví dụ: userService.Delete(“GroupID = Null”);
2.2.2.3.7 Phương thức Delete
Mô tả: Xóa bỏ một tập các đối tượng.
Cú pháp: virtual void Delete(IList entities)
Tham số:
entities: Danh sách các đối tượng cần xóa bỏ.
Ví dụ: userService.Delete(View.SelectedItems);
2.2.2.3.8 Phương thức DeleteAll
Mô tả: Xóa bỏ toàn bộ các đối tượng của một lớp.
Cú pháp: virtual void DeleteAll()
Ví dụ: userService.DeleteAll();
2.2.2.3.9 Phương thức Insert
Mô tả: Thêm mới một đối tượng.
Cú pháp: virtual TEntity Insert(TEntity entity)
Tham số:
entity: Đối tượng mới.
Ví dụ:
User user = new User() { UserName = “X” };
userService.Insert(user);
2.2.2.3.10 Phương thức Update
Mô tả: Override phương thức này để thực hiện cập nhật thông tin một đối tượng.
Cú pháp: virtual void Update(TEntity entity, string searchCondition)
Tham số:
– entity: Đối tượng chứa thông tin cập nhật.
– searchCondition: Điều kiện lọc.
Ví dụ:
user.UserName = “Y”;
userService.Update(user, “UserID = 1″);
2.2.2.3.11 Phương thức NotifyDataChanged
Mô tả: Gọi phương thức này để thông báo mỗi khi dữ liệu vừa có sự thay đổi. Phương thức này kích hoạt sự kiện DataChanged trên các presenter và gọi phương thức FillData cập nhật lại dữ liệu trên toàn bộ các presenter có thi hành giao diện IObserver.
Cú pháp: void NotifyDataChanged()
Ví dụ:
UserGroup group = DataContext.GetTable().Where(obj => obj.GroupID == entity.GroupID).SingleOrDefault();
IList users = SelectBy(searchCondition, “”);
foreach (User user in users)
{
user.UserName = entity.UserName;
user.UserGroup = group;
}
DataContext.SubmitChanges();
NotifyDataChanged();
2.2.2.3.12 Phương thức ClearCache
Mô tả: Xóa bộ đệm dữ liệu.
Cú pháp: static void ClearCache()
2.2.2.3.13 Hàm delegate DataChangeHandler
Mô tả: Đăng ký nhận sự kiện mỗi khi dữ liệu có sự thay đổi.
Ví dụ: Đăng ký một hàm có tên FillData, phương thức này được kích hoạt mỗi khi dữ liệu có sự thay đổi.
public override void OnViewSet()
{
service = new UserGroupService();
service.DataChanged += new DataChangeHandler(FillData);
…
// Phương thức này thực hiện cập nhật lại thông tin trên view
private void FillData()
{
View.ListItem = service.SelectAll(“GroupName ASC”);
}
Có hai cách chặn bắt sự kiện dữ liệu có sự thay đổi, dùng hàm delegate DataChangeHandler hoặc dùng phương thức AttachObserver. Sự khác biệt của hai phương cách thức này là:
– Dùng hàm delegate: Chỉ presenter nào đăng ký mới nhận được thông báo.
– Dùng AttachObserver: Tất cả các presenter nào có đăng ký sẽ cùng nhận được thông báo.
2.2.2.4 Giao diện IObserver
Giao diện IObserver chỉ định nghĩa một phương thức duy nhất là FillData, phương thức được gọi mỗi khi lớp đối tượng Subject có sự thay đổi dữ liệu, dùng để thực hiện các thao tác cập nhật lại giao diện người dùng.
public interface IObserver
{
void FillData();
}
2.2.2.5 Giao diện ISubject
Định nghĩa các phương thức cho lớp Subject thi hành (dựa theo Observer pattern).
2.2.2.6 Lớp tổng quát Subject
Lớp đối tượng thi hành giao tiếp ISubject.
2.2.2.6.1 Phương thức AttachObserver
Mô tả: Đăng ký làm một observer, lớp đăng ký sẽ nhận được thông báo mỗi khi có sự thay đổi dữ liệu từ data service (xem mục 2.2.2.3.14).
Cú pháp: void AttachObserver(IObserver observer)
Tham số:
observer: Tên lớp đối tượng thi hành giao tiếp IObserver.
Ví dụ:
public class UserPresenter : GenericPresenter, IObserver
{
private IUserService userService;
public override void OnViewSet()
{
// Lấy single instance của UserService
userService = UserService.Instance;
// Dăng ký presenter này là observer nhận thông báo từ data service.
// Hàm FillData tự động được gọi mỗi khi dữ liệu có sự thay đổi.
userService.AttachObserver(this);
2.2.2.6.2 Phương thức DetachObserver
Mô tả: Hủy đăng ký một observer.
Cú pháp: void DetachObserver(IObserver observer)
Tham số:
observer: Tên lớp đối tượng thi hành giao tiếp IObserver.
Ví dụ: userService.DetachObserver(this);
2.2.2.6.3 Phương thức DetachAll
Mô tả: Hủy đăng ký toàn bộ observer.
Cú pháp: void DetachAll()
2.2.2.6.4 Phương thức NotifyObservers
Mô tả: Thông báo dữ liệu có sự thay đổi tới các observer đã đăng ký
Cú pháp: void NotifyObservers()
Ví dụ: userService.NotifyObservers();
2.2.2.6.5 Thuộc tính Observers
Mô tả: Trả về danh sách các observer đã đăng ký
Trả về: IList
Ví dụ:
// Tổng số các observer được đăng ký
Console.WriteLine(Observers.Count);
3 Nguồn thông tin tham khảo
– Kiến trúc Model-View-Presenter trong .NET (http://www.fpt.edu.vn/story/kien-truc-model-view-presenter-trong-net)
– Creating a generic Model-View-Presenter framework (https://dotnetchris.wordpress.com/2009/02/16/creating-a-generic-model-view-presenter-framework)
– Smart Client Software Factory (http://msdn.microsoft.com/en-us/library/ff648753.aspx)
– Tài liệu LINQ bản tiếng Việt (http://congthuong.googlecode.com/files/LINQ%20tieng%20viet.pdf)
– Dynamic LINQ (http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx)
– Unity Application Block (http://msdn.microsoft.com/en-us/library/hh237493.aspx)
4 Ví dụ sử dụng
Tạo hai lớp User và UserGroup với các thuộc tính và quan hệ như sau:
Thiết kế các form cho đối tượng User và UserGroup với các thao tác thêm mới, cập nhật và xóa bỏ. Form UserGroup có thêm chức năng chọn thêm các thành viên vào nhóm chỉ định. Cụ thể có ba form như sau:
– frmUser quản lý danh sách người dùng.
– frmUserGroup quản lý danh sách nhóm người dùng.
– dlgUser để lựa chọn ra một số người dùng từ danh sách người dùng.
1 Tạo một solution với ba project tên là UI, Bussiness và Data (tên project tùy chọn) tương ứng với ba tầng View, Presenter và Model.
– Project UI chứa các form, là lớp giao diện tương tác với người phát triển (view).
– Project Business chứa các lớp xử lý nghiệp vụ (business).
– Project Data chứa các lớp đối tượng dữ liệu và các lớp dịch vụ truy cập dữ liệu (model).
Thêm tham chiếu tới thư viện MvpPattern vào References của ba project trên.
2 Trong project Data sử dụng LINQ để ánh xạ các bảng từ cơ sở dữ liệu quan hệ ra các đối tượng và để truy xuất cơ sở dữ liệu.
- Right click vào thư mục Data, chọn Add New Item, LINQ to SQL Classes, đặt tên cho file DBML.
- Vào menu View, chọn Server Explorer.
- Right click vào Data Connections, chọn Add Connection, chọn tên máy chủ và cơ sở dữ liệu.
- Kéo hai bảng Users và UserGroups thả vào file DBML.
- Lưu file DBML, các lớp đối tượng được tự động sinh mã trong file MvpExample.designer.cs, người phát triển có thể chỉnh sửa, bổ sung thêm mã bằng cách right click vào file DBML, chọn View Code.
3 Trong project Data, định nghĩa các giao diện và viết mã xử lý cho tầng dữ liệu.
Giao diện cho lớp UserService định nghĩa các phương thức thao tác với lớp User.
public interface IUserService : IGenericDataAccessService
{
// Thêm các thành viên vào nhóm người dùng
void AddToGroup(UserGroup group, IList users);
}
Thi hành giao diện IUserService và viết mã cho lớp UserService.
public class UserService : GenericDataAccessService, IUserService
{
// Constructor
public UserService() : base(new MvpExampleDataContext(LocalConfig.ConnectionString)) { }
Override các phương thức Insert, Update tương ứng.
Giao diện cho lớp UserGroupService định nghĩa các phương thức thao tác với lớp UserGroup.
public interface IUserGroupService : IGenericDataAccessService
{
}
Thực hiện các bước tương tự như với lớp UserService.
4 Trong project Bussiness, tạo các giao diện tương ứng cho các form trên.
Định nghĩa giao diện cho form frmUser và viết mã cho presenter:
public interface IUserView : IListManipulationView
{
IList GroupList { set; }
UserGroup CurrentGroup { get; }
}
UserPresenter quản lý giao diện IUserView.
public class UserPresenter : GenericPresenter, IObserver
{
private IUserService userService;
public override void OnViewSet()
{
userService = new UserService.Instance;
userService.AttachObserver(this);
groupService = UserGroupService.Instance;
}
public void FillData()
{
// Cập nhật thông tin của view ở đây
}
Định nghĩa giao diện cho hộp thoại dlgUser và viết mã cho presenter:
public interface IUserSelectionView : IListSelectionView
{
UserGroup CurrentGroup { get; set; }
}
UserSelectionPresenter quản lý giao diện IUserSelectionView.
public class UserSelectionPresenter : GenericPresenter
{
private IUserService userService;
public override void OnViewSet()
{
userService = UserService.Instance;
Định nghĩa giao diện cho form frmUserGroup và viết mã cho presenter:
public interface IUserGroupView : IListManipulationView
{
}
UserGroupPresenter quản lý giao diện IUserGroupView. Ngoài cách đăng ký làm một observer, còn cách khác là đăng ký một hàm nhận sự kiện. Trong ví dụ dưới đây hàm có tên là FillData.
public class UserGroupPresenter : GenericPresenter
{
private IUserGroupService groupService;
public override void OnViewSet()
{
groupService = new UserGroupService();
groupService.DataChanged += new DataChangeHandler(FillData);
}
private void FillData()
{
// Cập nhật thông tin của view ở đây
}
5 Trong project UI, tạo các form fmrUser, frmUserGroup và dlgUser.
Tạo form frmUser và thi hành giao diện IUserView
public partial class frmUser : Form, IUserView
Tạo hộp thoại dlgUser và thi hành giao diện IUserSelectionView
public partial class dlgUser : Form, IUserSelectionView
Tạo form frmUserGroup và thi hành giao diện IUserGroupView
public partial class frmUserGroup : Form, IUserGroupView
6. Tương tác giữa các tầng với nhau:
Khi người dùng cập nhật thông tin của một đối tượng, ấn nút Lưu, tầng UI sẽ gửi thông tin tới tầng như sau:
private void btnSave_Click(object sender, EventArgs e)
{
// CurrentItem là đối tượng hiện hành được cập nhật dữ liệu
CurrentItem.UserName = tbxName.Text.Trim();
CurrentItem.UserGroup = CurrentGroup;
// Phát sinh sự kiện lưu trữ gửi tới presenter
if (OnSaveEventHandler != null)
OnSaveEventHandler(this, e);
Tầng presenter lấy đối tượng vừa rồi, gọi phương thức Update của userService để cập nhật vào cơ sở dữ liệu:
public override void OnSaveEventHandler(object sender, EventArgs e)
{
userService.Update(View.CurrentItem, “UserID=” + View.CurrentItem.UserID);
}
Tải mã nguồn ví dụ:
– MvpPatternExample.rar (http://www.mediafire.com/?fqcznsk5s4euvu4)
– MvpPatternDIPExample.rar (http://www.mediafire.com/?u91e7keg8qr8mv5)
ManNT – R&D, HueCIT (bài cho HW)
09/01/2013
[*] Nguyên lý đảo ngược phụ thuộc (Dependency Injection): Lớp cấp cao không nên phụ thuộc vào lớp cấp thấp, cả hai nên phụ thuộc vào một lớp tổng quát (abstract class/interface); và, lớp tổng quát (abstract) không nên phụ thuộc vào lớp cụ thể (concrete), ngược lại lớp cụ thể nên phụ thuộc vào lớp trừu tượng. Do lớp tổng quát ít có sự thay đổi, ổn định hơn so với lớp cụ thể thường xuyên có sự thay đổi, chỉnh sửa nâng cấp; và khi phụ thuộc vào các lớp tổng quát, hệ thống vẫn hoạt động bình thường nếu có sự thay đổi diễn ra tại một lớp cụ thể nào đó. Bởi vậy, cần đảo ngược sự phụ thuộc đó thành lớp cụ thể phụ thuộc vào lớp tổng quát.