Mẫu Strategy bao gồm các thành phần sau:
– IStrategy: Giao diện (Interface) được chia sẻ giữa các lớp con cụ thể trong họ các thuật toán. Lớp Context sử dụng giao diện để gọi đến các thuật toán đã được định nghĩa trong các lớp con;
– ConcreteStrategy: Nơi các thuật toán được cài đặt cụ thể;
– Context: Lớp dùng để tham chiếu đến kiểu ISstrategy. Trong một số
trường hợp, Context có thể cài đặt các phương thức, bởi vậy các lớp
ConcreteStrategy có thể truy cập đến các dữ liệu này.
Sự hợp tác giữa các thành phần trong mẫu Strategy:
– IStrategy và Context tương tác để thực hiện việc lựa chọn các thuật toán. Một Context có thể truyền tất cả các dữ liệu cần thiết bằng các thuật tốn đến IStrategy. Ngồi ra, Context có thể truyền chính nó như là một đối số cho các hoạt động của IStrategy. Điều đó cho phép IStrategy gọi lại Context khi cần thiết;
– MộtContext chuyển tiếp yêu cầu từ máy khách (client) đến cácIStra- tegy của nó. Máy khách thường tạo và truyền đối tượng ConcreteStra- tegy đến Context; sau đó, nó tương tác riêng với Context. Thường có
Ưu điểm của việc sử dụng mẫu Strategy là đóng gói các thuật tốn trong các lớp riêng biệt, điều này sẽ làm cho việc sử dụng lại mã được thuận tiện hơn nhiều và do đó, hành vi của lớp Context có thể thay đổi một cách linh hoạt tại thời điểm chạy chương trình.
2.5 Ngơn ngữ ràng buộc đối tượng OCL (ObjectConstraint Language) Constraint Language)
Ngôn ngữ ràng buộc đối tượng OCL (Object Constraint Language) ra đời nhằm mục tiêu khắc phục các hạn chế của UML trong việc biểu diễn một cách chính xác các khía cạnh chi tiết của bản thiết kế hệ thống [21]. OCL được phát triển lần đầu bởi tổ chức IBM vào năm 1995 và được tích hợp vào UML năm 1997.
Thời gian đầu, OCL chỉ được sử dụng như là một ngôn ngữ ràng buộc đối tượng bổ sung cho UML, tuy nhiên nó nhanh chóng được mở rộng phạm vi và trở thành một thành phần quan trọng trong bất kỳ kỹ nghệ hướng mơ hình nào. OCL được coi như một ngơn ngữ mặc định dùng biểu diễn các truy vấn trên mơ hình hoặc siêu mơ hình, thực hiện và đặc tả các yêu cầu. OCL cũng thường được sử dụng để mô tả các phép biến đổi mơ hình (như là một phần của các mơ hình nguồn và mơ hình đích trong các quy tắc biến đổi), biểu diễn sự hợp lệ của các quy tắc (như là một phần của định nghĩa đặc tả các miền mới), hoặc các mẫu sản sinh mã nguồn (mô tả các mẫu và quy tắc sản sinh mã), v.v. Để đáp ứng các mục tiêu này, OCL được phát triển và phát hành một số các phiên bản. OCL được phát triển như là một chuẩn công nghiệp bởi tổ chức Object Management Group1 (OMG) [12]. Phiên bản mới nhất của OCL là 2.4 được ra đời vào năm 2014, phiên bản này tương thích với phiên bản 2.4.1 của UML.
Mỗi biểu thức trong OCL đều xác định một kiểu nhất định (kiểu này có thể được định nghĩa trước trong OCL hoặc là một kiểu được định nghĩa trong mơ hình với các ràng buộc được mơ tả bởi OCL). Kiểu của các biểu thức trong OCL cũng phải phù hợp với các quy tắc và các phép tốn được áp dụng trên kiểu đó. Chú ý rằng OCL chỉ là một ngôn ngữ đặc tả thuần túy, bởi vậy khi các biểu thức OCL được thực thi, nó khơng gây bất cứ ảnh
hưởng nào đến trạng thái của mơ hình phần mềm mà nó đặc tả. Ngoài ra, tất cả các vấn đề liên quan đến cài đặt cũng nằm ngoại phạm vi và không thể biểu diễn bằng OCL. OCL có thể được sử dụng để mơ tả nhiều loại ràng buộc khác nhau trong mơ hình UML, sau đây là một số loại ràng buộc tập trung chủ yếu vào tác dụng của nó trên biểu đồ lớp:
– Biểu diễn các ràng buộc bất biến của lớp (class invariants);
– Khởi tạo giá trị cho thuộc tính của các biến trong biểu thức OCL; – Biểu diễn cách tính giá trị của các phần tử dẫn xuất dựa trên giá trị
của các phần tử nguồn;
– Thực hiện các câu lệnh truy vấn;
– Biểu diễn tiền/hậu điều kiện (pre/post-conditions) của các phương thức có trong mơ hình.
Các khả năng biểu diễn trên của OCL sẽ lần lượt được cụ thể hóa như sau:
OCL được dùng để biểu diễn các ràng buộc bất biến (Inva- riants): Các ràng buộc toàn vẹn trong OCL được biểu diễn dưới dạng các bất biến được định nghĩa trong một Context cụ thể, với tên của Context
là kiểu của ràng buộc. Phần thân của context, là các điều kiện logic (sau từ khóa inv) phải được kiểm tra và thỏa mãn bởi tất cả các thể hiện của Context đó.
Các bất biến là các biểu thức được sử dụng phổ biến nhất trong OCL vì nó cho phép các nhà thiết kế dễ dàng đặc tả tất cả các loại điều kiện mà hệ thống phải tn thủ. Ngồi ra, bất biến cịn có thể hạn chế giá trị của các đối tượng đơn lẻ. Biểu thức dưới đây phát biểu rằng, tất cả các quotesphải có giá trị dương. Chú ý rằng biến self đại diện cho một thể hiện tùy ý của lớp Quote và dấu chấm được sử dụng để truy cập vào các tính chất (thuộc tính hoặc phương thức) của biến self trong lớp Quote. Tất cả các thể hiện
của lớp Quote phải được đánh giá là thỏa mãn bất biến này và biến (self)
đương nhiên cũng phải thỏa mãn ràng buộc bất biến đó.
1 context Quote inv QuoteOverZero: self.value > 0
OCL sử dụng để khởi tạo giá trị cho thuộc tính của các biến:
một đối tượng khi đối tượng đó được tạo ra. Để thực hiện công việc này, kiểu của biểu thức OCL khởi tạo và kiểu của thuộc tính được dùng khởi tạo phải phù hợp với nhau.
Biểu thức OCL sau đây khởi tạo giá trị là falsecho thuộc tínhpremium
củaCustomer(trạng thái của premiumsẽ được chuyển thành truekhi khách hàng đã thuê một số xe).
1 context Customer::premium: boolean init: false
Biểu thức OCL xác định các quy tắc tính tốn giá trị của các thuộc tính trong mơ hình dẫn xuất: các phần tử dẫn xuất là các phần tử mà có giá trị được suy dẫn từ các giá trị của các phần tử thuộc vào mơ hình nguồn. OCL là một lựa chọn phổ biến cho việc xác định các quy tắc dẫn xuất này.
Hãy xem xét quy tắc sau đây cho việc chiết khấu các phần tử dẫn xuất từ lớp Customer, phát biểu rằng các khách hàngs có trạng thái của thuộc
tínhpremiumlàtruethì được hưởng 30%, các khách hàng có trạng thái của thuộc tínhpremiumlà falsevà có ít nhất 5 chiếc xe cho thuê thì được giảm giá 15%, cịn lại tất cả các khách hàng khác đều khơng được giảm giá.
1 context Customer::discount: integer derive: 2 if not self.premium then
3 if self.rental.car.carGroup->select(c|c.category=’high’)->size ()>=5
4 then 15 else 0 endif 5 else 30 endif
Quy tắc này trong OCL sẽ cho phép tính các giá trị dẫn xuất phù hợp với từng trường hợp tương ứng.
Câu lệnh truy vấn: biểu thức OCL dạng này thực hiện truy vấn trên
cơ sở dữ liệu hệ thống và trả về thông tin cho người dùng.
Câu lệnh truy vấn sau sẽ trả về giá trị là true nếu chiếc car là chiếc được dùng nhiều nhất trong hệ thống xe cho thuê.
1 context Car::mostPopular(): boolean
2 body: Car::allInstances()->forAll(c1|c1<>self
3 implies c1.rentalAgreement->size()<=self.rentalAgreement->size ())
Biểu diễn tiền/hậu điều kiện của các phép tốn: có hai cách tiếp
cận để kiểm tra sự thỏa mãn của các ràng buộc về tiền/hậu điều kiện đối với các phép toán. Cách thứ nhất là dùng các câu lệnh chỉ thị và cách thứ hai là đặc tả các ràng buộc thông qua hợp đồng (contract). Trong cách tiếp cận đầu tiên, người thiết kế xác định rõ ràng tập các câu lệnh cấu trúc và các cấu trúc này sẽ được thực thi khi thực hiện phép toán. Theo cách tiếp cận thứ hai, nhà thiết kế sẽ cung cấp cho mỗi hoạt động một hợp đồng của nó. Mỗi hợp đồng bao gồm một tập các điều khoản về tiền/hậu điều kiện. Tiền điều kiện xác định một tập hợp các ràng buộc đầu vào trước khi hoạt động được thực thi, còn hậu điều kiện cho biết các ràng buộc mà hệ thống phải thỏa mãn khi kết thúc giao dịch. OCL là ngôn ngữ thường được lựa chọn để biểu diễn cho tiền/hậu điều kiện của hoạt động mức độ mơ hình.
1 context Rental::newRental(id:Integer, price:Real, startingDate: Date,
2 endingDate:Date, customer:Customer, carRegNum:String, pickupBranch: Branch, dropOffBranch: Branch)
3 pre: customer.licenseExpDate>endingDate
4 post: Rental.allInstances->one(r | r.oclIsNew() and 5 r.oclIsTypeOf(Rental) and r.endingDate=endingDate and r.
startingDate=startingDate
6 and r.driver=customer and r.pickupBranch=pickupBranch and r. dropOffBranch=dropOffBranch
7 and r.car=Car.allInstances()->any(c | c.regNum=carRegNum))
Biểu thức tiền điều kiện được đặt sau từ khóapre và hậu điều kiện được đặt sau từ khóa post.
Như vậy, trong Tiểu mục này luận án đã trình bày một số đặc trưng cơ bản của ngôn ngữ ràng buộc đối tượng OCL, cụ thể là các biểu thức OCL đặc tả bất biến (invariants), tiền/hậu điều kiện (pre/post-conditions)
bổ sung vào mơ hình thiết kế của hệ thống. Đặc biệt, luận án sẽ sử dụng các biểu thức đặc tả này để biểu diễn các ràng buộc về bất biến và hành vi cần kiểm chứng trong tiến trình tái cấu trúc trong các Chương 3 và 4. Nói cách khác, các ràng buộc cần kiểm chứng sự bảo tồn được biểu diễn một cách hình thức bằng các biểu thức OCL, điều này làm tăng tính chính xác cũng như tạo điều kiện dễ dàng cho các bước tiếp theo của tiến trình kiểm chứng.
2.6 Ngơn ngữ đặc tả cho Java (Java ModelingLanguage - JML) Language - JML)
Tại giai đoạn thiết kế hệ thống, tổ chức OMG cung cấp cho chúng ta ngôn ngữ ràng buộc OCL để biểu diễn các điều kiện ràng buộc trên mơ hình. Tại giai đoạn cài đặt mã nguồn, ngôn ngữ JML (Java Modeling Language) [36] là ngôn ngữ đặc tả hình thức được sử dụng để hỗ trợ cho ngơn ngữ lập trình Java trên khía cạnh đặc tả và kiểm chứng các ràng buộc về bất biến, tiền/hậu điều kiện của các phương thức trong chương trình. Đặc tả JML được nhúng vào mã nguồn Java (có thể ở cùng tệp mã nguồn của Java hoặc ở một tệp riêng biệt) và bắt đầu bởi kí hiệu //@<JML specification >hoặc /∗@ <JML specification > @∗/ theo sau là các thuộc tính cần đặc tả. Một số từ khóa cơ bản như requires, ensures định nghĩa các biểu thức tiền điều kiện, hậu điều kiện và invariant định nghĩa các bất biến. Đặc tả 2.1 biểu diễn các biểu thức tiền và hậu điều kiện để kiểm tra trạng thái cho phương thức analyzeTimeLimit() sử dụng ngơn ngữ JML. Các thuộc tính được đặc tả trong JML sẽ được biên dịch và thực thi cùng với mã nguồn để kiểm chứng sự thỏa mãn nó. 1 //@ ensures ((state==STATE.heavyTraffic)&&(signal==SIGNAL.red)) ==>(signalTime==\old(signalTime)-10); 2 //@ also 3 //@ensures ((state==STATE.heavyTraffic)&&(signal==SIGNAL.green) )==>(signalTime==\old(signalTime)+10); 4 //@ ensures ((state==STATE.lowTraffic)&&(signal==SIGNAL.red)) ==>(signalTime==\old(signalTime)+10); 5 //@also 6 //@ ensures ((state==STATE.lowTraffic)&&(signal==SIGNAL.green)) ==>(signalTime==\old(signalTime)-10);
Đặc tả 2.1: Biểu thức JML đặc tả cho phương thức
analyzeTimeLimit().
Hiện nay, đã có nhiều cơng cụ được xây dựng và phát triển để kiểm chứng mã Java cùng với đặc tả JML của nó như ESC/Java2 [25], RAC [13] hay OpenJML [17, 37], các cơng cụ này đều có thể tích hợp vào Eclipse.
Như vậy, xét về mặt vai trị ngơn ngữ ràng buộc OCL và ngôn ngữ đặc tả JML đều được sử dụng để đặc tả các ràng buộc về bất biến và hành vi của hệ thống phần mềm. Tuy nhiên, thời điểm sử dụng các ngôn ngữ này
là khác nhau, OCL được sử dụng bổ sung các đặc tả cho mơ hình hệ thống cịn JML lại biểu diễn các ràng buộc tại giai đoạn cài đặt hệ thống phần mềm.
2.7 Logic vị từ bậc 1 (First-Order Logic - FOL)
Lôgic vị từ bậc 1 (FOL) [63] cung cấp cho chúng ta khả năng biểu diễn các biểu thức logic mệnh đề (propositional logic) và cách thức định lượng hóa trên các đối tượng. Nhờ vào các lượng từ trong FOL chúng ta có thể mơ tả các đối tượng và mối quan hệ giữa chúng một cách chính xác. Đây chính là ưu điểm của FOL so với logic mệnh đề. FOL có thể dùng để biểu diễn lý thuyết số, lý thuyết tập hợp và thậm chí biểu diễn sự tính tốn trong máy Turing.
Bây giờ chúng ta sẽ mô tả một cách ngắn gọn các ký hiệu cơ bản dùng để xây dựng lên các công thức FOL. Các ký hiệu này được trình bày đầy đủ trong [63].
Các phép toán kết hợp (Logical connectives)(⇒,∧,∨, và ⇔), phủ định (¬), và dấu ngoặc. Chúng sẽ được sử dụng một cách đệ quy để tạo nên các công thức phức hợp.
Các ký hiệu hằng (Constants symbols) là các chuỗi (a, b, c, v.v.) dùng để biểu diễn thay thế cho các đối tượng.
Các ký hiệu biến (Variable symbols) sẽ được sử dụng như những “place holders” cho việc định lượng hóa trên các đối tượng.
Các ký hiệu vị từ (Predicate symbols) mỗi ký hiệu được liên kết với arity (ví dụ, số lượng các đối số), có thể là 0 hoặc một số xác định khác. Vị từ được dùng để biểu diễn cho thuộc tính của các đối tượng và mối quan hệ giữa chúng.
Các ký hiệu hàm (Function symbols) mỗi ký hiệu được đặc tả bởi arity (ví dụ, số lượng các đối số nhập vào) đây là một hàm ánh xạ từ một số lượng các đối tượng đến các đối tượng.
Các lượng từ với mọi và tồn tại (Universal and existential quan- tifier symbols) dùng để định lượng hóa trên các đối tượng.
Chương5của luận án trình bày về vấn đề phát triển cơng cụ hỗ trợ kiểm chứng tính nhất quán trong tái cấu trúc mơ hình phần mềm. Như đã đề cập, tại giai đoạn thiết kế hành vi cần kiểm chứng được biểu diễn bằng ngôn ngữ ràng buộc đối tượng OCL. Tuy nhiên, cho tới thời điểm hiện tại, các công cụ phát triển cho OCL cịn khá hạn chế trong khi cơng cụ sử dụng logic vị từ bậc nhất đã ở giai đoạn trưởng thành cả về số lương và chất lượng. Bởi vậy Tiểu mục này trình bày các kiến thức cơ sở về cơng thức FOL, các ràng buộc về hành vi biểu diễn bằng biểu thức OCL sẽ được chuyển đổi sang các công thức FOL này. Cơng cụ hỗ trợ kiểm chứng tính nhất qn CVT khơng thao tác trực tiếp trên các biểu thức OCL mà sẽ thực hiện kiểm tra tính nhất quán trên các công thức FOL tương ứng này.
2.8 Kết chương
Trong chương này luận án đã trình bày tóm tắt các kiến thức nền được sử dụng trong các chương tiếp theo. Mục 2.1 diễn tả về kỹ thuật tái cấu trúc với một số đặc điểm chính của kỹ thuật này. Mục 2.2 dành sự quan tâm đặc biệt đối với các khái niệm khóa của mơ hình hướng đối tượng được hình thức hóa trong các Chương 3 và 4. Mục2.3 luận án trình bày về ngơn ngữ mơ hình hóa thống nhất UML cùng với hai loại biểu đồ tiêu biểu là
biểu đồ lớp và biểu đồ tuần tự. Mục 2.4 diễn tả mẫu thiết kế Strategy thuộc về nhóm các mẫu hành vi, là mẫu thiết kế được áp dụng trong Chương 4. Ngôn ngữ ràng buộc đối tượng OCL được mô tả trong Mục 2.5. Cuối cùng là các kiến thức tổng quan về ngôn ngữ đặc tả cho Java (JML) và logic vị từ bậc 1 (FOL), đây là các phương tiện để biểu diễn các ràng buộc của hệ thống cần phải nghiên cứu sự bảo tồn trong tiến trình tái cấu trúc.
PHƯƠNG PHÁP BẢO TOÀN BẤT BIẾN TRONG TÁI CẤU TRÚC
Trong chương này, luận án đề xuất phương pháp bảo toàn các bất biến (class invariants) trong tái cấu trúc biểu đồ lớp của UML. Cụ thể, luận án
tập trung vào việc xây dựng các luật tái cấu trúc (refactoring rules) cho các phép toán tái cấu trúc (refactoring operations). Đồng thời cũng chứng
minh tính đúng đắn của các luật tái cấu trúc đã đề xuất khi áp dụng vào tiến trình tái cấu trúc.
3.1 Giới thiệu
Bất biến của lớp (class invariants) là khái niệm quan trọng sử dụng để mơ tả một cách chính xác các ràng buộc ngữ nghĩa áp dụng cho các thành phần (thuộc tính, quan hệ) của biểu đồ lớp trong UML. Tái cấu trúc thực hiện trên biểu đồ lớp đương nhiên sẽ ảnh hưởng trực tiếp đến các ràng buộc