Hình bên trên chỉ ra vị trí của 4 nhóm thiết kế mẫu Ajax trong một ứng dụng Ajax. Các mẫu trong 3 nhóm đầu là về sản phẩm, trong khi nhóm còn lại, Development patterns là về tiến trình. Trong các mẫu hƣớng sản phẩm, Foundational Technologies giải thích làm thế nào sử dụng các công nghệ web thô nhƣ là XMLHttpRequest và DOM. Ở mức trung bình là Programming Patterns, hƣớng dẫn các kế hoạch sử dụng các công nghệ này. Ở mức cao là các Functionality and Usability patterns. Foundational Technology Patterns là lõi của ngôn ngữ mẫu Ajax. Các nhóm còn lại tất cả đƣợc xây dựng trên đó, và khá độc lập với những nhóm khác.
4.3. Ứng dụng mẫu thiết kế trong thiết kế khung cho tầng truy cập dữ liệu
4.3.1. Đặt vấn đề
Khi xây dựng phần mềm, lập trình viên thƣờng quan tâm đến hệ cơ sở dữ liệu mà ứng dụng sẽ tƣơng tác. Điều này có một trở ngại là khi ngƣời dùng thay đổi hệ dữ liệu thì chƣơng trình không thực hiện đƣợc, hoặc phải cài đặt lại.
Một trƣờng hợp khác là một số phần mềm tƣơng tác với nhiều hệ cơ sở dữ liệu khác nhau, nhƣ: DB2, MySQL, SQLServer, Oracle, …. Lúc này buộc phải cài đặt các điều khiển truy cập dữ liệu theo yêu cầu. Điều này phát sinh một số vấn đề: tài nguyên cơ sở dữ liệu đƣợc khởi tạo chậm, mã cài đặt truy cập dữ liệu phức tạp, cồng kềnh dẫn đến khó phát triển và bảo trì.
Dựa trên lý thuyết thiết kế chƣơng trình theo mô hình ba tầng (3-Layer), luận văn áp dụng các mẫu thiết kế (Factory Method, Singleton và Null Object) để thiết kế và cài đặt Framework cho tầng truy cập dữ liệu một cách tổng quát, sử dụng đối tƣợng ADO.Net nhằm khắc phục những nhƣợc điểm nêu trên.
4.3.2. Mô hình 3 tầng
Ngày nay, đa phần các ứng dụng dựa trên mô hình 2-tầng Client/Server, trong đó tất cả mã lệnh về giao diện ngƣời dùng (UI), logic nghiệp vụ (Business logic) và truy cập dữ liệu (Data access) đƣợc viết “bên dƣới” tầng giao diện. Việc ứng dụng mô hình 2-tầng làm cho ngƣời phát triển ban đầu dễ triển khai và thời gian ngắn. Tuy nhiên có nhƣợc điểm là: khó thay đổi theo các nghiệp vụ khi chúng bị thay đổi do yêu cầu thực tế, khó bảo trì, tích hợp và không có khả năng kế thừa.
Để quản lý các thành phần hệ thống một cách độc lập, không ảnh hƣởng bởi các thay đổi, ngƣời ta nhóm những thành phần có cùng chức năng với nhau, phân chia nhiệm vụ cho từng nhóm để công việc không bị chồng chéo và ảnh hƣởng lẫn nhau. Khi đó, ngƣời ta dùng kiến trúc đa tầng (hay nhiều tầng), mỗi tầng thực hiện một chức năng nào đó, trong đó mô hình 3-tầng do MicroSoft đề xuất là phổ biến nhất, gồm: tầng trình diễn PL (Presentation Layer), tầng nghiệp vụ BL (Business Layer) và tầng dữ liệu DL (Data Layer).
Mỗi tầng tƣơng ứng với một trong ba phần tử cần thiết trong một kiến trúc ứng dụng: tƣơng tác, thao tác và lƣu trữ. Cụ thể nhƣ sau:
PL: giao tiếp với ngƣời dùng cuối để thu thập dữ liệu và hiển thị kết quả / dữ liệu thông qua các thành phần giao diện ngƣời dùng.
BL: thao tác thông tin theo yêu cầu của bài toán và ngƣời sử dụng.
DL: tổ chức lƣu trữ và truy xuất dữ liệu.
Các tầng này giao tiếp với nhau thông qua các dịch vụ mà mỗi tầng cung cấp để tạo nên ứng dụng. Tầng này không cần biết bên trong tầng kia làm gì mà chỉ quan tâm tầng kia cung cấp dịch vụ gì cho mình và sử dụng nó. Giao diện ngƣời dùng không gọi trực tiếp tầng DL và ngƣợc lại, vì lý do an toàn và các giao tác thƣờng đƣợc quản lý trong tầng BL. Tất cả các trao đổi với cơ sở dữ liệu phải thông qua giao diện dịch vụ trong tầng BL.
4.3.3. Cài đặt mô hình khung cho tầng truy cập dữ liệu
Để dễ hình dung ta có thể xét một mô hình ứng dụng đƣợc thiết kế theo mô hình 3-tầng nhƣ hình dƣới. Tầng DL lƣu trữ và truy xuất dữ liệu, đƣợc chia thành hai phần: DataAccess và DataStorage:
DataStorage: lƣu trữ dữ liệu và thực hiện các dịch vụ của hệ quản trị cơ sở dữ liệu nhƣ SQL Server, Oracle, DB2, MySQL, …
DataAccess: gồm các đối tƣợng tác nghiệp (Business Object) và đối tƣợng kết nối, truy cập dữ liệu. Business Object cung cấp dịch vụ từ tầng DL cho tầng trên, nhƣ các dịch vụ: chèn, cập nhật, xóa dữ liệu.
Tầng PL và DL độc lập nhau, trao đổi với nhau qua tầng BL. Do đó, việc thay đổi hệ quản trị cơ sở dữ liệu SQL Server thành Oracle, Oracle thành DB2,… hay ngƣợc lại thì giao diện chƣơng trình vẫn không thay đổi.
Trong cài đặt khung cho tầng truy cập dữ liệu tổng quát, ta xây dựng các Business Object dựa trên đối tƣợng ADO.Net để cung cấp dịch vụ cho tầng BL và bảo đảm sự độc lập giữa hai tầng PL và DL.
Có một cách là xây dựng một lớp dịch vụ có phƣơng thức chứa điều khiển switch để biết đƣợc kiểu của điều khiển truy cập cơ sở dữ liệu nào đƣợc thực hiện, rồi cài đặt mã tƣơng tác tƣơng ứng. Giả sử phƣơng thức này đƣợc cài đặt nhƣ sau :
public override void MyProcedure(proType ProviderType){ switch(proType){ case ProviderType.SqlClient: objSqlCommand.SqlProcedure () break; case ProviderType.OleDb: objOleDbCommand.QleDbProcedure()
break; default: … break; } }
Cách thiết kế và cài đặt nhƣ trên có một số nhƣợc điểm: mã lệnh cài đặt nhiều do phải viết lại những đoạn mã tƣơng tự nhau, phức tạp và đôi khi là không cần thiết. Mặt khác khi muốn truy cập cơ sở dữ liệu mới thì phải cài đặt và biên dịch lại lớp này. Giải quyết vấn đề này bằng cách sử dụng các mẫu Factory Method, Singleton và Null Object để cài đặt một Framework cho tầng truy cập dữ liệu tổng quát. Biểu đồ lớp cho bài toán đƣợc trình bày trong hình dƣới, trong đó, lớp DataAccessBaseClass và các lớp kế thừa nó là các Business Object chứa các dịch vụ cung cấp cho tầng BL tƣơng tác với cơ sở dữ liệu.
Hình 4.18. Biểu đồ lớp của tầng truy cập dữ liệu
Lớp DataAccessBaseClass là lớp Product gồm các thuộc tính và phƣơng thức tổng quát để tƣơng tác với các hệ cơ sở dữ liệu, các phƣơng thức này là các phƣơng thức đƣợc nạp chồng.
Các lớp OdbcDataAccess, OleDbDataAccess, OracleDataAccess, SqlDataAccess, NullObject (là các lớp ConcreteProduct) đƣợc kế thừa từ lớp DataAccessBaseClass và cài đặt chi tiết phƣơng thức GetDataProviderConnection() (trả về đối tƣợng chuỗi kết nối đến hệ cơ sở dữ liệu tƣơng ứng) và
thể. Lớp NullObject cài đặt phƣơng thức thực thi các ứng xử mặc định ngoài các hành vi của các đối tƣợng của các lớp còn lại.
Phƣơng thức GetDataAccessLayer() là phƣơng thức static đƣợc nạp chồng, nhận một tham số có kiểu ProviderType (gồm một trong các giá trị : Odbc, OleDb, Oracle, Sql) để quyết định đối tƣợng ứng với điều khiển truy cập dữ liệu (Data Provider) nào sẽ đƣợc tạo ra. Nội dung của lớp chứa phƣơng thức này nhƣ sau :
public class ConcreteCreator : Creator{ private ConcreteCreator() {}
//Lấy giá trị được thiết lập trong tệp tin cấu hình
private static string GetAppSetting(string setting){ string val;
try {
val = System.Configuration.ConfigurationSettings. AppSettings[setting].ToString();
}
catch (NullReferenceException e){ val = ""; } if (val == null) val = ""; return val; }
/*Lấy chuỗi kết nối database bằng cách đọc trong tệp tin cấu hình (app.config)*/
private static string GetConnectionString(){ string val;
val = "server=" + GetAppSetting("Datasource") + ";database=" + GetAppSetting("Database") +
";uid=" + GetAppSetting("Userid") + ";pwd=" + GetAppSetting("Password") + ((GetAppSetting("Timeout").Length > 0) ?
";Connection Timeout=" + GetAppSetting("Timeout"): ""); return val;
}
/*Xây dựng một data provider của tầng truy cập dữ liệu dựa trên các thiết lập cấu hình ứng dụng. Tập tin cấu hình ứng dụng phải chứa 2 key:
1. "DataProviderType" key : giá trị của nó là một trong các giá trị được định nghĩa (sql,oracle,access,odbc,oledb)
2. "ConnectionString" key : chuỗi kết nối database*/
public static DataAccessBaseClass GetDataAccessLayer(){ if (GetAppSetting("DataProviderType") == null
||GetAppSetting("Datasource") == null || GetAppSetting("Database") == null)
throw new ArgumentNullException("Chưa chỉ định 'DataProviderType' hoặc chưa chỉ định 'Server' hoặc chưa chỉ định 'Database' trong tệp tin cấu hình");
DataProviderType dataProvider; try{ dataProvider= (DataProviderType)System.Enum.Parse(typeof(DataProviderTy pe),GetAppSetting("DataProviderType")); } catch(Exception e){
throw new ArgumentException("Kiểu provider cho tầng truy cập dữ liệu không hợp lệ.");
}
return getDataAccessLayer(dataProvider,GetConnectionString()); }
/*Xây dựng một data provider của tầng truy cập dữ liệu dựa Provider được cung cấp. Chuỗi connection được lấy từ thuộc tính ConnectionString của lớp DataAccessBaseClass*/
public static DataAccessBaseClass
GetDataAccessLayer(DataProviderType dataProviderType){ return GetDataAccessLayer(dataProviderType, null); }
/*Xây dựng một data provider của tầng truy cập dữ liệu dựa Provider và chuỗi connection được cung cấp*/
public static DataAccessBaseClass
GetDataAccessLayer(DataProviderType dataProviderType, string connectionString) {
switch (dataProviderType){
case DataProviderType.OleDb:
return new OleDbDataAccess(connectionString); case DataProviderType.Odbc:
return new OdbcDataAccess(connectionString); case DataProviderType.Oracle:
return new OracleDataAccess(connectionString); case DataProviderType.Sql:
return new SqlDataAccess(connectionString); default:
return new NullObject (connectionString); }
}
Để sử dụng Framework này ta chỉ cần gọi phƣơng thức GetDataAccessLayer sử dụng hai tham số DataProviderType và ConnectionString để lấy về đối tƣợng điều khiển thao tác với hệ cơ sở dữ liệu tƣơng ứng. Các tham số đƣợc ngƣời dùng cung cấp
<appSettings>
<add key="DataProviderType" value="Sql" /> <add key="Database" value="MyDatabase" /> <add key="Datasource" value="localhost" /> <add key="Userid" value="test" />
<add key="Password" value="123456" /> <add key="Timeout" value="" />
</appSettings> </configuration>
4.4. Tổng kết chƣơng
Vận dụng các nguyên lý và phƣơng pháp thiết kế mẫu phần mềm đã đƣa ra, luận văn mô tả 4 mẫu thiết kế theo định dạng GOF. Đó là các mẫu thiết kế đƣa ra giải pháp cho những vấn đề hay gặp trong phân tích thiết kế hƣớng đối tƣợng. Luận văn cũng đã sử dụng 3 mẫu thiết kế Factory Method, Singleton và Null Object để cài đặt cho tầng truy cập dữ liệu tổng quát, nhƣ một ví dụ cho tính khả dụng và hiệu quả của mẫu thiết kế phần mềm.
Khi các mẫu thiết kế phần mềm đã đƣợc sử dụng rộng rãi và chứng minh tính hiệu quả của nó trong thiết kế phần mềm hƣớng đối tƣợng, đồng thời với sự xuất hiện của thế hệ web 2.0 (dựa trên công nghệ Ajax), ngƣời ta đã ứng dụng và phát triển các mẫu thiết kế cho ứng dụng web trên công nghệ Ajax. Đến nay đã phát triển đƣợc trên 60 mẫu thiết kế Ajax, tuy nhiên vẫn hứa hẹn nhiều tiềm năng phát triển. Đây là một hƣớng nghiên cứu phát triển mới và rất rộng, luận văn chỉ đƣa ra tổng quan về vấn đề này. Việc nghiên cứu sâu hơn xin để cho những quan tâm tiếp sau.