Đề tài Ứng dụng kỹ thuật tái cấu trúc mã nguồn để triển khai dò tìm và cải tiến các đoạn mã xấu trong chương trình C#
Luận văn thạc sĩ chuyên ngành khoa học máy tính
CHƯƠNG I: KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN (REFACTORING)
I.1 ĐỊNH NGHĨA KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN
I.1.1 Ví dụ minh họa
I.1.2 Định nghĩa kỹ thuật tái cấu trúc mã nguồn
I.2 HIỆU QUẢ CỦA TÁI CẤU TRÚC MÃ NGUỒN
I.2.1 Refactoring cải thiện thiết kế phần mềm
I.2.2 Refactoring làm mã nguồn phần mềm dễ hiểu
I.2.3 Refactoring giúp phát hiện và hạn chế lỗi
I.2.4 Refactoring giúp đấy nhanh quá trình phát triển phần mềm
I.3 KHI NÀO THỰC HIỆN TÁI CẤU TRÚC MÃ NGUỒN
I.3.1 Refactor khi thêm chức năng
I.3.2 Refactor khi cần sửa lỗi
I.3.3 Refactor khi thực hiện duyệt chương trình
I.4 CÁC KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN
I.4.1 Danh mục các kỹ thuật tái cấu trúc mã nguồn
I.5 NHẬN XÉT VÀ KẾT LUẬN
CHƯƠNG II: LỖI CẤU TRÚC (BAD SMELLS) TRONG MÃ NGUỒN
II.1 KHÁI NIỆM VỀ LỖI CẤU TRÚC (BAD SMELLS)
II.2 LỖI CẤU TRÚC VÀ GIẢI PHÁP CẢI TIẾN
II.2.1 Duplicated Code - Trùng lặp mã
II.2.2 Long Method – Phương thức phức tạp
II.2.3 Large Class – Qui mô lớp lớn
II.2.4 Long Parameter List - Danh sách tham số quá dài
II.2.5 Divergent Change – Cấu trúc lớp ít có tính khả biến
II.2.6 Shotgun Surgery – Lớp được thiết kế không hợp lý và bị phân rã
II.2.7 Feature Envy – Phân bố phương thức giữa các lớp không hợp lý
II.2.8 Data Clumps – Gôm cụm dữ liệu
II.2.9 Primitive Obsession – Khả năng thể hiện dữ liệu của lớp bị hạn chế
II.2.10 Switch Statements – Khối lệnh điều kiện rẽ hướng không hợp lý
II.2.11 Lazy Class – Lớp được định nghĩa không cần thiết
II.2.12 Speculative Generality – Cấu trúc bị thiết kế dư thừa
II.2.13 Temporary Field – Lạm dụng thuộc tính tạm thời
II.2.14 Message Chains –Chuỗi phương thức liên hoàn khó kiểm soát
II.2.15 Middle Man – Quan hệ ủy quyền không hợp lý/logic
II.2.16 Inapproprite Intimacy - Cấu trúc thành phần riêng không hợp lý
II.2.17 Alternative Classes with Different Interfaces - Đặc tả lớp không rõ ràng
II.2.18 Incomplete Library Class – Sử dụng thư viện lớp chưa được hòan chỉnh
II.2.19 Data Class – Lớp dữ liệu độc lập
II.2.20 Refused Bequest – Quan hệ kế thừa không hợp lý/logic
II.2.21 Comments – Chú thích không cần thiết
II.3 NHẬN XÉT VÀ KẾT LUẬN
CHƯƠNG III: NỀN TẢNG .NET VÀ NGÔN NGỮ LẬP TRÌNH C#
III.1 TỔNG QUAN VỀ NỀN TẢNG .NET
III.1.1 Định nghĩa .NET
III.1.2 Mục tiêu của .NET
III.1.3 Dịch vụ của .NET
III.1.4 Kiến trúc của .NET
III.2 NGÔN NGỮ LẬP TRÌNH C#
III.2.1 Tổng quan về ngôn ngữ lập trình C#
III.2.2 Đặc trưng của các ngôn ngữ lập trình C#
III.3 MÔI TRưỜNG PHÁT TRIỂN ỨNG DỤNG VISUAL STUDIO .NET
CHƯƠNG IV: ỨNG DỤNG KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN ĐỂ DÒ TÌM VÀ CẢI TIẾN CÁC ĐOẠN MÃ XẤU TRONG CHưƠNG TRÌNH C#
IV.1 GIẢI PHÁP VÀ CÔNG CỤ HỖ TRỢ REFACTOR
IV.1.1 Đặc tả giải pháp triển khai
IV.1.2 Một số công cụ và tiện ích hỗ trợ việc dò tìm và cải tiến mã xấu
IV.1.3 Thử nghiệm minh họa các công cụ hỗ trợ refactor trong VS.Net
IV.1.4 Nhận xét và đánh giá
IV.2 ỨNG DỤNG KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN ĐỂ DÒ TÌM VÀ CẢI TIẾN CÁC ĐOẠN MÃ XẤU TRONG CHưƠNG TRÌNH C#
IV.2.1 Thực hiện kỹ thuật tái cấu trúc mã nguồn trên chương trình thực tế
IV.2.2 Phân tích và đánh giá kết quả thực hiện
IV.3 NHẬN XÉT VÀ KẾT LUẬN
CHƯƠNG V: KẾT LUẬN
V.1 ĐÁNH GIÁ KẾT QUẢ CỦA ĐỀ TÀI
V.2 PHẠM VI ỨNG DỤNG
V.3 HƯỚNG PHÁT TRIỂN
V.3.1 Triển khai áp dụng trên các ngôn ngữ khác
V.3.2 Thử nghiệm xây dựng một refactoring tool tích hợp vào VS.NET
99 trang |
Chia sẻ: lvcdongnoi | Lượt xem: 2298 | Lượt tải: 0
Bạn đang xem trước 20 trang tài liệu Đề tài Ứng dụng kỹ thuật tái cấu trúc mã nguồn để triển khai dò tìm và cải tiến các đoạn mã xấu trong chương trình C#, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
chƣơng trình tiện ích do Xtreme Simplicity phát triển có khả
năng tích hợp vào Visual Studio cho phép thực hiện một số chức năng refactoring trên
mã nguồn chƣơng trình C#.
C# Refactory for Visual Studio .NET cung cấp một số kỹ thuật refactoring:
- Change Method Signature
- Copy Class
- Decompose Conditional
- Encapsulate Field
- Extract Class
- Extract Interface
- Extract Method
- Extract Superclass
- Extract Variable
- Push Up Members
- Rename Local Variable
- Rename Member
- Rename Parameter
- Rename Type
Hình 4.4: Màn hình trình chức năng refactor của C# Refactory for Visual Studio .NET
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 53
♦ .NET Refactor for C# & VB.NET [12]
.NET Refactor là một tiện ích do KnownDotNet phát triển, có khả năng tích hợp
vào Visual Studio .NET để hỗ trợ một số kỹ thuật refactoring trên các mã nguồn của
chƣơng trình C# và VB.NET:
- Extract Expression to Function
- Extract Method
- Extract Interface
- Extract Object
- Extract Superclass
- Insert Const or String
- Promote Local Variables
- Simlify Conditional
- Stub New Method
- Refactor Strings
- Rename Local Variable
- Rename Parameters
- Reorder Variables
- Replace Magic Number
Hình 4.5: Màn hình trình chức năng refactor của .NET Refactor for C# & VB.NET
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 54
♦ CodeIT.Once for .NET [8]
CodeIT.Once for .NET là một trong các công cụ hỗ trợ phát triển phần mềm do
vbCity.com và DevCity.Net phát triển. CodeIT.Once đƣợc tích hợp vào Visual Studio và
cung cấp một số chức năng refactor trên mã nguồn 2 ngôn ngữ C# và VB.NET.
Danh mục các kỹ thuật refactoring hỗ trợ trong CodeIT.Once for .NET:
- Add Parameter
- Convert Method To Property
- Convert Property To Method
- Decompose Conditional
- Inline Variable
- Introduce Constant
- Encapsulate Field
- Extract Interface
- Extract Method
- Move Class
- Promote Local Variable to Parameter
- Remove Parameters
- Rename Fileds
- Rename Local Variables
- Rename Methods
- Rename Parameters
- Rename Types
- Reorder Parameters
Hình 4.6: Màn hình trình chức năng refactor của CodeIT.Once for .NET
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 55
♦ JetBrains ReSharper [10]
Tiện ích ReSharper đƣợc công ty phát triển giải pháp và công cụ phần mềm
JetBrains xây dựng có khả năng tích hợp vào Visual Studio nhằm hỗ trợ các lập trình
thực hiện refactoring trên các mã nguồn chƣơng trình C#, VB/ASP.Net và XML.
Danh mục các kỹ thuật refactoring hỗ trợ trong JetBrains ReSharper:
- Change Method Signature
- Convert Abstract Class to Interface
- Convert Anonymous to Named Type
- Convert Extension Method to Plain Static
- Convert Interface to Abstract Class
- Convert Method to Property
- Convert Property to Method
- Convert Static to Extension Method
- Encapsulate Field
- Extract Class
- Extract Superclass
- Extract Interface
- Extract Method
- Inline Method
- InlineVariable
- Introduce Parameter
- Introduce Variable
- Pull Down Members
- Pull Up Members
- Rename
- Replace Constructor with
Factory Method
Hình 4.7: Màn hình trình chức năng refactor của JetBrances ReShape
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 56
♦ DevExpress Refactor!™ Pro [9]
Danh mục các kỹ thuật refactoring hỗ trợ trong DevExpress Refactor!™ Pro:
- Add to Interface
- Combine Conditionals
- Convert Method to Property
- Convert Property to Method
- Decompose Conditional
- Decompose Parameter
- Encapsulate Field
- Extract Class
- Extract Interface
- Extract Method
- Extract Property
- Introduce Constant
- Introduce Parameter
- Introduce Variable
- Promote Local Variable to Parameter
- Simplify/Split Conditional
- Simplify Expression
- Rename
- Remove Redundant Assignment
- Remove Redundant Conditional
- Reorder Parameters/Variables
- Replace Temp with Query
Hình 4.8: Màn hình trình chức năng refactor của DevExpress Refactor!™ Pro
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 57
IV.1.3 Thử nghiệm minh họa các công cụ hỗ trợ refactor trong VS.Net
Dựa trên các chức năng refactoing trong các công cụ tiện ích đƣợc tích hợp vào
Visual Studio .NET. Phần nội dung dƣới dây sẽ hiện thực minh họa việc áp dụng một số
kỹ thuật refactoring trong việc dò tìm và cải tiến mã xấu trong mã nguồn chƣơng trình
C#:
- Change Signature
- Convert Method to Property
- Decompose/ Simplify Conditional
- Encapsulate Field
- Extract Interface
- Extract Method
- Inline Variable
- Promote Local Variable to Parameter
- Rename
♦ Change Signature
Change Signature cho phép thực hiện việc thay đổi tính chất/đặc trƣng của một
phƣơng thức: thêm mới, xóa bới, hoán đổi trật tự hoặc thay đổi kiểu các tham số cũng
nhƣ kiểu trả về của phƣơng thức
Xét đoạn chƣơng trình thực hiện phƣơng thức Add để giá trị của cộng 2 số nguyên:
public class Calculator
{
public int Add(int number1, int number2)
{
return number1 + number2;
}
}
Một trong những dấu hiệu có thể nhận biết và tái cấu trúc của đoạn chƣơng trình
này là chuyển đối kiểu của tham số và trả về phƣơng thức từ kiểu int sang double để có
phạm vi hoạt động rộng hơn.
public class Calculator
{
public double Add(double number1, double number2)
{
return number1 + number2;
}
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 58
Hình 4.9: Màn hình minh họa kỹ thuật Change Signature trong JetBrains ReSharper
Hình 4.10: Màn hình kết quả minh họa kỹ thuật Change Signature
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 59
♦ Convert Method to Property
Convert Method to Property cho phép chuyển đổi các phƣơng thức truy vấn (get)
và thiết lập (set) trên một trƣờng dữ liệu thành các đặc tính của trƣờng dữ liệu đó trong
lớp.
Xét đoạn chƣơng trình có nội dung nhƣ sau:
namespace RefactoringExamples
{
class Foo
{
static int x;
public static int GetX()
{
return x;
}
public static void SetX(int value)
{
x = value;
}
public static void bar()
{
int myX = Foo.GetX();
Foo.GetX() = myX + 1;
}
}
}
Ta thấy rằng để truy xuất và gán giá trị cho biến x trong lớp Foo phải thông qua 2
hàm là SetX() và GetX() trông rất bất tiện và không tự nhiên. Bây giờ chúng ta sẽ có một
cách đơn giản hơn là chuyển đổi các phƣơng thức trên sang tính chất properties của
trƣờng dữ liệu x thông qua kỹ thuật Convert Method to Property
Kết quả sau khi chuyển đổi sẽ nhƣ sau:
namespace RefactoringExamples
{
class Foo
{
static int x;
public static int X
{
get { return x; }
set { x = value; }
}
public static void bar()
{
int myX = Foo.X;
Foo.X = myX + 1;
}
}
}
Bây giờ chƣơng trình trông gọn gàng, dễ nhìn và tự nhiên hơn khi sử dụng.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 60
Hình 4.11: Màn hình minh họa kỹ thuật Convert Method to Property của CodeIT.Once
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 61
Hình 4.12: Màn hình minh họa kỹ thuật Convert Method to Property của ReSharper
Hình 4.13: Màn hình kết quả kỹ thuật Convert Method to Property
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 62
♦ Decompose/Simplify Conditional
Decompose/Simplify Conditional cho phép thực hiện việc chuyển đổi/đơn giản
hóa một biểu thức phức tạp trong thân mệnh đề điều kiện if thành một phƣơng thức có
kiểu trả về kiểu luận lý (đúng hoặc sai)
public class SampleApp
{
public const string SummerStart = "6/1/2005 12:00:00 AM";
private const string SummerEnd = "8/31/2005 12:00:00 AM";
private static float _winterRate = 5.0;
private static float _summerRate = 5.4;
private static double CalculateCharge(int quantity)
{
int charge;
System.DateTime chargeDate = System.DateTime.Now;
if (System.DateTime.Compare(chargeDate, SummerStart) > 0 |
System.DateTime.Compare(chargeDate, SummerEnd) < 0)
{
charge = quantity * _winterRate;
}
else
{
charge = quantity * _summerRate;
}
return charge;
}
}
Kết quả sau khi biến đổi làm cho chƣơng trình rõ ràng hơn
public class SampleApp
{
public const string SummerStart = "6/1/2005 12:00:00 AM";
private const string SummerEnd = "8/31/2005 12:00:00 AM";
private static float _winterRate = 5.0;
private static float _summerRate = 5.4;
private static double CalculateCharge(int quantity)
{
int charge;
if (IsSummerDate())
{
charge = quantity * _winterRate;
}
else
{
charge = quantity * _summerRate;
}
return charge;
}
private static IsSummerDate()
{
System.DateTime chargeDate = System.DateTime.Now;
return (System.DateTime.Compare(chargeDate, SummerStart) > 0 |
System.DateTime.Compare(chargeDate, SummerEnd) < 0);
}
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 63
Hình 4.14: Màn hình minh họa kỹ thuật Decompose/Simplify Conditional
Hình 4.15: Màn hình kết quả kỹ thuật Decompose/Simplify Conditional
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 64
♦ Encapsulate Field
Encapsulate Field cho phép chuyển đổi và đóng gói các trƣờng dữ liệu trong lớp.
Một chƣơng trình đƣợc thiết kế nhƣ sau:
public struct MyPoint
{
public int x;
public int y;
public void SetLocation()
{
Console.Write("Enter X position: ");
x = int.Parse(Console.ReadLine());
Console.Write("Enter Y position: ");
y = int.Parse(Console.ReadLine());
}
public void PrintLocation()
{
// Print new location.
Console.WriteLine("[{0}, {1}]", x, y);
}
}
Lỗi dễ nhận thấy nhất trong thiết kế này là các trƣờng dữ liệu x, y của cấu trúc
MyPoint đƣợc khai báo dƣới dạng public thay vì nên đƣợc khai báo private để đảm bảo
sự đóng gói cần thiết.
Sử dụng kỹ thuật Encapsulate Field để tái cấu trúc mã nguồn chƣơng trình này
public struct MyPoint
{
private int x;
public int X
{
get { return x; }
set { x = value; }
}
private int y;
public int Y
{
get { return y; }
set { y = value; }
}
public void SetLocation()
{
Console.Write("Enter X position: ");
X = int.Parse(Console.ReadLine());
Console.Write("Enter Y position: ");
Y = int.Parse(Console.ReadLine());
}
public void PrintLocation()
{
// Print new location.
Console.WriteLine("[{0}, {1}]", X, Y);
}
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 65
Hình 4.16: Màn hình minh họa kỹ thuật Encapsulate Field của Refactor trong VS.NET
Ghi chú: Áp dụng trên cả 2 biến x và y
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 66
Hình 4.17: Màn hình minh họa kỹ thuật Encapsulate Field của Visual Assit X for .NET
Hình 4.18: Màn hình kết quả kỹ thuật Encapsulate Field
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 67
♦ Extract Interface
Extract Interface cho phép định nghĩa một giao diện của lớp. Một đặc tính rất
ling động của C# trong việc thay thế sự đa kế thừa.
Một lớp đối tƣợng TwoDShape thể hiện các đặc tính hình vẽ trong môi trƣờng 2D đƣợc
lập trình nhƣ sau:
class TwoDShape
{
public void Draw()
{ /* Some interesting code. */ }
public Rectangle GetBoundingRect()
{ /* More interesting code. */ }
public Color GetArgb()
{ /* Even more interesting code. */ }
}
Trong trƣờng hợp này, chúng ta có thể sử dụng đặc tính Interface(giao diện) trong
ngôn ngữ C# nhằm đảm bảo một sự ràng buộc, giao kết cho lớp phải thực hiện một số
các phƣơng thức bắt buộc. Ở đây chúng ta sẽ định nghĩa một interface IRender cho lớp
TwoDShape, lớp này sẽ có các phƣơng thức Draw(), GetBoundingRect(), GetArgb() đƣợc
khai báo trong giao diện IRender
class TwoDShape : IRender
{
public void Draw()
{ /* Some interesting code. */ }
public Rectangle GetBoundingRect()
{ /* More interesting code. */ }
public Color GetArgb()
{ /* Even more interesting code. */ }
}
interface IRender
{
void Draw();
Color GetArgb();
Rectangle GetBoundingRect();
}
Ghi chú: Interface giống nhƣ một lớp chỉ chứa các phƣơng thức trừu tƣợng, và đƣợc sử
dụng thay thế cho các lớp trừu tƣợng để tạo ra các sự ràng buộc giữa những lớp và các
thành phần client của nó.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 68
Hình 4.19: Màn hình minh họa kỹ thuật Extract Interface của Refactor trong VS.NET
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 69
Hình 4.20: Màn hình minh họa kỹ thuật Extract Interface của CodeIT.Once
Hình 4.21: Màn hình kết quả kỹ thuật Extract Interface
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 70
♦ Extract Method
Extract Method cho phép định nghĩa một phƣơng thức mới dựa trên việc trích
xuất một tập đoạn mã giúp cho nội dung mã nguồn rõ ràng và logic hơn.
Xét đoạn chƣơng trình có nội dung nhƣ sau:
namespace RefactoringExamples
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("*** Please enter your credentials ***");
// Get user name and password.
string userName;
string passWord;
Console.Write("Enter User Name: ");
userName = Console.ReadLine();
Console.Write("Enter Password: ");
passWord = Console.ReadLine();
}
}
}
Dấu hiệu nhận biết mã xấu ở đây là nội dung phƣơng thức Main dài dòng không
cần thiết, đoạn lệnh mã nguồn thực thi việc đọc username và password nên đƣợc tách
thành một phƣơng thức riêng. Khi đó chƣơng trình sẽ trở nên rõ ràng và có cấu trúc logic
hơn.
Áp dụng kỹ thuật Extract Method để tái cấu trúc mã nguồn cho kết quả nhƣ sau:
namespace RefactoringExamples
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("*** Please enter your credentials ***");
// Get user name and password.
string userName;
string passWord;
GetCredentials(out userName, out passWord);
}
private static void GetCredentials(out string userName, out string
passWord)
{
Console.Write("Enter User Name: ");
userName = Console.ReadLine();
Console.Write("Enter Password: ");
passWord = Console.ReadLine();
}
}
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 71
Hình 4.22: Màn hình minh họa kỹ thuật Extract Method của Refactor trong VS.NET
Hình 4.23: Màn hình kết quả kỹ thuật Extract Method
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 72
♦ Inline Variable
Inline Variable thực hiện việc thay thế một biến tạm bởi nội dung của biểu thức
đƣợc gán cho biến đó trong thân chƣơng trình. Khi đó biến tạm đó đƣợc xóa đi.
Xét đoạn chƣơng trình đƣợc cho dƣới đây:
class Program
{
private static int _quantity = 5;
private static double _itemPrice = 460;
static void Main(string[] args)
{
double basePrice = _quantity * _itemPrice;
if (basePrice > 1000)
return basePrice * 0.95;
else
return basePrice * 0.98;
}
}
Sử dụng Inline Variable để thay những nơi biến basePrice hiện diện trong thân
chƣơng trình bởi biều thức đƣợc gán cho nó _quantity * _itemPrice. Lúc này ta có thể
không xóa bỏ biến basePrice.
class Program
{
private static int _quantity = 5;
private static double _itemPrice = 460;
static void Main(string[] args)
{
//double basePrice = _quantity * _itemPrice ;
if ((_quantity * _itemPrice) > 1000)
return (_quantity * _itemPrice) * 0.95;
else
return (_quantity * _itemPrice) * 0.98;
}
}
}
Ghi chú: Inline Variable là đối nghịch của Introduce Variable. Trong kỹ thuật lập trình,
chúng ta thƣờng gặp các luật “bù - trừ”. Với trƣờng hợp này, việc xóa bỏ biến để thay
bằng biểu thức nhằm cho chƣơng trình rõ ràng hơn và ít tốn bộ nhớ, tuy nhiên khi thực
hiện chƣơng trình phải tính toán lại. Minh họa này cho ta thấy đƣợc tác động và ảnh
hƣởng lẫn nhau giữa refactoring và hiệu năng xử lý.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 73
Hình 4.24: Màn hình minh họa kỹ thuật Inline Variable của CodeIT.Once for .NET
Hình 4.25: Màn hình kết quả kỹ thuật Inline Variable
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 74
♦ Promote Local Variable to Parameter
Promote Local Variable to Parameter thực hiện việc chuyển đổi biến cục bộ thành
tham số truyền vào của phƣơng thức.
Xét một chƣơng trình đƣợc cho có cấu trúc nhƣ sau:
class Program
{
public static void ParseTextFile()
{
string fileToParse = @"C:\myFile.txt";
StreamReader sr = File.OpenText(fileToParse);
// Start parsing using StreamReader...
}
static void Main(string[] args)
{
ParseTextFile();
}
}
Trong trƣờng hợp này, chúng ta có thể tái cấu trúc để chƣơng trình trên trở nên
đơn giản và rõ ràng hơn bằng cách xóa bỏ biến cục bộ không cần thiết dùng để lƣu giá trị
tên file filetoParse.
Sử dụng kỹ thuật Promote Local Variable to Parameter để thay thế một biến cục
bộ thành tham số của một phƣơng thức
class Program
{
public static void ParseTextFile(string fileToParse)
{
StreamReader sr = File.OpenText(fileToParse);
// Start parsing using StreamReader...
}
static void Main(string[] args)
{
ParseTextFile(@"C:\myFile.txt");
}
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 75
Hình 4.26: Màn hình minh họa kỹ thuật Promote Local Variable to Parameter của VS.NET
Hình 4.27: Màn hình minh họa kỹ thuật Promote Local Variable to Parameter của
CodeIT.Once
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 76
Hình 4.28: Màn hình minh họa kỹ thuật Promote Local Variable to Parameter của
JetBrains ReSharper
Hình 4.29: Màn hình kết quả kỹ thuật Promote Local Variable to Parameter
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 77
♦ Rename Variables
Rename Variables thực hiện việc thay đổi tên của biến trong thân phƣơng thức
hoặc chƣơng trình
Cho một đoạn chƣơng trình có cấu trúc nhƣ sau:
class Program
{
public static void ParseTextFile()
{
// Open file on local disk.
string fileToParse = @"C:\myFile.txt";
StreamReader sr = File.OpenText(fileToParse);
// Start parsing using StreamReader...
}
static void Main(string[] args)
{
ParseTextFile();
}
}
Một trong những nguyên tắc trong lập trình để chƣơng trình trở nên sáng sủa và
dễ hiểu là cách đặt tên biến sao cho dễ nhớ và đặc tả đƣợc mục đích sử dụng biến. Trong
trƣờng hợp này, chúng ta nên đổi tên biến sr thành strBuffer.
Sử dụng kỹ thuật Rename Variables cho ta kết quả nhƣ sau:
class Program
{
public static void ParseTextFile()
{
// Open file on local disk.
string fileToParse = @"C:\myFile.txt";
StreamReader strBuffer = File.OpenText(fileToParse);
// Start parsing using StreamReader...
}
static void Main(string[] args)
{
ParseTextFile();
}
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 78
Hình 4.30: Màn hình minh họa kỹ thuật Rename Variables của Refactor trong VS.NET
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 79
Hình 4.31: Màn hình minh họa kỹ thuật Rename Variables của Visual Assit X for NET
Hình 4.32: Màn hình kết quả kỹ thuật Rename Variables
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 80
IV.1.4 Nhận xét và đánh giá
Qua quá trình thử nghiệm và đánh giá việc dò tìm và cải tiến mã xấu trong mã
nguồn C# , ta có đƣợc bảng tóm lƣợc một số chức năng refactor trong các giải pháp/công
cụ đƣợc tích hợp vào Visual Studio .NET nhƣ sau
STT Kỹ thuật Refactoring
R
e
fa
c
to
r
in
V
S
2
0
0
5
V
is
u
a
l
A
s
s
it
X
C
#
R
e
fa
c
to
ry
.N
E
T
R
e
fa
c
to
r
C
o
d
e
IT
.O
n
c
e
R
e
S
h
a
rp
e
r
R
e
fa
c
to
r!
™
P
ro
1 Add Member X
2 Add to Interface X
3 Change Signature X X X
4 Combine Conditionals X
5 Convert Abstract Class to Interface X
6 Convert Anonymous to Named Type X
7 Convert EXtension Method to Plain Static X
8 Convert Interface to Abstract Class X
9 Convert Method to Property X X X
10 Convert Property to Method X X X
11 Convert Static to EXtension Method X
12 Decompose/Simplify Conditional X X X X
13 Decompose Parameter X
14 Encapsulate Field X X X X X X
15 Extract Class X X
16 Extract Interface X X X X X X
17 Extract Method X X X X X X X
18 Extract Object X
19 Extract Property X X
20 Extract Superclass X X X
21 Extract Variable X
22 Generate Method Stub X
23 Inline Method X
24 Inline Variable X X
25 Insert Cont or String X
26 Introduce Constant X X
27 Introduce Variable X X
28 Move Class X
29 Promote Local Variable to Parameter X X X X X
30 Pull Down Members X
31 Pull Up Members X X
32 Simplify Expression X
33 Remove Redundant Assignment X
34 Remove Redundant Conditional X
35 Rename Variable/Method/Parameter/Type… X X X X X X
36 Reorder Parameters/Variables X X X X
37 Replace Constructor with Factory Method X
38 Replace Magic Number X
39 Replace Temp with Query X
40 Reverse Conditional X
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 81
Dựa vào bảng dữ liệu trên, ta thấy rằng hầu hết các kỹ thuật refactoring cơ bản đã
đƣợc các hãng thứ ba phát triển và tích hợp trong các công cụ hỗ trợ lập trình và phát
triển phần mềm. Việc triển khai đƣợc áp dụng trên nhiều công cụ khác nhau trên cùng
một kỹ thuật xác định nhằm phân tích và đánh giá kết quả. Về tổng quan các chức năng
đều hoạt động chính xác trên cơ sở lý thuyết kỹ thuật refactoring và có cùng chung kết
quả, tuy nhiên vẫn có sự khác nhau về tính hiệu quả của từng công cụ tiện ích:
- Số lƣợng các kỹ thuật refactoring mà công cụ hỗ trợ: CodeIT.Once, JetBrains
ReSharper, Refactor!™ Pro hỗ trợ nhiều kỹ thuật hơn các công cụ còn lại
- Hỗ trợ tính năng tùy biến trong quá trình thực hiện: Cùng thực hiện chức
năng Promote Local Variable to Parameter nhƣng CodeIT.Once cho phép tùy biến
đổi tên tham số khi thực hiện còn Refactor in VS.NET thì không (lấy tên biến làm
tên tham số)
- Mã nguồn ngôn ngữ có khả năng hỗ trợ: Refactor in VS.NET và Refactor!™
Pro hỗ trợ tất cả các ngôn ngữ thuộc họ .NET trong khi các công cụ còn lại chủ
yếu chỉ là C# và VB.NET
- Khả năng nhận biết mã xấu và tính tiện dụng: Khi đánh dấu chọn và áp dung
refactor trên một biến trong thân chƣơng trình. Refactor in VS.NET hiển thị tất cả
các chức năng hỗ trợ bao gồm cả Extract Interface (trên thực tế kỹ thuật này
không hỗ trợ trong trƣờng hợp này và khi chọn thì hệ thống báo không hợp lệ),
trong khi các công cụ khác CodeIT.Once, JetBrains ReSharper và Refactor!™ Pro
có thể tự động nhận biết và chỉ kích hoạt cho phép chọn các chức năng hợp lệ
(chức năng Extract Interface đã bị ẩn đi).
Nhƣ vậy qua kết quả nghiên cứu và ứng dụng của đề tài này, chúng ta cũng đƣa ra
một đề xuất dành cho các lập trình viên và nhà phát triển trong việc xác định và chọn lựa
một công cụ refactoring có chất lƣợng tốt và tiện dụng trong quá trình phát triển phần
mềm: CodeIT.Once, JetBrains ReSharper hoặc Refactor!™ Pro.
IV.2 ỨNG DỤNG KỸ THUẬT TÁI CẤU TRÚC MÃ NGUỒN ĐỂ DÒ TÌM VÀ
CẢI TIẾN CÁC ĐOẠN MÃ XẤU TRONG CHƢƠNG TRÌNH C#
Trên cơ sở lý thuyết của kỹ thuật tái cấu trúc mã nguồn và dấu hiệu mã xấu đã
đƣợc trình bày, nội dung phần này chúng ta sẽ áp dụng một trong những công cụ hỗ trợ
rafactor đƣợc đề xuất (CodeIT.Once) để tiến hành triển khai việc dò tìm và cải tiến các
đoạn mã xấu trên một chƣơng trình C# thực tế.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 82
IV.2.1 Thực hiện kỹ thuật tái cấu trúc mã nguồn trên chƣơng trình thực tế
♦ Yêu cầu bài tóan: Lập trình một chƣơng trình truy xuất và cập nhật dự liệu thông tin
thời tiết của các đài khí tƣợng. Thông tin dữ liệu thời thiết bao gồm: vị trí khu vực, nhiệt
độ và độ ẩm không khí tại khu vực đó. Các đài khác nhau có thể sử dụng các đơn vị đo
khác nhau(ví dụ với nhiệt độ thì Hà Nội sử dụng độ C còn NewWork dùng độ F)
♦ Cấu trúc và mã nguồn chƣơng trình ban đầu
Chƣơng trình đƣợc thiết kế và cấu trúc mã nguồn ban đầu nhƣ sau
WeatherData
_temp: int
_humidity: int
_location: int
_stations: event
WeatherStations()
Get_Temp()
Set_Temp ()
Get_Humidity()
Set_Humidity
Get_Location()
HanoiWeat erStation
_weather:WeatherData
showWe t er()
NewYorkWeatherStation
_weather: WeatherData
showWeather()
1 1 1 1
Hình 4.33: Sơ đồ lớp của chƣơng trình khi chƣa refactoring
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
using System;
using System.Collections.Generic;
using System.Text;
namespace RefactoringExample
{
public delegate void WeatherUpdated();
class WeatherData
{
public int _temp;
public int _humidity;
public string _location;
protected event WeatherUpdated _stations;
public WeatherUpdated WeatherStations
{
get { return _stations; }
set { _stations = value; }
}
public int Get_Temp()
{
return _temp;
}
public void Set_Temp (int temperature)
{
_temp = temperature;
foreach (WeatherUpdated s in _stations.GetInvocationList()) s();
}
public int Get_Humidity()
{
return _humidity;
}
public void Set_Humidity(int weather_humidity)
{
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 83
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
_humidity = weather_humidity;
foreach (WeatherUpdated s in _stations.GetInvocationList()) s();
}
public string Get_Location()
{
return _location;
}
public WeatherData(string location, int temp,int humility)
{
_location = location;
_temp = temp;
_humidity = humility;
}
}
class HanoiWeatherStation
{
protected WeatherData _weather;
public HanoiWeatherStation(WeatherData weather)
{
_weather = weather;
_weather.WeatherStations += new WeatherUpdated(showWeather);
}
protected void showWeather()
{
System.Console.WriteLine("Ha Noi Weather Station:");
System.Console.WriteLine("The weather at " + _weather.Get_Location());
System.Console.Write("Temperature: " + (_weather.Get_Temp() - 273) + "C, ");
System.Console.WriteLine("Humidity: " + _weather.Get_Humidity() + "%\n");
}
}
class NewYorkWeatherStation
{
protected WeatherData _weather;
public NewYorkWeatherStation(WeatherData weather)
{
_weather = weather;
_weather.WeatherStations += new WeatherUpdated(showWeather);
}
protected void showWeather()
{
System.Console.WriteLine("New York Weather Station:");
System.Console.WriteLine("The weather at " + _weather. Get_Location());
System.Console.Write("Temperature:" + (((_weather. Get_Temp() - 273)
* 9 / 5) + 32) + "F, ");
System.Console.WriteLine("Humidity: " + _weather. Get_Humidity() + "%");
int outdoor_temperature = _weather. Get_Temp() - 273;
int outdoor_humidity = _weather. Get_Humidity();
if (outdoor_temperature 50)
System.Console.WriteLine("It may start to snow!");
System.Console.WriteLine("\n");
}
}
public class MainEntry
{
public static void Main()
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 84
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
{
WeatherData weather = new WeatherData("Sa Pa", 283, 40);
HanoiWeatherStation hanoi = new HanoiWeatherStation(weather);
NewYorkWeatherStation newYork = new NewYorkWeatherStation(weather);
System.Console.WriteLine("WEATHER FORCAST INFORMATION \n");
weather.Set_Temp(289);
weather.Set_Humidity(60);
weather.Set_Temp(273);
System.Console.Read();
}
}
}
Và khi chạy chƣơnng trình cho ra kết quả dƣới đây:
Hình 4.34: Màn hình kết quả chạy chƣơng trình khi chƣa refactoring
♦ Tiến hành tái cấu trúc mã nguồn
Đầu tiên xem sơ đồ lớp, ta thấy 2 lớp HanoiWeatherStation và NewYorkWeatherStation
có chung thuộc tính (_weather) và phƣơng thức (showWeather). Trong trƣờng hợp này
chúng ta nên sử dụng kỹ thuật Extract Hierarchy đề tái cấu trúc sơ đồ lớp này
WeatherData
......
.......
HanoiWeatherStation
showWeather()
NewYorkWeatherStation
showWeather()
1
WeatherStation
_weather: WeatherData
showWeather()
1
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 85
namespace RefactoringExample
{
……
class WeatherStation
{
protected WeatherData _weather;
protected void showWeather() { }
}
class HanoiWeatherStation : WeatherStation
{
public HanoiWeatherStation(WeatherData weather)
{
…………
}
public void showWeather()
{
………………
}
}
class NewYorkWeatherStation : WeatherStation
{
public NewYorkWeatherStation(WeatherData weather)
{
………………
}
public void showWeather()
{
…………
}
}
………
}
Bƣớc tiếp theo ta thấy rằng nên đổi tên lớp WeatherData thành WeatherSensor
cho hợp lý và chính xác hơn. Sử dụng kỹ thuật Rename Class trong tiện ích
CodeIT.Once để thực hiện phép thay đổi này.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 86
namespace RefactoringExample
{
……
class WeatherSensor
{
………..
}
class HanoiWeatherStation : WeatherStation
{
public HanoiWeatherStation(WeatherSersor weather)
{
…………
}
public void showWeather()
{
………………
}
}
class NewYorkWeatherStation : WeatherStation
{
public NewYorkWeatherStation(WeatherSensor weather)
{
………………
}
public void showWeather()
{
…………
}
}
public class MainEntry
{
public static void Main()
{
WeatherSensor weather = new WeatherSensor("Sa Pa", 283, 40);
………..
}
}
}
Trong quá trình xem lại sự thay đổi của mã nguồn chƣơng trình sau khi đổi tên
lớp WeatherData, ta phát hiện ra rằng việc sử dung tên trƣờng dữ liệu _temp để lƣu dữ
liệu về nhiệt độ là không chính xác và dễ nhầm lẫn -> dùng kỹ thuật Rename Field để
đổi tên trƣờng dữ liệu _temp thành _temparature
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 87
class WeatherSensor
{
public int _temperature;
public int _humidity;
………
}
Nhƣ vậy trong nhóm kỹ thuật Rename, ta đã tiến hành đổi tên lớp và trƣờng dữ
liệu. Ta thấy rằng nội dung của phƣơng thức showWeather là hiển thị thông tin dữ liệu
thời tiết của một khu vực nên đổi tên phƣơng thức này ShowWeatherInfo
namespace RefactoringExample
{
………
class WeatherStation
{
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 88
…….
protected void ShowWeatherInfo() { }
}
class HanoiWeatherStation : WeatherStation
{
public HanoiWeatherStation(WeatherSensor weather)
{
………
_weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo);
}
protected void ShowWeatherInfo()
{
……….
}
}
class NewYorkWeatherStation : WeatherStation
{
public NewYorkWeatherStation(WeatherSensor weather)
{
……….
_weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo);
}
protected void ShowWeatherInfo()
{
……….
}
}
}
Các trƣờng dữ liệu _temperature, _humidity, _location trong lớp WeartherSensor
đƣợc khai báo dƣới dạng public -> tiến hành đóng gói các trƣờng dữ liệu này thông qua
kỹ thuật Encapsulate Field. Đồng thời xóa bỏ các phƣơng thức getting và setting trên
các trƣờng dữ liệu này.
namespace RefactoringExample
{
…….
class WeatherSensor
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 89
{
private int _temperature;
public int KelvinDegrees
{
get { return _temperature; }
set
{ _temperature = value;
foreach (WeatherUpdated s in _stations.GetInvocationList()) s();
}
}
private int _humidity;
public int Humidity
{
get { return _humidity; }
set
{
_humidity = value;
foreach (WeatherUpdated s in _stations.GetInvocationList()) s();
}
}
private string _location;
public string Location
{
get { return _location; }
}
………..
}
……..
class HanoiWeatherStation : WeatherStation
{
………
protected void ShowWeatherInfo()
{
………
System.Console.Write("Temperature: " + (_weather.KelvinDegrees - 273) +
"C, ");
System.Console.WriteLine("Humidity: " + _weather.Humidity + "%\n");
}
}
class NewYorkWeatherStation : WeatherStation
{
………..
protected void ShowWeatherInfo()
{
…………
System.Console.Write("Temperature:" + (((_weather.KelvinDegrees - 273)
* 9 / 5) + 32) + "F, ");
System.Console.WriteLine("Humidity: " + _weather.Humidity + "%");
int outdoor_temperature = _weather.KelvinDegrees - 273;
int outdoor_humidity = _weather.Humidity;
………..
}
}
public class MainEntry
{
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 90
public static void Main()
{
………
weather.KelvinDegrees = 289;
weather.Humidity = 60;
weather.KelvinDegrees = 273;
System.Console.Read();
}
}
}
Ta thấy rằng đọan mã nguồn
foreach (WeatherUpdated s in _stations.GetInvocationList()) s();
đƣợc lặp lại lần trong nội dung lớp WeatherSensor -> áp dụng kỹ thuật Extract Method
để trích xuất nó ra làm một phƣơng thức riêng.
public int KelvinDegrees
{
……….
set { _temperature = value;
NotifyWeatherStations();
}
}
public int Humidity
{
…………
set {
_humidity = value;
NotifyWeatherStations();
}
}
private void NotifyWeatherStations()
{
foreach (WeatherUpdated s in _stations.GetInvocationList()) s();
}
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 91
Trong phƣơng thức ShowWeatherInfo của lớp NewYorkWeatherStation có sử
dụng 2 biến tạm outdoor_temperature, outdoor_humidity. Cách sử dụng này là không cần
thiết -> Sữ dụng Remove Local Variable để xóa bỏ các biến này.
…….
if ((_weather.KelvinDegrees - 273) 50)
System.Console.WriteLine("It may start to snow!");
…….
Lúc này ta thấy cấu trúc chƣơng trình đã chặt chẽ và dễ hiểu hơn. Và đã đến lúc
chúng ta tạm hài lòng với kết quả có đƣợc sau quá trình ứng dụng kỹ thuật tái cấu trúc
mã nguồn và các công cụ hỗ trợ để cải tiến các đoạn mã xấu trong chƣơng trình ban đầu.
♦ Cấu trúc và mã nguồn chƣơng trình sau khi tái cấu trúc
WeatherSensor
_temperature: int
_humidity: int
_location: string
_stations event
KelvinDegrees()
Humidity()
Location()
WeatherStations()
NotifyWeatherStations()
HanoiWeatherStation
ShowWeatherInfo()
NewYorkWeatherStation
ShowWeatherInfo()
1
WeatherStation
_weather: WeatherSensor
ShowWeatherInfo()
1
Hình 4.35: Màn hình kết quả chạy chƣơng trình sau khi refactoring
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
using System;
using System.Collections.Generic;
using System.Text;
namespace RefactoringExample
{
public delegate void WeatherUpdated();
class WeatherSensor
{
private int _temperature;
public int KelvinDegrees
{
get { return _temperature; }
set {
_temperature = value;
NotifyWeatherStations();
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 92
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
}
}
private int _humidity;
public int Humidity
{
get { return _humidity;}
set {
_humidity = value;
NotifyWeatherStations();
}
}
private string _location;
public string Location
{
get { return _location;}
}
protected event WeatherUpdated _stations;
public WeatherUpdated WeatherStations
{
get { return _stations; }
set { _stations = value; }
}
private void NotifyWeatherStations()
{
foreach (WeatherUpdated s in _stations.GetInvocationList()) s();
}
public WeatherSensor(string location, int temp, int humility)
{
_location = location;
_temperature = temp;
_humidity = humility;
}
}
class WeatherStation
{
protected WeatherSensor _weather;
protected void ShowWeatherInfo(){}
}
class HanoiWeatherStation : WeatherStation
{
public HanoiWeatherStation(WeatherSensor weather)
{
_weather = weather;
_weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo);
}
public void ShowWeatherInfo()
{
System.Console.WriteLine("Hanoi Weather Station:");
System.Console.WriteLine("The weather at " + _weather.Location);
System.Console.Write("Temperature: " + (_weather.KelvinDegrees -
273) + "'C, ");
System.Console.WriteLine("Humidity: " + _weather.Humidity +"%\n");
}
}
class NewYorkWeatherStation : WeatherStation
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 93
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
{
public NewYorkWeatherStation(WeatherSensor weather)
{
_weather = weather;
_weather.WeatherStations += new WeatherUpdated(ShowWeatherInfo);
}
public void ShowWeatherInfo()
{
System.Console.WriteLine("New York Weather Station:");
System.Console.WriteLine("The weather at " + _weather.Location);
System.Console.Write("Temperature:" + (((_weather.KelvinDegrees -
273) * 9 / 5) + 32) + "'F, ");
System.Console.WriteLine("Humidity: " + _weather.Humidity + "%");
if ((_weather.KelvinDegrees - 273) 50)
System.Console.WriteLine("It may start to snow!");
System.Console.WriteLine("\n");
}
}
public class MainEntry
{
public static void Main()
{
WeatherSensor weather = new WeatherSensor("Sa Pa", 283, 40);
HanoiWeatherStation hanoi = new HanoiWeatherStation(weather);
NewYorkWeatherStation newYork = new NewYorkWeatherStation(weather);
weather.KelvinDegrees = 289;
weather.Humidity = 60;
weather.KelvinDegrees = 273;
System.Console.Read();
}
}
}
Và đây là kết quả thực thi của chƣơng trình sau khi đƣợc tái cấu trúc:
Hình 4.36: Màn hình kết quả chạy chƣơng trình sau khi refactoring
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 94
Trong quá trình tái cấu trúc mã nguồn, mỗi khi áp dung xong một kỹ thuật chúng
ta đều phải trải qua giai đọan kiểm thử và thực thi chƣơng trình với các bộ kiểm thử để
đảm bảo rằng kết quả là đồng nhất.
IV.2.2 Phân tích và đánh giá kết quả thực hiện
Với chƣơng trình trên chúng ta đã sử dụng một số kỹ thuật tái cấu trúc mã nguồn
để dò tìm và cải tiến các đoạn mã xấu:
- Extract Hierarchy
- Rename Class
- Rename Field
- Rename Method
- Encapsulate Field
- Extract Method
- Remove Local Variable
Đối chiếu kết quả trƣớc và sau khi thực hiện, ta có đánh giá nhận xét nhƣ sau:
♦ Định tính:
- Sau khi thực hiện tái cấu trúc, thiết kế lớp và cấu trúc chƣơng trình rõ ràng và chặt
chẽ hơn
- Các đoạn mã trùng lặp và biến tạm không cần thiết đã đƣợc loại bỏ
- Các tên lớp, trƣờng dữ liệu và phƣơng thức trở nên hợp lý và dễ hiểu
- Dữ liệu đƣợc đóng gói và an tòan hơn
♦ Định lƣợng:
Ta có bảng số liệu thống kê về các thành phần khác nhau trƣớc và sau khi thực
hiện tái cấu trúc mã nguồn nhƣ sau:
Thành phần so sánh
Áp dụng kỹ thuật tái cấu trúc mã nguồn
Trước Sau
Số dòng lệnh 102 106
Số lớp đối tượng 4 5
Số trường dữ liệu/thuộc tính lớp 6 5
Số phương thức 12 11
Số biến cục bộ sử dung 2 0
Trong 5 chỉ tiêu so sánh, ta thấy rằng có 3 chỉ tiêu đƣợc cải thiện (giảm) đó là: số
lƣợng thuộc tính lớp, phƣơng thức và biến cục bộ. Về số dòng mã, có sự chênh lệch
không đáng kể (4) nên có thể xem nhƣ là tƣơng đƣơng. Thành phần còn lại cần xét đến là
sự thay đổi về số lƣợng lớp đối tƣợng.
Ta thấy rằng với bài tóan nêu ra nhƣ trên, việc tạo mới một lớp dẫn xuất
WeatherStation là cần thiết giúp cho cấu trúc các lớp đối tƣợng đƣợc rõ ràng và có sự
đồng nhất(thuộc tính và hành vi xử lý). Việc tạo mới WeatherStation cũng làm cho
chƣơng trình có dễ dàng thay đổikhi có yêu cầu bổ sung thên các đài khí tƣợng (tạo thêm
lớp mới kế thừa từ lớp dẫn xuất WeatherStation.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 95
IV.3 NHẬN XÉT VÀ KẾT LUẬN
Trên cơ sở lý thuyết đã đƣợc nghiên cứu và trình bày, chúng ta đã đề xuất một
giải pháp tổng thể trong việc áp dụng kỹ thuật tái cấu trúc mã nguồn để triển khai xây
dựng công cụ hỗ trợ việc dò tìm và cải tiến các đoạn mã xấu trong mã nguồn C#. Đồng
thời tiến hành thử nghiệm và ứng dụng các công cụ hỗ trợ refactor hiện có để dò tìm và
tái cấu trúc các đoạn mã xấu trên một chƣơng trình C# thực tế.
Kết quả triển khai trên chƣơng trình thực tế đã làm sáng tỏ và chứng minh những
hiệu quả mà kỹ thuật tái cấu trúc mã nguồn mang lại trong việc cải thiện chất lƣợng
chƣơng trình. Đó là:
- Cấu trúc chƣơng trình trở nên rõ ràng và chặt chẽ hơn.
- Tính khả biến của chƣơng trình đƣợc nâng cao (dễ thay đổi và cập nhật theo yêu
cầu mới)
- Hạn chế và tối thiểu hóa sự trùng lặp mã lệnh và dƣ thừa dữ liệu
- Trong quá trình tái cấu trúc mã nguồn, cần thực hiện các bƣớc kiểm thử -> tăng
khả năng kiểm sóat và phát hiện lỗi, đảm bảo chƣơng trình họat động chính xác
khi triển khai sử dụng.
- V.v
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 96
CHƢƠNG V: KẾT LUẬN
V.1 ĐÁNH GIÁ KẾT QUẢ CỦA ĐỀ TÀI
Qua quá trình nghiên cứu và triển khai ứng dụng kỹ thuật tái cấu trúc mã nguồn
trong việc dò tìm và cải tiến các đoạn mã xấu trong chƣơng trình C#. Đề tài đã đạt đƣợc
một số kết quả:
- Nắm rõ cơ sở lý thuyết của kỹ thuật tái cấu trúc mã nguồn (refactoring)
- Dấu hiệu nhận biết mã xấu trong chƣơng trình và các giải pháp cải tiến dựa trên
kỹ thuật tái cấu trúc mã nguồn.
- Tiếp cận và đề xuất giải pháp triển khai công cụ hỗ trợ chức năng refactor trong
quá trình phát triển phần mềm.
- Tìm hiểu và ứng dụng các công cụ hỗ trợ chức năng refactor hiện có đƣợc tích
hợp trong môi trƣờng phát triển VS.NET để dò tìm và cải tiến các đọan mã xấu
trong chƣơng trình C#.
- Đánh giá hiệu quả của các công cụ hỗ trợ chức năng refactor hiện có -> đƣa ra
khuyến cáo dành cho các nhà lập trình và phát triển phần mềm trong việc lựa chọn
và sử dụng các công cụ hỗ trợ refactor phù hợp.
- Bài báo công bố các kết quả nghiên cứu và ứng dụng của đề tài
V.2 PHẠM VI ỨNG DỤNG
Với những kết quả đã đạt đƣợc, đề tài có ý nghĩa thực tiễn trong lãnh vực nghiên
cứu và ứng dụng các công nghệ mới của ngành công nghệ phần mềm tiên tiến. Đặc biệt
là tiến trình chuẩn hóa các qui trình và kiểm thử phần mềm trong tƣơng lai.
Đề tài có khả năng ứng dụng trong phạm vi và lãnh vực:
- Triển khai ứng dụng kỹ thuật refactoring trong việc dò tìm và cải tiến các đọan mã
xấu trong chƣơng trình C# cũng nhƣ các ngôn ngữ khác thuộc họ .NET
- Tài liệu tham khảo dành cho các sinh viên chuyên nghành khoa học máy tính và
lập trình viên trong vấn đề tìm hiểu và ứng dụng kỹ thuật tái cấu trúc mã nguồn.
- Đề xuất giải pháp và khuyến cáo dành cho các nhà lập trình và phát triển phần
mềm trong việc lựa chọn và sử dụng các công cụ hỗ trợ refactor phù hợp (trên các
ngôn ngữ lập trình thuộc họ .NET)
- Cơ sở lý thuyết cho việc xây dựng và triển khai các công cụ dò tìm các đoạn mã
xấu dựa trên kỹ thuật tái cấu trúc mã nguồn cho các ngôn ngữ lập trình.
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 97
V.3 HƢỚNG PHÁT TRIỂN
V.3.1 Triển khai áp dụng trên các ngôn ngữ khác
Mở rộng triển khai áp dụng kỹ thuật tái cấu trúc mã nguồn cho các ngôn ngữ
khác: C++, VB.NET, Java, Delphi,…
Ví dụ: Triển khai kỹ thuật Promote Local Variable to Parameter trong đoạn chƣơng
trình mã nguồn VB.NET
Public Class SampleApp
Private Const SummerStart As Date = #6/1/2005#
Private Const SummerEnd As Date = #8/31/2005#
Private Shared _winterRate As Double = 5.0
Private Shared _summerRate As Double = 5.4
Private Shared Function CalculateCharge(ByVal quantity As Integer) As Double
Dim charge As Integer
Dim chargeDate As Date = Date.Now
If Date.Compare(chargeDate, SummerStart) > 0 Or _
Date.Compare(chargeDate, SummerEnd) < 0 Then
charge = quantity * _winterRate
Else
charge = quantity * _summerRate
End If
Return charge
End Function
Public Shared Sub Main()
Console.WriteLine("Charge: " + CalculateCharge(10).ToString())
End Sub
End Class
Kết quả sau khi refactor:
Public Class SampleApp
Private Const SummerStart As Date = #6/1/2005#
Private Const SummerEnd As Date = #8/31/2005#
Private Shared _winterRate As Double = 5.0
Private Shared _summerRate As Double = 5.4
Private Shared Function CalculateCharge(ByVal chargeDate As Date,
ByVal quantity As Integer) As Double
Dim charge As Integer
If Date.Compare(chargeDate, SummerStart) > 0 Or _
Date.Compare(chargeDate, SummerEnd) < 0 Then
charge = quantity * _winterRate
Else
charge = quantity * _summerRate
End If
Return charge
End Function
Public Shared Sub Main()
Console.WriteLine("Charge: " + CalculateCharge(Date.Now, 10).ToString())
End Sub
End Class
V.3.2 Thử nghiệm xây dựng một refactoring tool tích hợp vào VS.NET
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 98
TÀI LIỆU THAM KHẢO
Tiếng Việt
[1] Phạm Văn Việt, Trƣơng Lập Vĩ. Tìm hiểu ngôn ngữ C# và viết một chƣơng
trình minh họa. Đồ án tốt nghiệp – Khoa CNTT – ĐH KHTN TP.HCM, 2002.
Tiếng nƣớc ngoài
[2] Jesse Liberty. Programming C#. O‟Reilly, 2001
[3] Joseph W. Yoder. Refactoring Principles. University of Illinois, 2004
[4] Martin Fowler. Refactoring: Improving the design of existing code. Addison
Wesley,1999.
Trang web
[5] Bad Smells in Code
[6] Building a Refactoring Plug-in for VS.NET
[7] C# Refactory - C# Refactoring tool.
[8] CodeIT.Once for .NET
[9] DevExpress Refactor!™ Pro
[10] JetBrains ReSharper- Code Refactoring
[11] Nhập môn Refactoring
v.com.vn/UsolV.dotNetCenter.OfficialSite/TechnicalDocuments
/An_Introduction_of_Refactoring/Default.htm
[12] .NET Refactor for C# & VB.NET
[13] Refactoring C# Code Using Visual Studio 2005
[14] Refactoring HomePage
[15] The Future of Software Development
[16] Visual Assit X for Visual Studio
Luận văn tốt nghiệp cao học – Khóa 2005 - 2008
Học viên thực hiện: Nhiêu Lập Hòa 99
Ý KIẾN NHẬN XÉT VÀ ĐÁNH GIÁ
GV hƣớng dẫn:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Chủ tịch hội đồng xét duyệt:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Các file đính kèm theo tài liệu này:
- Ứng dụng kỹ thuật tái cấu trúc mã nguồn để triển khai dò tìm và cải tiến các đoạn mã xấu trong chương trình c#.pdf