You are on page 1of 61

HFOOAD Chương 1

Một ứng dụng đơn giản


Chúng ta xây dựng phần mềm để giải quyết vấn đề.
Mọi người có những vấn đề.

Do đó, chúng ta xây dựng phần mềm cho mọi người.


Phần mềm tốt không chỉ giải quyết các vấn đề trước
mắt mà còn có thể được duy trì và sửa đổi để giải
quyết những thay đổi không thể tránh khỏi mà khách
hàng sẽ muốn.

2
Rick’s Guitars
‣ Duy trì kho guitar
‣ Xác định vị trí guitar cho khách hàng

3
What your predecessor built

Điều này có ý nghĩa gì với bạn không?

4
Chế độ xem đơn giản hóa

5
Nhưng có một vấn đề…
Tôi đang tìm Guitar của Rick
kiếm một
chắn bùn Strat.
Phòng sau
Không có
trong kho

6
But there’s a problem…
I’m looking Rick’s Guitars
for a
fender Strat.
Back Room
Not in
stock.

fender ≠ Fender

7
The Guitar class
public class Guitar {

private String serialNumber, builder, model, type, backWood, topWood;


private double price;

public Guitar(String serialNumber, double price,


String builder, String model, String type,
String backWood, String topWood) {
this.serialNumber = serialNumber;
this.price = price;
this.builder = builder;
this.model = model;
this.type = type;
this.backWood = backWood;
this.topWood = topWood;
}
public String getSerialNumber() {return serialNumber;}
public double getPrice() {return price;}
public void setPrice(float newPrice) {
this.price = newPrice;
}
public String getBuilder() {return builder;}
public String getModel() {return model;}
public String getType() {return type;}
public String getBackWood() {return backWood;}
public String getTopWood() {return topWood;}
}

8
The Inventory class
public class Inventory {
private List guitars;
public Inventory() { guitars = new LinkedList(); }
public void addGuitar(String serialNumber, double price,
String builder, String model,
String type, String backWood, String topWood) {
Guitar guitar = new Guitar(serialNumber, price, builder,
model, type, backWood, topWood);
guitars.add(guitar);
}
public Guitar getGuitar(String serialNumber) {
for (Iterator i = guitars.iterator(); i.hasNext(); ) {
Guitar guitar = (Guitar)i.next();
if (guitar.getSerialNumber().equals(serialNumber)) {
return guitar;
}
}
return null;
}

9
The Inventory class continued
public Guitar search(Guitar searchGuitar) {
for (Iterator i = guitars.iterator(); i.hasNext(); ) {
Guitar guitar = (Guitar)i.next();
String builder = searchGuitar.getBuilder().toLowerCase();
if ((builder != null) && (!builder.equals("")) &&
(!builder.equals(guitar.getBuilder().toLowerCase())))
continue;
String model = searchGuitar.getModel().toLowerCase();
if ((model != null) && (!model.equals("")) &&
(!model.equals(guitar.getModel().toLowerCase())))
continue;
String type = searchGuitar.getType().toLowerCase();
if ((type != null) && (!searchGuitar.equals("")) &&
(!type.equals(guitar.getType().toLowerCase())))
continue;
String backWood = searchGuitar.getBackWood().toLowerCase();
if ((backWood != null) && (!backWood.equals("")) &&
(!backWood.equals(guitar.getBackWood().toLowerCase())))
continue;
String topWood = searchGuitar.getTopWood().toLowerCase();
if ((topWood != null) && (!topWood.equals("")) &&
(!topWood.equals(guitar.getTopWood().toLowerCase())))
continue;
return guitar;
}
return null;
}
}

1
Bạn có thể làm gì?

1
Bạn có thể làm gì?

1 So sánh trường hợp vô cảm của nhà sản xuất

2 So sánh chuỗi không phân biệt chữ hoa chữ thường

3 Sử dụng hằng số cho các nhà sản xuất khác nhau

4 Nói chuyện với Rick và nhận thông tin chi tiết về vấn đê

1
Ba bước để có phần mềm tốt

1. Đảm bảo phần mềm thực hiện


những gì khách hàng muốn

2. Áp dụng các nguyên tắc


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

3. Phấn đấu cho một thiết kế có


thể duy trì, tái sử dụng

1
Bước 1: Nói chuyện với Rick

Bạn sẽ hỏi Rick những câu hỏi


nào?

1
Câu hỏi cho Rick

1
Câu hỏi cho Rick

1 Bạn chỉ bán guitar?

2 Bạn sẽ cập nhật hàng tồn kho như thế nào?


Tìm kiếm một cây đàn guitar thực sự nên hoạt động như thế nào?
3

4 Bạn có cần báo cáo về hàng tồn kho và bán hàng không?

1
Rick says

Khách hàng không phải


lúc nào cũng biết tất cả
Thường có nhiều hơn một
các đặc điểm của cây
cây đàn guitar phù hợp
đàn guitar mà họ muốn.
nhu cầu của khách hàng.

Khách hàng thường tìm kiếm


một Tôi cần báo cáo và các
Guitar với một mức giá cụ báo cáo khác
thể Khả năng trong My
phạm vi hàng tồn kho, nhưng # 1
của tôi
Vấn đề là tìm kiếm
Guitar phù hợp với khách
hàng.

1
Danh sách việc cần làm:
1. Nếu có những cây đàn guitar trong
kho phù hợp với nhu cầu của khách
hàng, hãy luôn tìm thấy chúng.
2. Hãy tính đến lỗi đánh máy của khách
hàng hoặc làm cho nó không thể nhập
dữ liệu sai.

1
Lặp lại 1: Loại bỏ chuỗi
public class Guitar {

private String serialNumber,


model;
private double price;
private Builder builder;
private Type type;
private Wood backWood, topWood;

public enum Type {

ACOUSTIC, ELECTRIC;

public String toString() {


switch(this) {
case ACOUSTIC: return "acoustic";
case ELECTRIC: return "electric";
default: return "unspecified";
}
}
}

1
Triển khai enum tốt hơn

public enum Type {


ACOUSTIC("acoustic"),
ELECTRIC("electric"),
UNSPECIFIED("unspecified");
String value;
private Type(String value)
{
this.value = value;
}
public String toString() {
return value;
}
}

2
Tác động của những thay đổi của
chúng ta
1

Chúng ta có thể phải làm gì khác với ứng dụng


của mình?

2
Tác động của những thay đổi của
chúng ta

1 Thay đổi mã và biểu mẫu nhập dữ liệu

2 Cập nhật cơ sở dữ liệu hàng tồn kho

3 …

2
Rick says

Khách hàng không phải Thường có nhiều hơn


lúc nào cũng biết tất cả Một cây đàn guitar phù
các đặc điểm của cây hợp
đàn guitar mà họ muốn. nhu cầu của khách hàng.

Tôi cần báo cáo và các báo


cáo khác
Khách hàng thường tìm Khả năng trong My
kiếm một hàng tồn kho, nhưng # 1 của
Guitar với m tôi
Vấn đề là tìm kiếm
Guitar phù hợp với khách
hàng.

2
Danh sách việc cần làm:
1. Nếu có những cây đàn guitar trong
kho phù hợp với nhu cầu của khách
hàng, hãy luôn tìm thấy chúng.
2. Hãy tính đến lỗi đánh máy của khách
hàng hoặc làm cho nó không thể nhập
dữ liệu sai.
3. Tìm TẤT CẢ các cây đàn guitar phù
hợp.

2
Tạo sao không
phải là danh sách
Chúng tôi có thể Gutar
trả lại một
mảng Guitar.

Nó có thực sự quan
trọng?

2
Giải pháp từ sách giáo khoa
public List search(Guitar searchGuitar) {
List matchingGuitars = new LinkedList();
for (Iterator i = guitars.iterator(); i.hasNext(); ) {
Guitar guitar = (Guitar)i.next();
// Ignore serial number since that's unique
// Ignore price since that's unique
if (searchGuitar.getBuilder() != guitar.getBuilder())
continue;
String model = searchGuitar.getModel().toLowerCase();
if ((model != null) && (!model.equals("")) &&
(!model.equals(guitar.getModel().toLowerCase())))
continue;
if (searchGuitar.getType() != guitar.getType())
continue;
if (searchGuitar.getBackWood() != guitar.getBackWood())
continue;
if (searchGuitar.getTopWood() != guitar.getTopWood())
continue;
matchingGuitars.add(guitar);
}
return matchingGuitars;
}

2
Giải pháp thay thế
public Iterator<Guitar> search(Guitar searchGuitar) {
List<Guitar> matchingGuitars = new LinkedList<Guitar>();
for (Iterator<Guitar> i = guitars.iterator(); i.hasNext(); ) {
Guitar guitar = i.next();
// Ignore serial number since that's unique
// Ignore price since that's unique
if (searchGuitar.getBuilder() != guitar.getBuilder())
continue;
String model = searchGuitar.getModel().toLowerCase();
if ((model != null) && (!model.equals("")) &&
(!model.equals(guitar.getModel().toLowerCase())))
continue;
if (searchGuitar.getType() != guitar.getType())
continue;
if (searchGuitar.getBackWood() != guitar.getBackWood())
continue;
if (searchGuitar.getTopWood() != guitar.getTopWood())
continue;
matchingGuitars.add(guitar);
}
return matchingGuitars.iterator();
}
}

2
Vẫn còn điều gì đó sai
Tôi nghĩ bạn đã có lựa chọn guitar Gibson
tốt nhất trong tiểu bang. Tôi thực sự muốn
một cái nhưng hệ thống kiểm kê bị tổn
thương não của bạn nói rằng bạn không có
bất kỳ Gibson nào.
Tôi chỉ muốn một Gibson. Tôi không quan
tâm nó có điện hay không và tôi không quan
tâm đến loại gỗ. Và bạn không có bất cứ thứ
gì như thế trong kho! Đây là loại cửa hàng
âm nhạc nào?

2
Rick không vui

Tôi nghĩ bạn đã sửa lỗi này.


Tôi có rất nhiều Gibsons. Tôi
trả tiền cho bạn để làm gì?

2
Có lẽ thực sự có
không có trong kho.
Tại sao không
Gibsons xuất
hiện?

Những gì đã làm
khách hàng
vào?

3
Vẫn còn điều gì đó sai nha
Tôi vừa nhập "Gibson" và để
trống mọi thứ khác. Đúng vậy,
phải không?

3
Ba bước để có phần mềm tuyệt

1. Đảm bảo phần mềm thực hiện


những gì khách hàng muốn
2. Áp dụng các nguyên tắc
hướng đối tượng tốt
3. Phấn đấu cho một thiết kế có
thể duy trì, tái sử dụng

Phần mềm có làm những gì


khách hàng muốn không?

Vấn đề là gì?

3
Những điều có thể sai

3
Những điều có thể sai

1 Không phải tất cả các thuộc tính đều có liên quan

2 Không có giá trị ký tự đại diện


Không có cách nào để chọn nhiều hơn một giá trị cho một
3 thuộc tính

4 …

3
Bạn biết đấy, khi khách hàng tìm
kiếm một cây đàn guitar, họ đang
cung cấp một tập hợp các đặc
điểm mà họ đang tìm kiếm,
không phải là một cây đàn guitar
cụ thể. Có lẽ đó là vấn đề.

3
GuitarSpec không phải là Guitar
Tôi không phải là 1
Guitar.

GuitarSpec Guitar

3
Chúng ta có thể sử dụng UML để
hiển thị điều này

3
Thay đổi gia tăng
public class GuitarSpec {

private Builder builder;


private String model;
private Type type;
private Wood backWood;
private Wood topWood;

public GuitarSpec(Builder builder, String model, Type type,


Wood backWood, Wood topWood) {
this.builder = builder;
this.model = model;
this.type = type;
this.backWood = backWood;
this.topWood = topWood;
}

public Builder getBuilder() {


return builder;
}…

3
Thay đổi gia tăng (2)
public class Guitar {

private String serialNumber;


private double price;
GuitarSpec spec;

public Guitar(String serialNumber, double price,


Builder builder, String model, Type type,
Wood backWood, Wood topWood) {
this.serialNumber = serialNumber;
this.price = price;
this.spec = new GuitarSpec(builder, model, type, backWood, topWood);
}

public GuitarSpec getSpec() {


return spec;
}
}

3
Có gì trong một cái tên?

GuitarSpec có phải là một cái tên hay cho lớp


mới không?

Những cái tên khác có thể phù hợp?


Tốt hơn hay tệ hơn?

4
Điều này có ý nghĩa không?

4
Những thứ có thể sai

1 Không phải tất cả các thuộc tính đều có liên quan

2 Không có giá trị ký tự đại diện


Không có cách nào để chọn nhiều hơn một giá trị cho
3 một thuộc tính

4 …

Những thay đổi chúng tôi vừa thực hiện


có giúp ích không?

4
Ba bước để có phần mềm tốt

1. Đảm bảo phần mềm thực hiện


những gì khách hàng muốn
2. Áp dụng các nguyên tắc
hướng đối tượng tốt
3. Phấn đấu cho một thiết kế có
thể duy trì, tái sử dụng

Chúng tôi đã áp dụng những


nguyên tắc nào?

Còn có cái nào nữa không


Bạn nghĩ đến điều đó?

4
Một từ về gia tăng & lặp lại
‣ Phát triển lặp đi lặp lại
Lặp đi lặp lại các bước trong quá trình phát triển
Các lần lặp ngắn hơn sẽ tốt hơn
‣ Phát triển gia tăng
Thêm một chút tại một thời điểm
Không có vụ nổ lớn

Goa
l

Start

4
Rất nhiều khách hàng đang tìm kiếm
guitar 12 dây. Có lẽ chúng ta nên thêm
điều đó vào đặc điểm của guitar mà
chúng ta thu âm.

According to the
contract, that’s not
what you asked for.

4
Chúng ta có thể thêm số lượng
chuỗi. Nó không phải là một
vấn đề.

4
Bạn cần thay đổi điều gì?

4
Bạn cần thay đổi điều gì?

1 GuitarSpec

2 Hảng tồn Kho

4
Thay đổi đối với GuitarSpec
public class GuitarSpec {

private Builder builder;


private String model;
private Type type;
private int numStrings;
private Wood backWood;
private Wood topWood;

public GuitarSpec(Builder builder, String model, Type type,


int numStrings, Wood backWood, Wood topWood) {
this.builder = builder;
this.model = model;
this.type = type;
this.numStrings = numStrings;
this.backWood = backWood;
this.topWood = topWood;
}

public int getNumStrings() {


return numStrings;
}

}

4
Thay đổi đối với Kho
public Iterator<Guitar> search(GuitarSpec searchSpec) {
List<Guitar> matchingGuitars = new LinkedList<Guitar>();
for (Iterator<Guitar> i = guitars.iterator(); i.hasNext(); ) {
Guitar guitar = i.next();
GuitarSpec spec = guitar.getSpec();
if (searchSpec.getBuilder() != spec.getBuilder())
continue;
String model = searchSpec.getModel().toLowerCase();
if ((model != null) && (!model.equals("")) &&
(!model.equals(spec.getModel().toLowerCase())))
continue;
if (searchSpec.getType() != spec.getType())
continue;
if (searchSpec.getBackWood() != spec.getBackWood())
continue;
if (searchSpec.getTopWood() != spec.getTopWood())
continue;
if (searchSpec.getNumStrings() != spec.getNumStrings())
continue;
matchingGuitars.add(guitar);
}
return matchingGuitars.iterator();
}

5
Mát. Đó chỉ là những gì tôi
muốn. Em là người tuyệt
vời nhất. Lần sau bạn lại có
công việc kinh doanh của
tôi.

5
Ba bước để được phần mềm tốt

1. Đảm bảo phần mềm thực hiện


những gì khách hàng muốn
2. Áp dụng các nguyên tắc
hướng đối tượng tốt
3. Phấn đấu cho một thiết kế có
thể duy trì, tái sử dụng

Điều đó không quá


khó!

5
Chúng ta có thể làm tốt hơn?
Tại sao chúng tôi
phải sửa đổi hai tệp
để thực hiện thay
đổi?

5
Có thể chúng tôi đã phân bổ trách
nhiệm không chính xác. Có một
mô hình gọi là Chuyên gia thông
tin có thể thích hợp ở đây.

Thiết kế O-O là tất cả về


việc phân công trách nhiệm
cho các đối tượng trong hệ
thống của chúng tôi.

5
Chuyên gia thông tin

Phân công trách nhiệm cho lớp có thông tin


cần thiết — chuyên gia thông tin.

Craig Larman, “Applying UML and Patterns”

5
Hãy suy nghĩ về điều này?

Hành vi nào bị đặt sai chỗ?

Ai là chuyên gia thông tin?

Chúng ta nên làm cái gì?

5
Hãy suy nghĩ về điều này?

Hành vi nào bị đặt sai chỗ?


Phù hợp với cây đàn guitar với đặc điểm kỹ thuật

Ai là chuyên gia thông tin?


GuitarSpec

Chúng ta nên làm cái gì?


Làm cho GuitarSpec hợp lý để xác định

nếu nó phù hợp với một cây đàn guitar.

5
The new GuitarSpec class
public class GuitarSpec {

public boolean matches(GuitarSpec otherSpec) {
if (builder != otherSpec.builder)
return false;
if ((model != null) && (!model.equals("")) &&
(!model.toLowerCase().equals(otherSpec.model.toLowerCase())))
return false;
if (type != otherSpec.type)
return false;
if (numStrings != otherSpec.numStrings)
return false;
if (backWood != otherSpec.backWood)
return false;
if (topWood != otherSpec.topWood)
return false;
return true;
}

}

Trời ạ, cái này nhìn có vẻ quen


quen!

5
The new Inventory class
Public class Inventory {

public List search(GuitarSpec searchSpec) {
List matchingGuitars = new LinkedList();
for (Iterator i = guitars.iterator(); i.hasNext(); ) {
Guitar guitar = (Guitar)i.next();
if (guitar.getSpec().matches(searchSpec))
matchingGuitars.add(guitar);
}
return matchingGuitars;
}

}

5
Congratulations!
‣ Bạn vừa thực hiện tái cấu trúc đầu tiên của
mình
‣ Bạn đã làm cho khách hàng hài lòng
‣ Bạn đã áp dụng các nguyên tắc O-O vững
chắc
‣ Bạn có một ứng dụng có thể duy trì
‣ Bạn đã tạo ra phần mềm tuyệt vời, phải
không?

Đi ra ngoài và ăn mừng tại quán cà phê

6
Bạn có nghĩ rằng chúng tôi
có thể đã phá vỡ một cái gì
đó khi chúng tôi thực hiện
những thay đổi cuối cùng đó
không?

Làm thế nào bạn có thể


chắc chắn?

You might also like