Không có sự khác biệt giữa các đối tượng; bạn có một HashMap<String, Object>
trong cả hai trường hợp. Có một sự khác biệt trong giao diện bạn có đối tượng. Trong trường hợp đầu tiên, giao diện là HashMap<String, Object>
, trong khi đó trong giao diện thứ hai Map<String, Object>
. Nhưng đối tượng cơ bản là như nhau.
Lợi thế của việc sử dụng Map<String, Object>
là bạn có thể thay đổi đối tượng cơ bản thành một loại bản đồ khác mà không phá vỡ hợp đồng của bạn với bất kỳ mã nào sử dụng nó. Nếu bạn tuyên bố nó là HashMap<String, Object>
, bạn phải thay đổi hợp đồng nếu bạn muốn thay đổi việc thực hiện cơ bản.
Ví dụ: Giả sử tôi viết lớp này:
class Foo {
private HashMap<String, Object> things;
private HashMap<String, Object> moreThings;
protected HashMap<String, Object> getThings() {
return this.things;
}
protected HashMap<String, Object> getMoreThings() {
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Lớp này có một vài bản đồ bên trong của chuỗi-> đối tượng mà nó chia sẻ (thông qua các phương thức truy cập) với các lớp con. Hãy nói rằng tôi viết nó bằng HashMap
s để bắt đầu bởi vì tôi nghĩ đó là cấu trúc phù hợp để sử dụng khi viết lớp.
Sau đó, Mary viết mã phân lớp nó. Cô ấy có một cái gì đó cô ấy cần phải làm với cả hai things
và moreThings
, vì vậy, tự nhiên cô ấy đặt nó trong một phương thức chung, và cô ấy sử dụng cùng loại tôi đã sử dụng getThings
/ getMoreThings
khi xác định phương pháp của mình:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Sau đó, tôi quyết định rằng thực sự, sẽ tốt hơn nếu tôi sử dụng TreeMap
thay vì HashMap
vào Foo
. Tôi cập nhật Foo
, đổi HashMap
thành TreeMap
. Bây giờ, SpecialFoo
không biên dịch nữa, vì tôi đã phá vỡ hợp đồng: Foo
được sử dụng để nói nó cung cấp HashMap
s, nhưng bây giờ nó cung cấp TreeMaps
thay thế. Vì vậy, chúng tôi phải sửa chữa SpecialFoo
ngay bây giờ (và loại điều này có thể gợn qua một cơ sở mã).
Trừ khi tôi có một lý do thực sự tốt để chia sẻ rằng việc triển khai của tôi đang sử dụng một HashMap
(và điều đó xảy ra), những gì tôi nên làm là tuyên bố getThings
và getMoreThings
như chỉ trở lại Map<String, Object>
mà không cụ thể hơn điều đó. Trong thực tế, việc cấm một lý do chính đáng để làm một việc khác, ngay cả trong Foo
tôi có lẽ nên khai báo things
và moreThings
như Map
, không HashMap
/ TreeMap
:
class Foo {
private Map<String, Object> things; // <== Changed
private Map<String, Object> moreThings; // <== Changed
protected Map<String, Object> getThings() { // <== Changed
return this.things;
}
protected Map<String, Object> getMoreThings() { // <== Changed
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Lưu ý cách tôi hiện đang sử dụng Map<String, Object>
ở mọi nơi tôi có thể, chỉ cụ thể khi tôi tạo các đối tượng thực tế.
Nếu tôi đã làm điều đó, thì Mary sẽ làm điều này:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
... và thay đổi Foo
sẽ không SpecialFoo
ngừng biên dịch.
Các giao diện (và các lớp cơ sở) cho phép chúng tôi chỉ tiết lộ càng nhiều càng cần thiết , giữ cho sự linh hoạt của chúng tôi dưới vỏ bọc để thay đổi khi thích hợp. Nói chung, chúng tôi muốn có các tài liệu tham khảo của chúng tôi là cơ bản nhất có thể. Nếu chúng ta không cần biết nó là một HashMap
, chỉ cần gọi nó là a Map
.
Đây không phải là một quy tắc mù quáng, nhưng nói chung, mã hóa cho giao diện chung nhất sẽ ít giòn hơn so với mã hóa thành một cái gì đó cụ thể hơn. Nếu tôi nhớ điều đó, tôi sẽ không tạo ra một Foo
Mary khiến tôi thất bại SpecialFoo
. Nếu Mary đã nhớ điều đó, thì mặc dù tôi đã nhắn tin Foo
, nhưng cô ấy đã tuyên bố phương thức riêng tư của mình Map
thay vì HashMap
và Foo
hợp đồng thay đổi của tôi sẽ không ảnh hưởng đến mã của cô ấy.
Đôi khi bạn không thể làm điều đó, đôi khi bạn phải cụ thể. Nhưng trừ khi bạn có một lý do, lỗi về giao diện ít cụ thể nhất.