Kiến trúc tổng thể: Bức tranh toàn cảnh
|
|||
Nguyễn Tuấn Hoa (www.pcworld.com.vn)
|
|
Mọi tổ chức đều vận động dựa trên thông tin. Theo đó, những con người hay nhóm – thành phần cấu tạo tổ chức – đảm đương những nhiệm vụ cụ thể luôn luôn giao tiếp với nhau, thông tin cho nhau để tương tác giữa bộ phận này với bộ phận khác, người này với người khác… Chỉ như thế, tổ chức mới có thể tồn tại và phát triển.
Trong khi đó, tổ chức lại xuất hiện từ xa xưa, trước CNTT rất lâu. Và từ thời xa xưa ấy, bản chất trên đã tồn tại và sẽ tồn tại mãi mãi cùng với xã hội loài người. Vì thế, việc mô hình hóa tổ chức luôn luôn dẫn đến bộ đôi: Mô hình tổ chức (tổ chức được cấu trúc như thế nào?) và mô hình thông tin (hệ thống thông tin bên trong tổ chức được xây dựng và vận hành như thế nào?).
Mọi chuyện thay đổi khi CNTT ra đời và mở ra những viễn cảnh mới, mang đến cho tổ chức phương tiện xử lý thông tin với tốc độ rất cao, lưu trữ thông tin với khối lượng rất lớn và truyền thông tin gần như tức thì và không giới hạn về khoảng cách. Những ưu việt đó vượt xa khả năng làm việc thủ công. Chúng giúp con người thực hiện những điều mà trong thế giới thủ công chỉ là mơ ước, với các ứng dụng ngày càng phong phú, đa dạng và phức tạp dựa trên những nền tảng công nghệ ngày một phát triển. Vì thế, nghiên cứu ứng dụng CNTT trong một tổ chức luôn dẫn đến mô hình ứng dụng (application model – tổ chức sẽ hoạt động như thế nào trong môi trường CNTT) và mô hình công nghệ (technology model – các ứng dụng được phát triển trên nền công nghệ nào).
Tổ chức là một thực thể thống nhất, nên mọi sự thay đổi ở một thành phần bên trong luôn luôn kéo theo sự thay đổi ở tất cả các thành phần còn lại. Khi CNTT xâm nhập vào tổ chức, làm thay đổi cách thức con người hoạt động thông tin bên trong tổ chức, kéo theo thay đổi cả về mô hình tổ chức lẫn mô hình thông tin. Nói theo ngôn ngữ quản lý, việc ứng dụng CNTT (hay điện tử hóa) chắc chắn làm thay đổi các quy trình làm việc thủ công (cải cách hành chính) theo hướng tạo điều kiện tốt nhất cho CNTT phát huy những năng lực phục vụ phù hợp với khả năng tiếp thu và phát triển của tổ chức.
Tổng hợp những ý trên dẫn chúng ta đến 4 hợp phần mà tất cả các phương pháp luận về CPĐT đều thống nhất lựa chọn là: Mô hình tổ chức + Mô hình thông tin (được xây dựng trên nền móng của chiến lược CPĐT về tổ chức); Mô hình ứng dụng + Mô hình công nghệ (được xây dựng trên nền móng của chiến lược CPĐT về CNTT).
|
Khung kiến trúc tổng thể
Kiến trúc của một tổ chức là một tập hợp các mô hình được dùng làm cơ sở để phân tích, giúp các nhà quản lý quyết định thực hiện những thay đổi cần thiết để đạt được mục đích và mục tiêu của tổ chức đó. Các mô hình này thực hiện vai trò giống như các bản kế hoạch chi tiết hướng dẫn và phối hợp nỗ lực của các bộ phận liên quan trong việc xây dựng mới hoặc thay đổi một tổ chức hiện tại.
Thực tiễn cho thấy trong những tổ chức lớn, các mô hình tổ chức tại những bộ phận khác nhau thường được xây dựng bởi các nhóm khác nhau. Các nhóm này thường có xu hướng tạo ra những sản phẩm kiến trúc chỉ đáp ứng yêu cầu của riêng chứ không thể áp dụng ở nơi khác, còn nếu muốn áp dụng thì phải hiệu chỉnh rất nhiều. Vì thế, khi một tổ chức muốn chuẩn hóa kết quả làm việc của tất cả các nhóm vào kiến trúc tổng thể thì biện pháp đầu tiên là thiết lập một khung kiến trúc tổng thể chung (EA).
Khó có thể xây dựng một khung EA duy nhất chung cho tất cả mọi trường hợp do sự khác nhau về lĩnh vực , trình độ quản lý, nguồn nhân lực, khả năng đầu tư, trang bị, cơ chế vận động… Từ đây, xuất hiện những cách tiếp cận khác nhau về xây dựng khung EA cho những lớp tổ chức khác nhau.
|
Người ta ghi nhận có 5 phương pháp được áp dụng nhiều nhất và được xem là có ảnh hưởng nhất:
• TOGAF (The Open Group Architecture Framework – Khung kiến trúc nhóm mở)
• The Zachman Framework (Khung Zachman)
• FEAF (Federal Enterprise Architecture Framework – Khung kiến trúc tổng thể kiểu liên bang)
• MDA (Model Driven Architecture – Kiến trúc được điều khiển bởi mô hình)
• EUP (Enterprise Unified Process – Quy trình hợp nhất tổ chức).
Mỗi phương pháp đưa ra một khung (framework) gồm nhiều mô hình con phân tích các khía cạnh khác nhau của kiến trúc cho một lớp tổ chức phù hợp. Trong số đó, theo ý kiến cá nhân, FEAF là phương pháp có cách diễn đạt sáng sủa và dễ hiểu hơn cả.
FEAF đặt tất cả các quy trình phát triển, từ kiến trúc nghiệp vụ, kiến trúc dữ liệu, kiến trúc ứng dụng và kiến trúc công nghệ hiện thời thông qua các mô hình kiến trúc và các quá trình chuyển đổi, chuẩn hóa để đạt tới kiến trúc nghiệp vụ, kiến trúc dữ liệu, kiến trúc ứng dụng và kiến trúc công nghệ tương lai trong một khung tổng thể thống nhất.
FEAF được sử dụng nhiều trong các tổ chức có trình độ phát triển tương đối cao, nơi hiện hữu môi trường ứng dụng tương đối đồng nhất. Nếu khởi đầu từ một môi trường ứng dụng không đồng nhất (có những ứng dụng được phát triển ở các cấp độ khác nhau trong cùng một tổ chức như thường thấy ở nước ta) thì TOGAF là phương pháp được xem là phù hợp.
|
TOGAF dựng lên một khung kiến trúc tổng thể gồm phần lõi và các thành phần mở rộng. Khung kiến trúc tổng thể lõi bao gồm:
• Kiến trúc nghiệp vụ: Mô tả các mục tiêu hoạt động, các hoạt động, các quy trình nghiệp vụ…
• Kiến trúc dữ liệu: Xác định các quan hệ giữa các tập hợp dữ liệu, các quy trình nghiệp vụ và dữ liệu
• Kiến trúc ứng dụng: Xác định mô hình ứng dụng, giao diện người – máy, cơ chế xử lý, các quy tắc nghiệp vụ
• Kiến trúc kỹ thuật: Thể hiện các mô hình dữ liệu vật lý, thiết kế hệ thống kỹ thuật, công nghệ và các cơ chế trình diễn, thiết kế các thủ tục và cơ chế kiểm soát.
Các thành phần mở rộng gồm:
• Các tiêu chuẩn, chính sách: Xác định các tiêu chuẩn, đề xuất các chính sách cho từng bộ phận cấu thành
• Kiến trúc an ninh: Xác định các yêu cầu và giải pháp về an ninh cho toàn bộ tổ chức, đặc biệt là an ninh dữ liệu
• Kiến trúc dịch vụ: Xác định cách thức cung cấp dịch vụ của tổ chức.
Đến tháng 11/2010, trong cả nước chỉ có TP.Đà Nẵng là đã xây dựng hoàn chỉnh kiến trúc tổng thể CPĐT (Kết quả của dự án CNTT-TT TP.Đà Nẵng). Khung kiến trúc tổng thể được đề xuất cho TP.Đà Nẵng có các thành phần được mô tả trong hình.
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.
Phiếm đàm về “òa” và “oà”
Và đây là kết quả:
Khoảng 23.500.000 kết quả (0,22 giây) cho “hòa bình”
Khoảng 8.780.000 kết quả (0,27 giây) cho “hoà bình”
Khoảng 6.970.000 kết quả (0,21 giây) cho “thỏa mãn”
Khoảng 2.860.000 kết quả (0,23 giây) cho “thoả mãn”
Khoảng 1.400.000 kết quả (0,15 giây) cho “giải tỏa”
Khoảng 1.440.000 kết quả (0,22 giây) cho “giải toả”
Khoảng 1.770.000 kết quả (0,27 giây) cho “khỏe mạnh”
Khoảng 1.990.000 kết quả (0,28 giây) cho “khoẻ mạnh”
Khoảng 576.000 kết quả (0,33 giây) cho “tung tóe”
Khoảng 224.000 kết quả (0,36 giây) cho “tung toé”
Khoảng 565.000 kết quả (0,34 giây) cho “mánh khóe”
Khoảng 135.000 kết quả (0,27 giây) cho “mánh khoé”
Khoảng 1.890.000 kết quả (0,16 giây) cho “tùy ý”
Khoảng 452.000 kết quả (0,40 giây) cho “tuỳ ý”
Khoảng 165.000 kết quả (0,27 giây) cho “thành lũy”
Khoảng 92.800 kết quả (0,34 giây) cho “thành luỹ”
Khoảng 437.000 kết quả (0,32 giây) cho “tiều tụy”
Khoảng 94.800 kết quả (0,32 giây) cho “tiều tuỵ”
Khoảng 80.700 kết quả (0,22 giây) cho “túy lúy”
Khoảng 26.000 kết quả (0,29 giây) cho “tuý luý”
Khoảng 246.000 kết quả (0,22 giây) cho “lũy kế”
Khoảng 386.000 kết quả (0,36 giây) cho “luỹ kế”
Chịu khó phân tích thấy cũng có nhiều thông tin từ các con số khô khan của Google:
1. Các từ càng phổ thông, càng có xu hướng viết kiểu cũ như “hòa bình”, “thỏa mãn”… Các từ ít phổ thông có lẽ khiến người viết phải cân nhắc lại chính tả khi viết nên xu hướng viết kiểu mới lại thắng thế như “giải toả”…
Tuy nhiên, cũng có người đưa ra ý kiến cho rằng “Không phải vậy, người ta quen viết kiểu cũ, viết kiểu mới là vì từ thời máy tính được dùng phổ biến thay máy chữ soạn thảo văn bản, thì các bộ gõ bị đặt mặc định kiểu gõ mới, nên họ buộc phải theo thôi, quay lui sửa mệt chứ không phải thích kiểu bỏ dấu mới! Chẳng hạn nếu không bật về kiểu gõ cũ thì khi muốn gõ “hòa” sẽ phải gõ “hò a” có dấu cách ở giữa, rồi quay lui 1, xóa dấu cách, rồi lại tiến lên 1, tính ra phải thêm đến 4 lần bấm phím”
2. Chịu khó xem viết trong văn bản nào, có thể thấy các tác phẩm văn học thường in theo kiểu cũ
3. Các từ thuộc nhóm KHXH thiên về kiểu cũ (75% cho túy lúy)
4. Các từ nhóm KHKT lại nghiêng theo kiểu mới (61% cho luỹ kế)
5. Xu hướng viết cân đối mỹ thuật vẫn còn nhiều người ủng hộ: kết quả về tiều tụy/tiều tuỵ ở trên cho thấy rõ là khi kiểu viết mới mất cân đối rõ rệt thì tỷ lệ ủng hộ rất thấp (chỉ có 18% cho tiều tuỵ). Khi cắt khẩu hiệu, băng rôn treo ngoài đường phố thì chữ rất to, vấn đề cân đối cũng thấy rõ nên xu hướng chọn kiểu viết cũ cũng thắng thế, xem dạng font cỡ lớn ở dưới sẽ hiểu:
HÒA , HOÀ
Với tình hình khảo sát thống kê ở trên, người viết trộm nghĩ giá hồi xưa người ta đừng đứng ra phát động cuộc cải cách về dấu trên các vần oa, oe, uy thì biết đâu chính tả tiếng Việt bây giờ sẽ đỡ lộn xộn hơn? Người viết từng có dịp trao đổi với cụ Nguyễn Tài Cẩn, GS đầu ngành ngôn ngữ học của Việt Nam. Khi nhắc tới vấn đề này, thì thấy GS có vẻ không quan tâm và không bình luận đúng sai gì cả. Cá nhân người viết cho rằng đặt dấu trên nguyên âm chính có vẻ “khoa học” hơn, nhưng những người đặt dấu trên âm đệm -o-, -u- cũng có cái lý của họ (mà không cần viện dẫn lý do “cân đối”, “mỹ thuật” đâu nhé).
Vấn đề là, thanh điệu vốn là thuộc tính của cả từ chứ không phải là “độc quyền” của nguyên âm chính. Do quán tính vật lý của bộ máy phát âm nên khó có thể ngay lập tức thay đổi cao độ của từ chỉ trong khoảng thời gian ngắn của âm chính, nên các âm đệm trước (-o-,-u-) và sau âm chính (như -i ở vần -ai, -oi) ít nhiều cũng tham gia vào việc thể hiện thanh điệu. Ngay cả phát âm các phụ âm cuối cũng có thể biến đổi ít nhiều phụ thuộc vào thanh điệu cả từ.
Có lẽ những người phát minh dấu điện tín tiếng Việt (telex) cũng đã nắm khá rõ vấn đề này nên quy tắc điện tín chuẩn thời xưa là bỏ dấu (f,j,r,s,x) ở cuối từ, chứ không phải đính sau một nguyên âm nào cả. Người viết nhớ, khi nhóm cải cách muốn “giác ngộ” quần chúng, họ đã yêu cầu thử đọc tách rời hò-a và ho-à để xem cách nào sát âm “hòa” hơn… Quả thực ho-à sát hơn, nhưng cách làm đó chưa công bằng, vì tách âm đúng hơn nữa phải là hò-à, dấu không thuộc riêng một nguyên âm nào.
Như vậy viết “hòa” theo kiểu cũ, cho dấu nằm ngay giữa từ, chính là để nhắc người đọc rằng dấu thanh vốn thuộc về cả từ, cũng có logic lắm chứ? Nếu thực sự cần phát động một cuộc “cách mạng chữ viết” thì còn rất nhiều cái đáng phải sửa chữa hơn là quy tắc bỏ dấu trên 3 vần đó. Chẳng hạn:
- Trong các vần -ay, -au thì “a” là nguyên âm a ngắn, chính tả thông thường viết là “ă”. Như vậy tau, say, mày, mau… phải viết tău, săy, mằy, mău… Khi đọc thấy điều “nằy” trong cuốn giáo trình lịch sử ngữ âm tiếng Việt của GS Cẩn, người viết rất bất ngờ, té ra lâu “năy” mình dốt.
- Trong các vần -ay, -au khó nhận ra nguyên âm nào là âm chính, nhưng dựa vào các ví dụ như ni = nay, thu = thâu thì lại có thể cho rằng âm chính là -y và -u? Như vậy, nếu theo logic dấu phải đặt trên âm chính thì lại phải sửa thêm rất nhiều trường hợp như mày => măỳ, máu => măú…
- Tiếng Việt còn nhiều cặp nguyên âm kép khá cân bằng về độ dài và cường độ tương đối, rất khó nhận ra âm nào là chính. Như vậy, nếu yêu cầu phải đặt dấu trên âm chính thì sẽ rất khó cho người bình thường không có máy móc kỹ thuật đo đạc chính xác trường độ, cường độ, tần số âm thanh…?
- Phụ âm “Ph” có bật hơi thời Alexandre De Rhodes hầu như đã biến mất khỏi tiếng Việt, chuyển thành “F”, nên chính tả hiện đại phải là “F”.
- Âm đệm -o-, -u- thực chất chỉ là một, có thể viết là -w- . Nhưng trong một số vần như -oi , -ui thì -o-, -u- lại là âm chính chứ không phải âm đệm, nên nếu cải cách thì có lẽ vấn đề sẽ rất phức tạp, bởi tùy địa phương và thời đại mà có thể nguyên âm thứ nhất mạnh hơn (là âm chính) hay suy giảm (trở thành âm đệm).
- “Q” nên viết là “K”?
- “Gi” có thể viết là “j”, “d” là “z”, “đ” là “d” .v.v…
- So với các vấn đề “nằy” thì chuyện “òa”, “oà” là chuyện nhỏ, nhưng nói ra cũng dễ bị… “chọi đá”. Đã làm cách mạng thì phải triệt để. Cuộc cải cách nửa vời nói trên đã gây ra tình trạng hỗn loạn không đáng có cho chính tả tiếng Việt thời @!
Nhân tiện bàn thêm: Vấn đề truyền thống văn hóa cũng rất quan trọng. Chữ quốc ngữ đã có lịch sử gần 500 năm, văn học viết bằng chữ quốc ngữ cũng đã có hơn một thế kỷ, nếu vứt bỏ để theo hệ thống chính tả mới, các tiểu thuyết, thi ca thời tiền chiến sẽ phải đem ra phiên dịch lại? Có lẽ lý do tương tự mới giải thích được vì sao người Anh, Mỹ không cải tiến chính tả tiếng Anh dù chính tả tiếng Anh đã nổi tiếng thế giới về lối viết một đằng, đọc một nẻo?