Khung làm việc cộng tác

Một phần của tài liệu ứng dụng framework và lập trình ràng buộc cho bài toán lập thời khóa biểu (Trang 54 - 60)

Một sự cộng tác mô tả tương tác giữa các đối tượng được thiết kế để làm việc với nhau. Mỗi đối tượng được thiết kếđể nhằm một mục đích nhất định và tất cả các hoạt động của nó đều nhằm vào hoàn thành mục đích đó. Hầu hết các kỹ năng thiết kế

hướng đối tượng là thiết kế sự cộng tác. Kỹ thuật CRC (classes: các lớp, responsibilities: các trách nhiệm, collaborations: các cộng tác) là kỹ thuật cơ bản của việc thiết kế hướng đối tượng và là sự phân chia các trách nhiệm giữa các đối tượng cộng tác với nhau để làm một công việc nào đó. Chính việc phân tích này phân biệt việc lập trình hướng đối tượng và thiết kế hướng cấu trúc, ở đó tất cả các công việc

được gộp vào một chương trình. Nếu ta làm công việc thiết kế tốt, ta sẽ có được một thiết kế phân rã có tính linh hoạt và mở rộng được.

Khi hoàn thành tốt một thiết kế về sự cộng tác, nó sẽ có tác dụng ghi lại các ý tưởng của người thiết kế và sử dụng lại được các ý tưởng đó. Đây chính là động lực trong việc sử dụng các mẫu thiết kế. Một vài công cụ có khả năng hỗ trợ cách thức

định nghĩa các cộng tác này và kết nối chúng lại với nhau tạo thành các thiết kế lớn hơn.

Các khung làm việc chính là các thành phần có khả năng sử dụng lại của thiết kế. Chúng ta sẽ sử dụng các khung làm việc này vào các thành phần có khả năng sử

dụng lại của sự cộng tác.

Trong thực tế, các đối tượng tham gia vào nhiều sự cộng tác lẫn nhau, và trong mỗi cộng tác đó, nó đều có một vai trò nhất định. Ví dụ, khi miêu tả về sự cộng tác giữa đối tượng nhân viên, nó miêu tả sự tác động lẫn nhau giữa các nhân viên trong công việc. Tuy nhiên, một nhân viên vừa có thể đóng vai trò là người quản lý, vừa

đóng vai trò là nhân viên. Tức là khi tham dự vào nhiều sự cộng tác thì trong mỗi sự

cộng tác, một đối tượng có thểđóng vai trò khác nhau.

Tuy nhiên trong những sự cộng tác như vậy, có thể có các sự cộng tác riêng rẽ ảnh hưởng đến cùng một thuộc tính của một đối tượng. Ví dụ, giá trị tài khoản ngân hàng (thuộc tính) của một người có thểđược tăng lên nhờ vào việc gửi thêm tiền vào tài khoản (sự cộng tác giữa khách hàng và ngân hàng). Mặt khác giá trị tài khoản đó cũng có thể được tăng nhờ vào việc các nhân viên ngân hàng cộng gộp tiền lãi của tài khoản vào trong tài khoản gốc (sự cộng tác của nhân viên ngân hàng và ngân hàng) của người đó.

Để minh họa, ta xem xét sự cộng tác Subject-Observer. Trong hình 12 chúng ta chỉ ra các giao diện bên ngoài của mỗi đối tượng chia được thành các vai trò trong các sự cộng tác khác nhau cho dù các thuộc tính bên trong có thểđược chia sẻ. Sự cộng tác này “quản lý” hai vai trò: Subject Observer. Subject có thuộc tính value

Observer có thuộc tính khác được gọi là value_view. Một hành động update (cập nhật)

được khởi tạo bởi Subject và làm cho Observer cập nhật theo.

Hình 12. Sự cộng tác giữa các đối tượng

Tất nhiên một cặp các lớp bất kỳ có mối quan hệ như vậy trong một chuỗi các mã chương trình có thể không được gọi là SubjectObserver. Chúng có vai trò lớn và đáng quan tâm hơn trong chương trình của chúng, có lẽ giống như các thành phần của GUI hay các ủy nhiệm trong các hệ thống phân tán. Nhưng cái đó mới nói lên chính xác khung làm việc là gì: Chúng ta có thể chỉ định nghĩa các khía cạnh về một cái gì đó mà ta muốn nói và sau đó cho phép người dùng sử dụng các tên khác và mở

rộng các định nghĩa khi họ áp dụng khung làm việc của ta.

Chính vì thế, đúng như chúng ta chỉ ra trong hình 12, chúng ta thực sự chỉ biết một phần của đối tượng mà chúng ta đang miêu tả: phần còn lại phụ thuộc vào bất cứ

ai sử dụng khung làm việc. Trong ví dụ này, chúng ta không biết cách thức và tại sao

value của Subject thay đổi. Chúng ta chỉ biết rằng nó có thể thay đổi và khi nó thay đổi

Observer phải được cập nhật.

value value_view

Cập nhật

Subject Observer Các vai trò được nắm giữ bởi phần này của mỗi đối tượng Phần này của đối tượng liên quan đến sự cộng tác và không được biết đến Phần này của đối tượng liên quan đến sự cộng

tác Subject-Observer Biđếến cn nảộ hai phi tại liên quan ần Phần còn lại của đối tượng

3.2.1.1. Các hành động trong khung làm việc cộng tác

Sự khác nhau lớn nhất giữa khung làm việc này và các khung làm việc khác là khung làm việc này có các hành động. Thực tế, khung làm việc này có các hành động sau:

♦ Hành động cập nhật giữa SubjectObserver.

♦ Tất cả các hành động khác mà ta không biết về chúng, các hành động đó thay

đổi giá trị của Subject.

Việc xác định hành động đầu tiên là khá dễ dàng:

action Observer :: update () post value_view = subject.value

- - phản ánh một cách chính xác giá trị value của Subject

Hành động update chỉ là một trong rất nhiều hành động có thể làm thay đổi giá trị value của Subject. Nói một cách hình thức, ta sử dụng một kết quả bất biến, tức là ta không quan tâm đến các hành động xảy ra đối với hệ thống như thế nào, khi nào và như thế nào. Ta chỉ cần biết rằng, khi có một hành động xảy ra thì ta thu được một kết quả bất biến. Ở đây cũng vây, ta không quan tâm xem hành động nào xảy ra, xảy ra khi nào và xảy ra như thế nào đối với giá trị của Subject, nhưng ta chỉ biết một kết quả

bất biến là khi giá trị bị thay đổi thì hành động update luôn xảy ra: nó là một điều kiện sau :

inv effect Subject ::

post value@pre <> value _ [[ observers.update() ]]

---Bất cứ hành động nào thay đổi giá trị value cũng đảm bảo Observer phản ánh chính xác giá trị mới.

Điều kiện sau không chỉ áp dụng cho khung làm việc, mà nó còn phải được thực hiện một cách chính xác trong các chương trình cụ thể là trong các lớp của

SubjectObserver. Không những thế các đặc tả (làm tài liệu) của nó cũng phải miêu tả chính xác về các điều kiện sau này.

Hình sau đây chỉ ra khung làm việc cộng tác như chúng ta đã miêu tả nó trong phần trước. Sự kết hợp Subject-Observer liên kết các thể hiện cụ thể của hai kiểu này và hành động update chỉ áp dụng cho các Observer có một Subject hiện tại. Hành động

register liên kết một Subject cụ thể tới một Observer cụ thể. Nó là một hành động kết nối mà chúng ta không xác định cách thức nó xảy ra, thậm chí ai là người gửi thông

điệp làm cho nó xảy ra, chúng ta chỉ xác định được là sẽ có một hành động như thế, với trách nhiệm thực thi nó được phân bố giữa SubjectObserver.

Hình 13. Khuôn mẫu cộng tác 3.2.1.2. Áp dụng khung làm việc cộng tác

Bây giờ chúng ta sẽ xem xét một áp dụng cho khung làm việc cộng tác đã nói ở

phần trên cho hệ thống quản lý cuộc gọi. Một trong số các kiểu của mô hình được gọi là CallQueue: một danh sách các cuộc gọi. Giả sử chúng ta đã có kiểu đó trong một gói nào đó. Trong gói khác ta có một tập trang bị các giao diện người sử dụng đồ họa (GUI), mà một trong sốđó là Thermometer—dùng cho việc hiển thị giá trị các số.

Bây giờ chúng ta thiết kế một cầu nối giữa lôgic nghiệp vụ và giao diện người sử dụng đồ họa (GUI), và chúng ta tạo ra một gói mà trong đó chúng ta thay thế

ThermometerCallQueue. Ta muốn Thernmometer được sử dụng để chỉ ra số cuộc gọi ( Calls) trong một danh sách hàng đợi cuộc gọi ( CallQueue). Chính vì vậy chúng ta áp dụng khung làm việc quan sát như hình 14. Tại đây chúng ta thêm vào các đặc tả

<value> <value_view> Register subject observers update 0,1 0..* <Subject> <Observer> Observer :: action update ( )

pre subject <> null

post value_view = subject.value

(s: Subject, o: Observer) :: action register ( ) pre o.subject = null post o.subject = s

Subject ::

inv effect

post value @ pre <> value ® [[observers.update()]]

cần thiết. Hình 13 hiển thị mô hình được mở: kết quả của việc áp dụng khung làm việc và đưa ra đặc tả.

Hình 14. Mô hình kiểu đích cho việc sử dụng sự quan sát

Hình 15. Ví dụứng dụng khung làm việc và sự thay thế

addCall (c : Call)

post calls = calls @ pre + c getCall ( ) : Call

post result = calls @ pre->head & calls = calls @ pre->tail

temperature : int other stuff about Thermometers Thermometer Call CallQueue calls 0..* {seq} CallQueue Call Thermometer reading Observation Subject [value\calls->size] Observer [value_view\reading] 0..* calls

Hình 16. Kết quả mở của ứng dụng khung làm việc

Khi nhìn vào ứng dụng khung làm việc, ta thấy tên SubjectObserverđã được thay thế và các phương thức addCallgetCall cũng đã được đưa vào, chúng luôn luôn thay đổi độ lớn các cuộc gọi vào mọi lúc, chính vì vậy cần loại bỏ

value<>value@pre từ các hậu điều kiện của chúng. Tại đây, hành động update có thể được nhận diện như thông điệp notify (newvalue) hay theo kiểu MVC (Model, View, Control) thì có thể bao gồm thông điệp update() tới Thermometer, và sau đó, nó phải quay ngược trở lại CallQueueđể yêu cầu chi tiết về sự thay đổi đã xảy ra.

addCall (c : Call) post calls = calls @ pre + c

& [[observers.update ( )]]

getCall ( ) : Call post result = calls @ pre->head

& calls = calls @ pre- >tail & [[observers.update ( )]] CallQueue reading other stuff about Thermometers Thermometer Call calls 0..* {seq} subject observers 0,1 0..* update register Thermometer :: action update ( ) pre subject <> null

post reading = subject.calls->size

(s: CallQueue, o: Thermometer) :: action register ( )

pre o.subject = null post o.subject = s

Hành động register có thểđược khởi tạo bằng một đối tượng giám sát để chỉ ra một Thermometer cụ thể quan sát một CallQueue cụ thể. Tiếp đó, Thermometer phải chỉ ra chính bản thân nó cho CallQueue biết, có như vậy thì chúng mới biết về nhau.

Một phần của tài liệu ứng dụng framework và lập trình ràng buộc cho bài toán lập thời khóa biểu (Trang 54 - 60)