Tải bản đầy đủ (.pdf) (12 trang)

TÌM HIỂU CÔNG NGHỆ DESIGN BY CONTRACT VÀ XÂY DỰNG CÔNG CỤ HỖ TRỢ CHO C# - 7 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (559.42 KB, 12 trang )









Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
73

Hình 13-1: Một vòng lặp tính toán

Một tính toán bằng vòng lặp gồm những thành phần sau:
Mục tiêu post, là một hậu điều kiện, được định nghĩa như là một thuộc tính
mà bất cứ trạng thái cuối nào của sự tính toán đều phải thỏa mản. Ví dụ như:
“Result là giá trị lớn nhất của mảng”. Mục tiêu này được biểu diễn trong hình minh
họa là một tập hợp những trạng thái POST
thỏa mãn post.
Điều kiện bất biến inv, là một sự tổng quát hóa của mục tiêu (post là một
trường hợp đặc biệt của inv). Ví dụ: “Result là giá trị lớn nhất của phần mảng không
rỗng bắt đầu từ biên thấp nhất”. Điều kiện bất biến được biểu diễn trong hình minh
họa là một tập hợp những trạ
ng thái INV thỏa mãn inv.
Điểm khởi động init thuộc INV, điểm này thỏa mãn điều kiện bất biến. Ví
dụ: khi giá trị của i là biên dưới của mảng và giá trị của Result là phần tử mảng
tương ứng tại vị trí đó, thỏa mãn điều kiện bất biến bởi vì phần tử lớn nhất của
mảng một phần tử chính là phần tử đó.









Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
74
Sự biến đổi body (bắt đầu từ một điểm trong INV chứ không phải trong
POST) phát sinh ra một điểm tiến đến gần POST hơn nhưng vẫn thuộc INV. Trong
ví dụ trên, sự biến đổi này mở rộng mảng lên từng phần tử và thay thế Result bằng
phần tử thêm đó nếu nó lớn hơn Result. Thân vòng lặp trong hàm maxarray ví dụ ở
trên là cài đặt của sự biến đổi này.
Biên trên dựa vào số body cần thiết để đưa điểm trong INV đến POST. Đây
là biến.
Tính toán xấp xỉ là phương pháp chính của toán giải tích, nhưng ý tưởng này
thì được áp dụng rộng rãi hơn. Sự khác biệt cơ bản là trong toán học thuần túy, ta
chấp nhận có sự tồn tại của một giới hạ
n, mặc dù không thể đạt được giới hạn đó.
Ví dụ như 1/n có giới hạn là 0 nhưng không có n cụ thể nào để đạt được giới hạn
đó. Còn trong tin học, chúng ta cần có được kết quả cụ thể, cho nên chúng ta phải
nhấn mạnh rằng tất cả các sự xấp xỉ đều tiến đến kết quả cụ thể sau một số lần lặp đi
lặp lại nhất định.

13.4. Cú pháp của vòng lặp
− Gồm những thành phần sau:
− Điều kiện bất biến (invariant) của vòng lặp inv – đây là một xác nhận

Điều kiện thoát khỏi vòng lặp exit.

Điều kiện biến đổi (variant) của vòng lặp var – đây là một biểu thức

nguyên.


Tập lệnh khởi tạo init, tập lệnh này luôn tạo ra một trạng thái thỏa inv
và làm var không âm.
− Tập lệnh body, tập lệnh này, khi khởi đầu một trạng thái mà inv được
giữ và var không âm, sẽ bảo vệ điều kiện bất biến và làm điều kiện biến đổi giảm
đi (nhưng vẫn bảo đảm không âm). Vì vậy, trong trạng thái kết quả, inv được thỏa
và var có giá trị nhỏ hơn trước (nhưng luôn không âm).
Tóm lại, vòng lặp có cú pháp như
sau:








Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
75
from
init
invariant
inv
variant
var
until
exit
loop

body
end


Đây là phiên bản vòng lặp cho hàm maxarray:

from
i := t.lower; Result := t @ lower
invariant
Result là giá trị lớn nhất của t khi chỉ số
t.lower = i.
variant
t.lower – i
until
i = t.upper
loop
i := i + 1
Result := Result.max (t @ i)
end

Dưới đây là một ví dụ khác về điều kiện bất biến, đây là hàm tính ước chung
lớn nhất (greatest common divisor - gcd) của 2 số nguyên dương a, b bằng thuật
toán Euclid.
Phiên bản không có không có điều kiện bất biến và điều kiện biến đổi:









Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
76
gcd (a, b: INTEGER): INTEGER is
Uớc chung lớn nhất của a và b
require
a > 0; b > 0
local
x, y: INTEGER
do
from
x := a; y := b
until
x = y
loop
if x>y then x:=x–y else y:=y–x end
end
Result := x
ensure
Result là ước chung lớn nhất của a và b
end
Làm sao chắc chắn được rằng hàm gcd trả về đúng giá trị ước chung lớn nhất
của a và b. Có một cách để kiểm tra điều này, lưu ý rằng thuộc tính này luôn đúng
trong suốt quá trình lặp:
x > 0; y > 0
Cặp x, y có cùng ước chung lớn nhất với cặp a, b
Đây chính là điều kiện bất biến mà ta cần cho hàm này.
Làm sao chúng ta biết vòng lặp này luôn luôn kết thúc? Chúng ta cần một
điều kiện biến đổi để xác định điều này. Không thể chọn x làm điều kiện biến đổi vì

ta không chắc rằng một bước lặp tuỳ ý sẽ làm giảm x, cũng vì lý do đó, y không thể
được chọn. Nhưng ta chắc rằng hoặc x hoặc y sẽ giảm giá trị, vì vậ
y giá trị lớn nhất
của chúng (được biểu diễn bằng hàm
x.max(y)) là lựa chọn tốt nhất.
Ta có phiên bản có điều kiện bất biến và điều kiện biến đổi của vòng lặp cho
hàm gcd:








Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
77
from
x := a; y := b
invariant
x > 0; y > 0
Cặp <x, y> có cùng UCLN với cặp <a, b>
variant
x.max (y)
until
x = y
loop
if x > y then x := x – y else y := y – x end
end



Chương 14: Sử dụng những xác nhận
Xem qua tất cả các cấu trúc có liên quan đến những xác nhận, ta thấy có 4
loại ứng dụng chính liên quan đến những xác nhận:
− Trợ giúp cho việc viết phần mềm chính xác.
− Trợ giúp việc viết tài liệu.
− Hỗ trợ kiểm tra (testing), chạy từng bước (debugging) và đảm bảo
chất lượng.
− Hỗ trợ khả năng chịu lỗi của phần mềm.
Chỉ có 2 ứng dụng cuối có khả năng kiểm tra những xác nhận lúc thực thi.

14.1. Những xác nhận như một công cụ để viết phần mềm
chính xác
Ứng dụng đầu tiên này hoàn toàn mang tính phương pháp và có vai trò quan
trọng nhất. Điều này đã được làm rõ trong những phần trước: giải thích rõ ràng
những yêu cầu chính xác trên mỗi thủ tục, những thuộc tính tổng quát của lớp đối








Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
78
tượng và vòng lặp, giúp cho người lập trình có thể tạo ra những phần mềm chính
xác ngay từ lần đầu tiên (khác với những cách tiếp cận khác, cố gắng sửa lỗi cho
đến khi đạt được tính đúng đắn).
Từ khóa xuyên suốt ở đây là Design By Contract. Trong thế giới thực, một

hợp đồng tốt là một hợp đồng chỉ định rõ ràng quyền lợi và nghĩa vụ của mỗi bên
tham gia, và giới h
ạn của những quyền và nghĩa vụ này. Trong thiết kế phần mềm,
tính đúng đắn và tính vững chắc vô cùng quan trọng, vì vậy ta cần chỉ rõ những điều
khoản của hợp đồng như là một điều kiện tiên quyết trước khi hợp đồng có hiệu lực.
Những xác nhận cung cấp phương tiện nhằm chỉ rõ những điều được mong đợi và
được bảo đảm cho mỗi đối tác của sự ký kết này.

14.2. Sử dụng những xác nhận cho việc viết tài liệu: thể rút
gọn của một lớp đối tượng
Ứng dụng thứ hai này rất cần thiết cho việc sản xuất những thành phần của
phần mềm có tính tái sử dụng cao, và tổng quát hơn, trong việc tổ chức những
interface của một môđun trong một hệ thống lớn. Tiền điều kiện, hậu điều kiện và
những điều kiện bất biến của lớp cung cấp cho những khách hàng tiềm năng của
một môđun thông tin cơ bản về những dịch vụ được cung cấp bởi môđun đó. Những
thông tin này được biểu diễn bằng một hình thức ngắn gọn và chính xác. Không
một tài liệu dài dòng nào có thể thay thế được một tập những xác nhận dùng để biểu
diễn xuất hiện trong chính phần mềm.
Thể rút gọn này sử dụng xác nhận như là một thành phần quan trọng trong
việc trích những thông tin thích hợp cho những khách hàng tiềm năng từ lớp đối
tượng. Thể rút gọn này chỉ bao gồm những thông tin có ích cho tác giả của những
lớp client, vì vậy nó không cho thấy những đặc tính ẩn cũng như cài đặt của lớp
(mệnh đề do). Nhưng thể rút gọn này vẫn giữ lại những xác nhận, chúng sẽ cung
cấp những tài liệu cần thiết của hợp
đồng mà lớp này quy định với những client.
Thể rút gọn của lớp STACK4









Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
79
indexing
description: " Stacks: Cấu trúc dữ liệu với quy tắc truy
xuất LIFO, và có độ lớn cố định."
class interface STACK4 [G] creation
make
feature Khởi tạo
make (n: INTEGER) is
Cấp phát cho stack độ lớn n phần tử
require
non_negative_capacity: n >= 0
ensure
capacity_set: capacity = n
end

feature -– Truy cập
capacity: INTEGER
Số phần tử tối đa của stack
count: INTEGER
Số phần tử của stack
item: G is
Phần tử trên cùng
require
not_empty: not empty –- i.e: count > 0
end


feature -– Báo cáo tình trạ
ng
empty: BOOLEAN is
Kiểm tra stack rỗng?
ensure
empty_definition: Result = (count = 0)
end








Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
80
full: BOOLEAN is
Kiểm tra stack đầy?
ensure
full_definition: Result = (count = capacity)
end

feature –- Thay đổi thành phần
put (x: G) is
Thêm phần tử x vào stack.
require
not_full: not full
ensure

not_empty: not empty
added_to_top: item = x
one_more_item: count = old count + 1
end
remove is
Xóa phần tử trên cùng của stack.
require
not_empty: not empty –- i.e: count > 0
ensure
not_full: not full
one_fewer: count = old count – 1
end

invariant
count_non_negative: 0 <= count
count_bounded: count <= capacity
empty_if_no_elements: empty = (count = 0)
end class interface STACK4









Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
81
Thể rút gọn này không phải là những mã chương trình đúng cú pháp. Nếu ta

so sánh những xác nhận trong thể rút gọn này với những xác nhận trong lớp đối
tượng, ta thấy rằng tất cả những mệnh đề bao gồm representation đều biến mất.
Thể rút gọn này gây sự chú ý đặc biệt bởi những lý do sau:
− Tài liệu này có mức độ trừu tượng hơn so với những gì chúng mô tả,
đây là một yêu cầu chủ yếu để có một tài liệu có chất lượng. Những cài đặt thực tế
(trả lời câu hỏi như thế nào) được loại bỏ, nhưng những xác nhận (trả lời câu hỏi cái
gì – hoặc tại sao) vẫn được giữ lại. Lưu ý rằng nhữ
ng ghi chú ở đầu thủ tục (để bổ
sung cho xác nhận bằng những giải thích sơ lược về mục đích của thủ tục) và mô tả
trong mệnh đề clause cũng được giữ lại.


Với thể rút gọn này, tài liệu không còn được xem như một sản phẩm
riêng biệt mà bao gồm trong chính phần mềm. Điều này có nghĩa là chỉ có duy nhất
một sản phẩm để bảo trì. Và cũng vì vậy, tài liệu chắc chắn sẽ đúng đắn hơn, bởi vì
bạn sẽ không quên việc cập nhật tài liệu mỗi khi thay đổi phần mềm hay ngược lại.


Thể rút gọn này có thể được phát sinh từ lớp đối tượng bằng những
công cụ tự động.



Chương 15: Giới thiệu công cụ XC#
15.1. Giới thiệu
XC# là một phần mở rộng của trình biên dịch C#.
Luôn biên dịch sau trình biên dịch C#.
Có khả năng kiểm tra mã nguồn và đưa ra các cảnh báo lỗi nếu có.
Cho phép người lập trình tự định nghĩa các ràng buộc, luật của riêng mình.
Cho phép thêm hay loại bỏ các các khai báo tiền tố, hậu tố, rất hữu dụng cho

việc debug chương trình.









Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
82
15.2. XC# hoạt động như thế nào
XC# bao gồm các component thực hiện các tác vụ biên dịch, đưa ra các cảnh
báo lỗi, và một số tác vụ khác.
XCSharp.Compiler.dll đây là trình biên dịch của XC#
XCSharp.Parser.dll đây là bộ phân tích cú pháp của XC#, nó tạo ra
CodeDom ASTs từ mã nguồn
XCSharp.Interface.dll tạo sự tương tác giữa trình biên dịch và các thuộc
tính
XCSharp.Attributes.dll and XCSharp.Verifier.dll nắm giữ toàn bộ tập
các thuộc tính (như obfuscation, declarative assertions, verification, etc.)
XCSharp.VisualStudio.dll nhận dạng và biên dịch Visual Studio solutions
XCSharp.AddIn.dll quản lý việc Add_in trong Visual Studio
xcsc.exe biên dị
ch bằng dòng lệnh của XC#

Trình biên dịch thông thường như MS C# lấy dữ liệu đầu vào là tập các file
mã nguồn và đầu ra là mã thực thi. Tuy nhiên, cách này vẫn còn một hạn chế là
không thể hiệu chỉnh được các cư xử bên trong của quá trình biên dịch.

XC# cho phép can thiệp vào bên trong quá trình biên dịch bằng cách khai
báo các câu lệnh, các luật ngay trong mã nguồn. Điều này cho phép trình biên dịch
có thể đưa ra các cảnh báo và thông báo lỗi theo các ràng buộc đã được định nghĩa.

15.3. Khai báo các xác nhận
Như đã mô tả ở trên, khai báo các xác nhận cho phép can thiệp vào
bên trong quá trình biên dịch, đưa ra các cảnh báo lỗi… Các xác nhận có thể là tiền
điều kiện hay hậu điều kiện.
15.3.1. Tiền điều kiện
− Kiểm tra điều kiện ban đầu của phương thức








Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
83
− Thuộc tính Requires giúp xác định điều kiện ban đầu của phương
thức. Đối của Requires đơn giản chỉ là một đoạn text mô tả điều kiện ban đầu của
phương thức.
Ví dụ :
[Requries (“obj != null”)]
public void SetData(Object obj)
{

}
15.3.2. Hậu điều kiện

− Kiểm tra điều kiện kết thúc của phương thức
− Thuộc tính Ensures giúp xác định điều kiện kết thúc của phương
thức. Đối của Ensures cũng là một đoạn text mô tả điều kết thúc của phương thức.
Ví dụ :
[Ensures (“result != null”)]
public Object GetData()
{
Object obj;
………
rerurn obj;
}
15.3.3. Một số thuộc tính mà XC# qui ước sẵn
Tên Mô tả Sử dụng
NotNull
Yêu cầu đối
tượng nhập vào
hay trả về phải
“not null”
Void SetData([NotNull] Object
obj) {}
//obj != null
Equal
Yêu cầu đối Void SetData([Equal (5)] int









Tìm hiểu công nghệ Design By Contract và Xây dựng công cụ hỗ trợ cho C#
84
tượng nhập vào
hoặc trả về phải
“equal” với một
giá trị cho trước
value) {}
//value == 5
ExclusiveBetween
Yêu cầu đối
tượng nhập vào
hoặc trả về phải
nẳm trong một
khoảng cho
trước
Void SetData([ExclusiveBetween
(1, 5)] int value) {}
//1 <= value <= 5
GreaterThan
Yêu cầu đối
tượng nhập vào
hoặc trả về phải
lớn hơn với một
giá trị cho trước
Void SetData([GraeterThan (5)]
int value) {}
//value > 5
GreaterThanOrEqual
Yêu cầu đối

tượng nhập vào
hoặc trả về phải
lớn hơn hau
bằng với một giá
trị cho trước
Void
SetData([GraeterThanOrEqual
(5)] int value) {}
//value >= 5
Is
Yêu cầu đối
tượng nhập vào
hoặc trả về phải
“Is” một giá trị
cho trước
Void SetData([Is (typeof
(HOCSINH))] Object obj) {}
//kiểu của obj phải là HOCSINH
LessThan
Yêu cầu đối
tượng nhập vào
hoặc trả về phải
Void SetData([LessThan (5)] int
value) {}
//value < 5

×