Giả sử chúng ta chỉ vừa mới bắt đầu việc thiết kế và chưa có gì nhiều trong mô hình thiết kế. Chúng ta sẽ tìm kiếm trong mô hình domain để tìm ra lớp IE và lớp đó chính là Sale. Chúng ta thêm vào mô hình thiết kế lớp phần mềm mới cũng có tên gọi là Sale và gán cho nó nhiệm vụ biết “knowing total” thông qua method getTotal.
62 trang |
Chia sẻ: maiphuongdc | Lượt xem: 3183 | Lượt tải: 3
Bạn đang xem trước 20 trang tài liệu Bài giảng Design Pattern, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
CHƯƠNG 8:Design Pattern * Nội dung * Coupling là gì? Cohesion là gì? Pattern là gì? GRASP là gì? Coupling là gì? Coupling là 1 cách để đo lừơng xem 1 phần tử khi được kết nối thì nó có khả năng “hiểu biết” đến mức nào hay hoàn toàn phụ thuộc vào các phần tử khác. Phần tử có thể là class, subsystem, system… Một phần tử có coupling thấp (low coupling) nghĩa là nó không phụ thuộc nhiều vào các phần tử khác. * Coupling là gì? Một lớp có coupling cao sẽ phụ thuộc vào nhiều lớp khác. Các lớp này là không nên dùng vì: Những thay đổi trong các lớp có liên quan sẽ làm cho lớp này cũng bị thay đổi theo Khó hiểu khi chúng bị cô lập Khó dùng lại vì nó đòi hỏi sự hiện diện của 1 số lớp mà nó phụ thuộc vào * Cohesion là gì? Coupling đề cập đến sự tương tác giữa các đối tượng thì cohesion đề cập đến sự tương tác bên trong 1 đối tượng. Cohesion là 1 cách đo lường để xem các nhiệm vụ của 1 phần tử có quan hệ chặt chẽ với nhau như thế nào? Một phần tử có trách nhiệm tương đối cao, và không phải làm quá nhiều việc được xem là có cohesion cao (high cohesion) * Cohesion là gì? Một lớp có low cohesion khi nó làm nhiều việc không liên quan nhau hay làm quá nhiều việc. Những lớp này là không nên dùng vì: Khó hiểu Khó dùng lại Khó bảo trì Dễ bị ảnh hưởng bởi các thay đổi Các lớp có cohesion thấp thường biểu diễn cho việc trừu tượng ở mức quá lớn, hay nhận những nhiệm vụ mà lẽ ra phải giao lại cho các đối tượng khác thực hiện. * Cohesion là gì? Method cohesion: là method chỉ đảm nhiệm 1 chức năng hay 1 nhiệm vụ. Thông thường cách đặt tên của nó cũng ngầm nói lên chức năng, ví dụ method chon_nha_cung_cap(), Tinh_tong() Class cohesion: các thuộc tính và method của lớp phải có mức độ cohesion cao, nghĩa là chúng phải được dùng bởi chính các method trong class hay chỉ chứa các method phục vụ cho mục đích chính của class * Các mức độ cohesion Very low cohesion: một class phải tự mình làm nhiều việc trong những miền chức năng hoàn toàn khác nhau. Ví dụ: một lớp vừa có có nhiệm vụ tương tác với database quan hệ vừa quản lý các lệnh gọi thủ tục từ xa. Những nhiệm vụ này thuộc 2 vùng chức năng khác nhau, nên lớp này có very low cohesion. * Các mức độ cohesion Low cohesion: class có nhiệm vụ phải tự mình thực hiện 1 công việc phức tạp trong 1 vùng chức năng. Ví dụ: một lớp có nhiệm vụ tương tác với database quan hệ. Các method của lớp đều có liên quan với nhau nhưng lớp này có quá nhiều method để đảm đương nhiệm vụ Nên chia lớp này thành 1 họ các lớp cùng chia xẻ nhau công việc truy xuất database. * Các mức độ cohesion High cohesion: lớp có nhiệm vụ vừa phải (moderate responsibilities) trong cùng 1 vùng chức năng và hợp tác với các lớp khác để hoàn thành nhiệm vụ. Ví dụ: lớp RDBInterface chỉ có 1 phần nhiệm vụ trong việc tương tác với database. Nó tương tác với hàng tá các lớp khác để khôi phục và lưu trữ dữ liệu. * Quy luật Cohesion và Coupling Cohesion kém thì thường sinh ra coupling kém và ngược lại. Cohesion và couling được ví như âm và duơng (yin and yang) của software engineering * Các lợi ích của high cohesion Làm cho việc thiết kế rõ ràng và dễ hiểu hơn. Việc bảo trì và mở rộng cũng đơn giản hơn. Low coupling thường đuợc hỗ trợ. * Pattern là gì? Trong thực tế có rất nhiều lược đồ class có cấu trúc giống nhau. Pattern được xem như là giải pháp hay cách thức để giải quyết bài toán. Khái niệm về pattern trong thiết kế phần mềm đuợc vay mượn từ ngành kiến trúc xây dựng nơi mà các pattern trợ giúp rất nhiều cho các kiến trúc sư khi làm việc với các cấu trúc phức tạp * Pattern là gì? Một pattern khi được áp dụng vào1 ngữ cảnh mới sẽ đưa ra các khuyến cáo (recommendation) làm thế nào để áp dụng và hòa hợp nó vào tình huống mới “A pattern is a named problem/ solution pair that can be applied in new context, with advice on how to apply it in novel situations and discussion of its trade-offs” * GRASP GRASP (General Responsibility Assignment Software Patterns) bao gồm nhiều pattern mô tả các nguyên tắc cơ bản trong việc thiết kế đối tượng và gán nhiệm vụ cho đối tượng. Hiểu và áp dụng các nguyên tắc GRASP trong quá trình tạo lược đồ tương tác là rất quan trọng giúp thiết kế thành công phần mềm hướng đối tượng. * GRASP Mô hình thiết kế có thể chứa hàng trăm hay hàng ngàn các lớp phần mềm, và 1 ứng dụng có thể yêu cầu hàng trăm hay hàng ngàn các nhiệm vụ cần phải hoàn thành. Khi thiết kế đối tượng, cần chọn lựa xem nhiệm vụ nên gán cho đối tượng nào là phù hợp hơn. Nếu gán hợp lý, hệ thống sẽ trở nên dễ hiểu, dễ bảo trì và mở rộng. * GRASP Có rất nhiều pattern thuộc loại này nhưng 5 pattern cơ bản nhất : Information Expert Creator High Cohesion Low Coupling Controller * Information Expert (or Expert) Solution: Assign a responsibility to the information expert - the class that has the information necessary to fulfill the responsibility. Problem: What is a general principle of assigning responsibilities to objects? Gọi tắt pattern này là IE * Case study 1: Lớp nào biết tổng trị giá Nếu có một số lớp cần biết tổng trị giá của 1 lần bán. Câu hỏi đặt ra là lớp nào có nhiệm vụ cho biết tổng trị giá một lần bán. Theo IE cần tìm xem có lớp nào chứa thông tin cần thiết để xác định tổng số hay không? Chúng ta nên tìm các lớp trong mô hình domain hay mô hình thiết kế. * Case study 1: Lớp nào biết tổng trị giá Trước hết tìm các lớp thích hợp trong mô hình thiết kế. Nếu không tìm thấy, thì tìm các lớp trong mô hình domain và cố sử dụng các lớp trong mô hình domain để tạo lập các lớp tương ứng trong mô hình thiết kế. * Case study 1: Lớp nào biết tổng trị giá Giả sử chúng ta chỉ vừa mới bắt đầu việc thiết kế và chưa có gì nhiều trong mô hình thiết kế. Chúng ta sẽ tìm kiếm trong mô hình domain để tìm ra lớp IE và lớp đó chính là Sale. Chúng ta thêm vào mô hình thiết kế lớp phần mềm mới cũng có tên gọi là Sale và gán cho nó nhiệm vụ biết “knowing total” thông qua method getTotal. * Case study 1: Lớp nào biết tổng trị giá * Case study 1: Lớp nào biết tổng trị giá Thông tin gì cần biết để xác định thành tiền (subtotal) của mỗi mặt hàng (line item)? cần phải biết số lượng (quantity) và đơn giá (price). Theo mô hình nghiệp vụ, thì lớp SalesLineItem biết số lượng (quantity) và thông tin hàng (ProductSpecification) tương ứng. Vì vậy, SalesLineItem xác định được thành tiền (subtotal) nên nó cũng là IE. * Case study 1: Lớp nào biết tổng trị giá Trong lược đồ tương tác ,để nhận thành tiền của mỗi mặt hàng thì lớp Sale cần gửi thông điệp get-Subtotal cho mỗi lớp SalesLineItem và tính tổng trên kết quả mà nó nhận được * Case study 1: Lớp nào biết tổng trị giá Để hoàn thành nhiệm vụ biết và trả lời thành tiền (subtotal), lớp LineItem cần biết đơn giá sản phẩm. Lớp ProductSpecification là IE sẽ giúp trả lời về đơn giá. Và lớp này cần một thông báo được gửi đến để hỏi giá. * Case study 1: Lớp nào biết tổng trị giá * Case study 1: Lớp nào biết tổng trị giá Tóm lại để hoàn tất nhiệm vụ biết và trả lời tổng trị giá bán, ba nhiệm vụ được gán vào ba lớp thiết kế như sau: * Information Expert IE thường được dùng trong việc gán nhiệm vụ (responsibilitiy); Nó là 1 nguyên tắc hướng dẫn cơ bản được dùng liên tục trong thiết kế object. Nó diễn đạt nhận thức ("intuition“) chung rằng object làm các việc có liên quan đến thông tin chúng có. Việc hoàn thành nhiệm vụ thường yêu cầu thông tin ngang qua các class khác nhau, có nghĩa là có nhiều IE bộ phận (partial) cộng tác nhau để làm nhiệm vụ * Creator Solution: Assign class B the responsibility to create an instance of class A if one or more of the following is true: B aggregates A objects. B contains A objects. B records instances of A objects. B closely uses A objects. B has the initializing data that will be passed to A when it is created B is a creator of A objects. If more than one option applies, prefer a class B which aggregates or contains class A. * Creator Problem: Who should be responsible for creating a new instance of some class? The creation of objects is one of the most common activities in an object-oriented system. Consequently, it is useful to have a general principle for the assignment of creation responsibilities. Assigned well, the design can support low coupling, increased clarity, encapsulation, and reusability. * Creator Solution: gán cho class B trách nhiệm phải tạo 1 instance của class A nếu 1 trong các điều kiện sau đúng: B kết hợp các đối tượng A (B aggregates A objects). B chứa các đối tượng A. B sử dụng thường xuyên các đối tượng A. B có các dữ liệu khởi tạo cần được chuyển cho A khi A được khởi tạo B là 1 creator của A Problem : Ai nên có trách nhiệm tạo 1 instance mới cho 1 số class? Việc tạo đối tương là 1 trong những hoạt động thông dụng nhất trong hẹ thống OO. Cần có các nguyên tắc chung để gán trách nhiệm này. Nếu gán đúng, thiết kế có thể hỗ trợ low coupling, tăng độ rõ ràng, khả năng sử dụng lại * Case Study: Lớp nào tạo điển hình của SalesLineItem Trong ứng dụng POS, ai có trách nhiệm tạo instance của lớp SalesLineltem ? Theo Creator, cần tìm 1 lớp mà nó kết hợp và chứa các instance của SalesLineltem. * Case Study: Lớp nào tạo điển hình của SalesLineItem * Case Study: Lớp nào tạo điển hình của SalesLineItem Từ mô hình domain, cho thấy lớp Sale chứa nhiều đối tượng SalesLineltem, do đó Creator đề nghị Sale là 1 ứng viên tốt cho nhiệm vụ tạo các instance của SalesLineltem. Dẫn đến việc vẽ lược đồ tương tác như sau * Lược đồ tuần tự * Creator Việc gán nhiệm vụ này dẫn đến việc là phải có method makeLineItem() trong lơp Sale Việc xem xét và gán nhiệm vụ đã được làm trong lúc vẽ lược đồ tương tác. * Creator Creator hướng dẫn việc gán responsibility có liên quan đến việc tạo các object. Mục đích cơ bản của Creator là tìm 1 class cần kết nối tới object được tạo trong bất kỳ sự kiện nào. Các container, hay class dạng ghi chép lưu trữ đều là ứng viên tốt để làm creator. * Creator Đôi khi lớp creator được tìm thấy trong lúc tìm kiếm lớp chứa dữ liệu ban đầu cần được chuyển cho lớp sẽ được tạo. Ví dụ: giả sử instance của Payment cần có giá trị khởi đầu (initial value) là tổng số tiền bán khi nó được tạo. Vì Sale biết tổng số này nên Sale là ứng viên tốt để trở thành creator của Payment. * Low Coupling Solution gán responsibility sao cho coupling vẫn giữ được ở mức thấp. Problem Làm thế nào để làm cho sự phụ thuộc thấp, những ảnh hưởng khi thay đổi thấp, và khả năng sử dụng lại tăng. (How to support low dependency, low change impact, and increased reuse?) * Ví dụ Trong lược đồ lớp có 3 lớp sau: register, Sale và Payment. Giả sử ta có nhu cầu tạo 1 instance của Payment và kết nối nó với Sale. Lớp nào có thể làm điều này? Vì Register phải ghi chép lại ("records“) các thanh toán (Payment) trong thế giới thực nên Creator đề cử Register là ứng viên tạo Payment. Tiếp đó Register cũng cần gửi message “addPayment” cho Sale, kèm theo tham số là “new payment”. Khi đó lược đồ tương tác sẽ được vẽ như sau: * Cách 1: gán trách nhiệm cho Register Việc gán responsibility này đã làm cho lớp Register phải biết (knowledge) đến lớp Payment. Điển hình Payment này được đặt tên tường minh là p vì vậy trong message số 2 nó được tham chiếu như 1 tham số * Cách 2: gán trách nhiệm cho Sale Để Sale tạo lớp Payment * Chọn lựa thiết kế Thiết kế nào hỗ trợ Low Coupling? Trong cả 2 trường hợp, ta đều giả sử là Sale cuối cùng đều phải biết đến Payment. Cách 1: Register tạo Payment, thêm 1 kết nối từ Register tới Payment Cách 2: Sale tạo Payment, không thêm bất kỳ coupling nào Thiết kế cách 2 tốt hơn * Chọn lựa thiết kế Trường hợp đặc biệt của Low Coupling là khi không có 1 coupling nào giữa các class. Điều này cũng không tốt vì theo hướng đối tượng thì các đối tượng cần giao tiếp với nhau thông qua các message. Nếu Low Coupling được thực hiện quá triệt để thì sẽ tạo ra 1 thiết kế nghèo nàn, các đối tương không couple sẽ làm việc như 1 kho dữ liệu đơn thuần hoặc chúng phải tự làm hết mọi việc. * High Cohesion Solution: gán nhiệm vụ (responsibility) sao cho cohesion vẫn giữ ở mức cao. Problem Làm thế nào vẫn quản lý được độ phức tạp (complexity)? * Ví dụ Trong ví dụ trước để tạo 1 instance của Payment và kết hợp nó với Sale. Class gì nên làm việc này? Vì Register ghi chép lại Payment nên creator đề nghị Register là 1 ứng viên cho việc tạo Payment. Sau đó Register gửi message addPayment cho Sale cùng với tham số là payment mới vừa tạo. * Ví dụ Register đang nhận trách nhiệm hoàn thành thao tác hệ thống makePayment. Nếu chỉ xét trong phạm vi ví dụ này thì nhiệm vụ này có thể chấp nhận được, nhưng nếu tiếp tục gán cho Register nhiều việc hơn, nó sẽ trở nên quá tải và không còn cohesion nữa. * Controller Solution: gán nhiệm vụ nhận và quản lý một thông báo sự kiện hệ thống cho một lớp có một trong hai dạng sau: Đại diện cho cả hệ thống, thiết bị hay hệ thống con (boundary class). Đại diện cho một kịch bản use case mà trong đó có sự kiện hệ thống xảy ra, lớp này thường được đặt tên là Handler, Coordinator, hay Session. * Controller Problem: Ai có trách nhiệm quản lý một sự kiện hệ thống đầu vào (input system event)? Sự kiện hệ thống đầu vào (input system event) là 1 sự kiện được phát ra bởi actor bên ngoài. Chúng kết hợp với các thao tác hệ thống (system operation) giống như vai trò của messgase và method * Controller Ví dụ: khi thâu ngân sử dụng phần mềm POS nhấn nút "End Sale“, anh ta đã phát ra 1 sự kiện hệ thống chỉ ra “việc bán hàng đã kết thúc”. Tương tự, khi người dùng phần mềm xử lý văn bản nhấn nút "spell check“, anh ta đã phát ra 1 sự kiện hệ thống chỉ ra “nhiệm vụ kiểm tra chính tả”. Controller là 1 đối tượng giao diện không dành cho người dùng (non-user interface object) có trách nhiệm nhận và quản lý sự kiện hệ thống. Controller sẽ định nghĩa các method cho hoạt động của hệ thống. * Thao tác hệ thống (System operation) Trong quá trình phân tích, các thao tác hệ thống có thể được gán tạm cho lớp phân tích System. Điều này không có nghĩa là lớp phần mềm System phài thực hiện hết các thao tác này. Trong lúc thiết kế các lơp controller sẽ lần lượt được gán nhiệm vụ thực thi các thao tác hệ thống này. Trong ứng dụng POS có rất nhiều thao tác hệ thống như sau: endSale() enterItem() makeNewSale() makePayment() . . * Case study : hệ thống POS Lớp nào sẽ là controller cho các sự kiện hệ thống chẳng hạn như enterltem và endSale Theo mẫu Controller, có thể có 1 số chọn lựa sau khi tạo lớp thiết kế : Biểu diễn thành 1 hệ thống chung đặt tên là Register hay POSSystem Biểu diễn thành receiver hay handler để quản lý tất cả các sự kiện hệ thống theo kịch bản của UC như ProcessSaleHandler, ProcessSaleSession * Case study : hệ thống POS * Lớp controller cho enterItem Lớp controller cho sự kiện hệ thống enterItem có thể là 1 trong 2 dạng trên * * Bloated Controllers Nếu thiết kế không tốt một lớp controller sẽ bị low cohesion và sẽ được gọi là bloated controller. Dấu hiệu để nhận biết 1 lớp bị bloated: Chỉ có 1 lớp controller duy nhất để nhận mọi sự kiện hệ thống và có khá nhiều sự kiện hệ thống. Chính controller phải thực thi nhiều nhiệm vụ mà không ủy thác công việc cho lớp khác. Controller có nhiều thuộc tính và chứa nhiều thông tin về hệ thống và nghiệp vụ. * Biện pháp tránh Bloated Controllers Bổ sung thêm các controllers. Một hệ thống không nên chỉ có 1 controller. Ví dụ hệ thống đặt chỗ vé máy bay, có thể chứa các controller sau: * Biện pháp tránh Bloated Controllers Thiết kế một controller chuyên trách làm nhiệm vụ giao phó việc hoàn thành từng thao tác hệ thống cho các đối tượng khác. * Hệ quả của mẫu Controller Các đối tượng interface (như các đối tượng window) và interface layer không nên có nhiệm vụ quản lý sự kiện hệ thống. Giả sử hệ thống POS có 1 cửa sổ hiển thị thông tin bán hàng (dùng lớp JFrame của Java) và thu nhận các thao tác của thâu ngân. Hãy xét 2 trường hợp interface layer này có và không can thiệp vào nhiệm vụ quản lý sự kiện hệ thống. * * Interface không quản lý sự kiện hệ thống Interface không quản lý sự kiện hệ thống Lớp SaleJFrame – một phần của interface layer – truyền thông điệp enterItem cho đối tượng Register. Nó không liên quan gì đến việc xử lý thao tác này, mà chuyển giao cho layer khác. Gán nhiệm vụ liên quan đến thao tác hệ thống cho controller (Register) sẽ làm tăng cơ hội sử dụng lại logic xử lý nghiệp vụ này cho các ứng dụng tương lai. * * Interface quản lý sự kiện hệ thống Interface quản lý sự kiện hệ thống Nếu SaleJFrame ( thuộc interface layer) quản lý luôn thao tác hệ thống enterItem, có nghĩa là nó chứa luôn logic xử lý nghiệp vụ, làm mất đi cơ hội sử dụng lại logic này vì nó bi kết nối (coupling) vào giao diện đặc biệt. *
Các file đính kèm theo tài liệu này:
- chuong_7_design_pattern_6244.ppt