1. Trang chủ
  2. » Công Nghệ Thông Tin

Tài liệu NGUYÊN LÝ THIẾT KẾ HƯỚNG ĐÔI TƯỢNG - LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG doc

55 1,1K 3
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Nguyên lý thiết kế hướng đối tượng - Lập trình hướng đối tượng
Tác giả Bob Tarr
Trường học Trường Đại học Công nghệ Thông tin - Đại học Quốc gia Hà Nội
Chuyên ngành Nguyên lý thiết kế hướng đối tượng
Thể loại Sách giáo trình
Thành phố Hà Nội
Định dạng
Số trang 55
Dung lượng 419,5 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

"Trừu tượng hóa" nghĩa là gì? Tony Hoare: “trừu tượng hóa xuất phát từ một cách nhìn nhận những đặc điểm tương đồng giữa một số đối tượng, tình thế, hoặc quy trình nhất định trong thế g

Trang 1

Nguyên lý thiết kế hướng đối tượng

Lập trình hướng đối tượng

Trang 2

Nguyên tắc số 1

Giảm thiểu khả năng truy nhập

tới lớp và các thành viên

Trang 3

"Trừu tượng hóa" nghĩa là gì?

 Tony Hoare: “trừu tượng hóa xuất phát từ một cách nhìn nhận

những đặc điểm tương đồng giữa một số đối tượng, tình thế, hoặc quy trình nhất định trong thế giới thực, và quyết định tập trung vào những điểm tương đồng này và nhất thời lờ đi các điểm khác biệt.”

 Grady Booch: “Một trừu tượng hóa kí hiệu các đặc điểm cốt lõi của một đối tượng mà các đặc điểm này phân biệt nó với tất cả các loại đối tượng khác, cho ta các ranh giới được xác định rõ ràng Tất cả được xét một cách tương đối trong góc nhìn của người quan sát.”

 Trừu tượng hóa là một trong những phương pháp nền tảng để đối phó với sự phức tạp

 Một trừu tượng hóa tập trung vào hình ảnh bên ngoài của một đối tượng và tách hành vi của đối tượng đó ra khỏi cài đặt của nó

Trang 5

Che dấu thông tin ở Java

 Sử dụng các thành viên private và các hàm đọc (get) và ghi (set) mỗi khi có thể

 Ví dụ:

 Thay thế

public double speed;

 bằng

private double speed;

public double getSpeed () { return speed;

} public double setSpeed (double newSpeed) { speed = …

Trang 6

Che dấu thông tin ở Java

 Ta có thể quy định các ràng buộc về giá trị

public void setSpeed(double newSpeed) {

 Nếu các client được truy cập trực tiếp đến thành viên dữ liệu thì

từng client phải chịu trách nhiệm kiểm tra ràng buộc

Trang 7

Che dấu thông tin ở Java

 Ta có thể thay đổi biểu diễn dữ liệu bên trong lớp đối

tượng mà không phải sửa giao diện

// Now using metric units (kph, not mph)

public void setSpeedInMPH(double newSpeed) {

Trang 8

Che dấu thông tin ở Java

public void setSpeed(double newSpeed) {

speed = newSpeed;

notifyObservers();

}

dữ liệu của mình, mỗi client sẽ phải chịu trách nhiệm chạy hiệu ứng phụ

Trang 9

Nguyên tắc số 2

Ưu tiên sử dụng Composition hơn

Inheritance

Trang 10

 Phương pháp tái sử dụng mà trong đó chức năng mới được xây dựng bằng cách tạo một đối tượng có thành phần là các đối tượng khác

 Chức năng mới được tạo bằng cách sử dụng chức năng của một trong các đối tượng thành phần

Trang 11

Ưu/nhược điểm của Composition

Trang 12

Ưu/nhược điểm của Composition

nhiều đối tượng hơn

thận để sử dụng nhiều đối tượng khác

nhau trong vai trò các khối cấu thành

Trang 13

Thừa kế

năng mới được xây dựng bằng cách mở rộng cài đặt của một đối tượng có sẵn

tường minh các thuộc tính và phương thức

chung

các thuộc tính và phương thức bổ sung

Trang 14

Ưu nhược điểm của thừa kế

Ưu điểm:

 Dễ dàng cài lớp mới, do phần lớn đã được thừa kế

 Dễ sửa hoặc mở rộng cài đặt được tái sử dụng

Nhược điểm

 Phá vỡ tính đóng gói, do nó để cho lớp con biết về chi tiết cài đặt của lớp cha

 Tái sử dụng kiểu "hộp trắng"

 Có thể phải sửa lớp con nếu cài đặt của lớp cha có thay đổi

 Tại thời gian chạy, không thể thay đổi cài đặt đã được thừa kế từ các lớp cha

Trang 15

Ví dụ Inheritance & Compostion

Ví dụ lấy từ cuốn Effective Java của Joshua Bloch.

Ta cần một dạng HashSet (tập hợp được cài bằng bảng băm) có chức năng lưu lại số lần chèn thêm phần tử Ta tạo lớp con của HashSet:

public class InstrumentedHashSet extends HashSet {

// The number of attempted element insertions

private int addCount = 0;

public InstrumentedHashSet(Collection c) {super(c);}

public InstrumentedHashSet(int initCap, float loadFactor) {

super(initCap, loadFactor);

}

Trang 16

public class InstrumentedHashSet extends HashSet {

// The number of attempted element insertions

private int addCount = 0;

public InstrumentedHashSet(Collection c) {super(c);}

public InstrumentedHashSet(int initCap, float loadFactor) {

public static void main(String[] args) {

InstrumentedHashSet s = new InstrumentedHashSet();

s.addAll(Arrays.asList(new String[] {"Snap","Crackle","Pop"})); System.out.println(s.getAddCount());

}

Trang 17

Ví dụ Inheritance & Compostion

HashSet gọi phương thức add()

 Tại add() của InstrumentedHashSet, ta cộng 3 vào addCount

 Gọi addAll() của HashSet, với mỗi phần tử, phương thức addAll() này lại gọi add() – bản định nghĩa lại của IntrumentedHashSet.

 Kết quả: mỗi phần tử bổ sung được đếm 2 lần

Trang 18

Ví dụ Inheritance & Compostion

 Có vài cách sửa, nhưng hãy ghi nhận điểm yếu của lớp con IntrumentedHashSet: chi tiết cài đặt của lớp cha ảnh hưởng tới hoạt động của lớp con

 Cách sửa tốt nhất: sử dụng composition.

 Viết lớp IntrumentedSet chứa một đối tượng Set

 Lớp này lặp lại interface Set, nhưng tất cả các thao tác tập hợp

sẽ được chuyển tới cho đối tượng Set chứa trong

IntrumentedSet

 IntrumentedSet được gọi là một lớp bọc ngoài (wrapper class),

nó bọc ra ngoài một đối tượng Set

 Đây là ví dụ về đại diện ủy quyền qua việc sử dụng composition

Trang 19

public class InstrumentedSet implements Set {

private final Set s;

private int addCount = 0;

public InstrumentedSet(Set s) {this.s = s;}

public boolean add(Object o) {

public int getAddCount() {return addCount;}

// Forwarding methods (the rest of the Set interface methods)

public void clear() { s.clear(); }

public boolean contains(Object o) { return s.contains(o); }

public boolean isEmpty() { return s.isEmpty(); }

public int size() { return s.size(); }

public Iterator iterator() { return s.iterator(); }

public boolean remove(Object o) { return s.remove(o); }

Trang 20

Ví dụ Inheritance & Compostion

 Một vài điểm cần lưu ý về InstrumentedSet :

 Lớp này là một Set

 Có một constructor có tham số là một Set

 Đối tượng Set nằm trong lớp có thể là một đối tượng thuộc bất

cứ lớp nào cài đặt interface Set (có thể không phải HashSet)

 Lớp này rất linh động và có thể bọc ra ngoài một đối tượng Set bất kì

 Ví dụ:

int capacity = 7;

float loadFactor = 66f;

Set s2 = new InstrumentedSet(new HashSet(capacity, loadFactor));

List list = new ArrayList();

Set s1 = new InstrumentedSet(new TreeSet(list));

Trang 21

Quy tắc Coad

Chỉ sử dụng thừa kế khi tất cả các tiêu chí sau đều được thỏa mãn:

 Lớp con "là một loại đặc biệt" chứ không phải "là một vai trò" của lớp cha

 Đối tượng của lớp con không bao giờ cần trở thành một đối tượng của một lớp khác

 Lớp con mở rộng, chứ không định nghĩa lại hoặc xóa bỏ, các trách nhiệm của lớp cha

 Lớp con không mở rộng khả năng của một lớp chỉ là lớp tiện ích

 Đối với một lớp trong ngữ cảnh thực của bài toán, lớp con chuyên biệt hóa một vai trò, giao tác, hoặc thiết bị

Trang 22

Ví dụ 1

Trang 23

Ví dụ 1

 "Là một loại đặc biệt" chứ

không phải "là một vai trò" của lớp cha.

Sai Passenger hay Agent đều là

các vai trò mà một người có thể giữ

 Không biến đổi

Sai Một người có thể lúc này là một passenger, lúc khác lại là agent

 Mở rộng chứ không định nghĩa lại hoặc xóa bỏ

Trang 24

Ví dụ 1 - Composition

Trang 25

Ví dụ 2 Inheritance/Composition

Trang 26

Ví dụ 1

 "Là một loại đặc biệt", không phải

"là một vai trò", của lớp cha

Đúng Passenger và Agent là

các dạng đặc biệt của PersonRole

 Không biến đổi

Đúng Một đối tượng passenger sẽ luôn là passenger, agent cũng vậy

 Mở rộng chứ không định nghĩa lại hoặc xóa bỏ

Trang 27

Ví dụ 3

Trang 28

Ví dụ 3

 "Là một loại đặc biệt", không phải

"là một vai trò", của lớp cha

Đúng Reservation và Purchase là các dạng giao tác (transaction)

 Không biến đổi

Đúng Một đối tượng Reservation sẽ luôn là Reservation, Purchase

Trang 29

Tóm tắt Inheritance/Composition

 composition và inheritance là các phương pháp tái sử dụng quan trọng

 Có thể làm cho các thiết kế phần mềm đơn giản hơn và có khả

năng tái sử dụng cao hơn bằng cách ưu tiên dùng composition

 Có thể dùng inheritance để mở rộng tập hợp các lớp có thể dùng làm thành phần cho composition

 Do đó, composition và inheritance có tính chất tương hỗ

 Nhưng nguyên tắc căn bản là:

Ưu tiên sử dụng Composition hơn Inheritance

Trang 30

Nguyên tắc số 3

Lập trình theo một giao diện,

không theo một cài đặt

Trang 31

 Một interface của một đối tượng là một tập các phương thức của đối tượng đó mà các đối tượng khác biết rằng chúng có thể kích hoạt

 Các đối tượng chỉ biết về nhau qua interface

 Một đối tượng có thể có nhiều interface

 về bản chất, mỗi interface là một tập con của tập tất cả các phương thức mà một đối tượng có cài

 Một kiểu (type) là một interface cụ thể

 Các đối tượng thuộc các lớp khác nhau có thể thuộc cùng một kiểu,

và một đối tượng có thể có nhiều kiểu khác nhau

 Interface là chìa khóa cho khả năng ghép nối (plugability)!

Trang 32

Ưu/nhược điểm của interface

 Ưu điểm:

 Client không biết về lớp cụ thể của đối tượng mà mình đang dùng

 Có thể dễ dàng thay thế đối tượng này vào chỗ của đối tượng khác

 Quan hệ giữa các đối tượng không cần phải được mã cứng cho một lớp cụ thể, từ đó tăng tính linh hoạt

 Giảm phụ thuộc lẫn nhau (coupling) giữa các thành phần hệ thống

 Tăng khả năng tái sử dụng

 Tăng cơ hội sử dụng composition do các đối tượng thành phần có thể thuộc bất cứ lớp nào cài đặt một interface cụ thể

 Nhược điểm

 Làm tăng nhẹ độ phức tạp của thiết kế

Trang 33

Ví dụ về interface "interface"

Expression

+ asString(): String + evaluate(): int

"interface"

BinaryExpression

+ left(): Expression + right(): Expression

Numeral

- int: value + Numeral(int) + Numeral()

Square

- Expression: expression + Square(Expression)

Addition

- Expression: left

- Expression: right

Trang 34

Ví dụ interface

 Lớp Addition có thể chứa các số hạng trái và phải mà không cần quan tâm chúng thực ra là đối tượng thuộc các lớp nào (Square, Numeral, Addition,…) hoặc nằm trong cây phân cấp thừa kế nào

class Addition implements BinaryExpression {

private Expression _left;

private Expression _right;

Addition (Expression l, Expression r)

{ _left = l; _right = r; }

public int evaluate()

{ return (_left.evaluate() + _right.evaluate() );}

}

Trang 36

Nguyên tắc Mở-đóng (OCP)

 Phát biểu: ta nên cố gắng thiết kế các mô-đun mà không bao giờ cần sửa

 Để mở rộng hành vi của hệ thống, ta bổ sung các đoạn trình mới, ta không sửa mã cũ.

 Các mô-đun thỏa mãn OCP cần đạt được 2 tiêu chí:

 Mở đối với mở rộng: mở rộng hành vi của mô-đun để thỏa mãn yêu cầu mới

 Đóng đối với sửa đổi: không được sửa mã nguồn của mô-đun

 Làm thế nào để thực hiện được nguyên tắc này?

 Trừu tượng hóa

 Đa hình

 Thừa kế

 Interface

Trang 37

Nguyên tắc Mở-đóng

thống phần mềm đều thỏa mãn OCP, nhưng ta nên cố giảm thiểu số mô-đun không thỏa mãn OCP

kế hướng đối tượng

nhất về tính tái sử dụng và khả năng bảo trì

Trang 38

Ví dụ

 Xét phương thức tính tổng giá tiền của một loạt phụ tùng:

public double totalPrice(Part[] parts) {

 Thỏa mãn nguyên tắc Mở-đóng

Trang 39

for (int i=0; i<parts.length; i++) {

if (parts[i] instanceof Motherboard)

Không thỏa mãn OCP!

Mỗi lần chính sách giá thay đổi là lại phải sửa nội dung totalPrice()

 Không đóng đối với sửa đổi

Trang 40

Ví dụ

public double totalPrice(Part[] parts) {

double total = 0.0;

for (int i=0; i<parts.length; i++) {

total += parts[i] getPrice();

}

return total;

}

 Để dùng phiên bản totalPrice() đầu tiên, ta

có thể kết hợp chính sách giá vào phương thức getPrice của một lớp Part

Trang 41

Ví dụ (tiếp)

 Ví dụ về các lớp Part và ConcretePart

// Class Part is the superclass for all parts.

public class Part {

private double price;

public Part(double price) (this.price = price;}

public void setPrice(double price) {this.price = price;}

public double getPrice() {return price;}

}

// Class ConcretePart implements a part for sale.

// Pricing policy explicit here!

public class ConcretePart extends Part {

public double getPrice() {

// return (1.45 * price); //Premium

return (0.90 * price); //Labor Day Sale

Nhưng giờ phải sửa từng lớp con của Part mỗi khi có thay đổi về chính sách giá.

Trang 42

Ví dụ (tiếp)

 Cách tốt hơn là tạo lớp Price Policy với nhiệm vụ cung cấp nhiều chính sách giá

// The Part class now has a contained PricePolicy object.

public class Part {

private double price;

private PricePolicy pricePolicy;

public void setPricePolicy(PricePolicy pricePolicy) {

this.pricePolicy = pricePolicy;

}

public void setPrice(double price) {this.price = price;}

public double getPrice() {

return pricePolicy.getPrice(price);

}

}

Trang 43

public class PricePolicy {

private double factor;

public PricePolicy (double factor) {

this.factor = factor;

}

public double getPrice(double price) {

return price * factor;

}

}

Trang 44

Nguyên tắc lựa chọn duy nhất

hệ quả của nguyên tắc Mở-đóng

Trang 45

Nguyên tắc số 5

Nguyên tắc thế Liskov:

Hàm nào dùng tham chiếu tới lớp cơ sở thì

phải có khả năng dùng nó cho đối tượng thuộc lớp dẫn xuất

mà không cần biết đến việc này

Trang 46

 Khi cài đặt các lớp dẫn xuất, cần cẩn trọng để đảm bảo không vô tình vi phạm nguyên tắc Liskov

Trang 47

Nguyên tắc thế Liskov

Liskov, có thể nó đã tham chiếu tường

minh đến một vài hoặc tất cả các lớp con của lớp cơ sở

Mở-đóng vì nó sẽ phải bị sửa đổi khi có một lớp con mới được tạo ra.

Trang 48

// A very nice Rectangle class.

public class Rectangle {

private double width;

private double height;

public Rectangle(double w, double h) {

width = w;

height = h;

}

public double getWidth() {return width;}

public double getHeight() {return height;}

public void setWidth(double w) {width = w;}

public void setHeight(double h) {height = h;}

public double area() {return (width * height);

}

Lớp Square (hình vuông) thì sao?

Hình vuông cũng là một hình chữ nhật.

Ví dụ

Trang 49

Ví dụ (tiếp)

 Hơi phí bộ nhớ nhưng không quan trọng lắm

phải được định nghĩa lại.

 Phải định nghĩa lại cả những phương thức đơn giản nhất??

 Có vẻ thừa kế ở đây không thích hợp lắm

Trang 50

// A Square class.

public class Square extends Rectangle {

public Square(double s) {super(s, s);}

public void setWidth(double w) {

Trang 51

public class TestRectangle {

// Define a method that takes a Rectangle reference.

public static void testLSP(Rectangle r) {

public static void main(String args[]) {

//Create a Rectangle and a Square

Rectangle r = new Rectangle(1.0, 1.0);

Square s = new Square(1.0);

testLSP(r);

testLSP(s);

Theo nguyên tắc thế Liskov, testLSP phải chạy ổn cho cả Rectangle và Square

Trang 53

Ví dụ (tiếp)

 Vấn đề ở đây là gì? Người viết testLSP() đã dùng giả thiết hợp lý rằng việc sửa chiều rộng hình chữ nhật không làm thay đổi chiều dài hình

 Truyền một đối tượng Square cho một phương thức như vậy đã

gây vấn đề, làm lộ diện một vi phạm đối với nguyên tắc LSP

 Các lớp Rectangle và Square trông có vẻ nhất quán và hợp lệ

Nhưng một giả thiết hợp lý của lập trình viên lại làm mô hình thiết kế

bị đổ vỡ

xét chúng trong các giả thiết hợp lý mà người sử dụng thiết kế có thể đưa ra

Trang 54

Ví dụ (tiếp)

một hình chữ nhật Nhưng một đối tượng

Square không phải là một đối tượng Rectangle

vì hành vi của một đối tượng Square không nhất quán với hành vi của một đối tượng Rectangle.

chữ nhật Không có tính đa hình giữa Square và Rectangle.

Trang 55

Nguyên tắc thế Liskov

 Nguyên tắc thế Liskov (LSP) nêu bật rằng quan hệ ISA (là) hoàn toàn là về hành vi

 Để nguyên tắc này được thỏa mãn (cùng với nó là

nguyên lý Mở-đóng) tất cả các lớp con phải tuân theo hành vi mà client trông đợi ở lớp cha.

 Một kiểu con không được có nhiều ràng buộc hơn kiểu cơ bản, nếu không, sẽ có trường hợp sử dụng mà lớp cha dùng được nhưng lớp con lại không dùng được

 Điều kiện đảm bảo nguyên tắc Liskov: bất cứ đâu dùng được lớp cha thì cũng dùng được lớp con.

Ngày đăng: 18/02/2014, 23:20

HÌNH ẢNH LIÊN QUAN

Hình vuông cũng là một hình chữ nhật. - Tài liệu NGUYÊN LÝ THIẾT KẾ HƯỚNG ĐÔI TƯỢNG - LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG doc
Hình vu ông cũng là một hình chữ nhật (Trang 48)

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w