2009-03-08 22 views
6

Trước khi giới thiệu về Generics với ngôn ngữ Java, tôi sẽ có các lớp văn bản đóng gói các bộ sưu tập-of-bộ sưu tập-of-bộ sưu tập. Ví dụ:Để sử dụng các bộ sưu tập chung được lồng nhau hoặc các lớp trung gian tùy chỉnh?

class Account { 
    private Map tradesByRegion; //KEY=Region, VALUE=TradeCollection 
} 

class TradeCollection { 
    private Map tradesByInstrument; //KEY=Instrument, Value=Trade 
} 

Tất nhiên, với Generics, tôi chỉ có thể làm:

class Account { 
    private Map<Region, Map<Instrument, Trade>> trades; 
} 

tôi có xu hướng đến nay lựa chọn tùy chọn # 2 (trên một phiên bản generified của tùy chọn # 1) vì điều này có nghĩa là tôi không kết thúc với sự gia tăng của các lớp tồn tại chỉ với mục đích gói một bộ sưu tập. Nhưng tôi có cảm giác dai dẳng rằng đây là thiết kế tồi (ví dụ: tôi nên sử dụng bao nhiêu bộ sưu tập lồng nhau trước khi khai báo các lớp mới). Ý kiến?

Trả lời

4

2 là tốt hơn bởi vì:

  • Ít mã thực hiện giống hiệu lực thi hành (tốt hơn, thực sự, như trong # 1 một số loại thông tin của bạn tồn tại chỉ trong ý kiến)
  • Đó là hoàn toàn rõ ràng những gì đi vào.
  • Lỗi loại của bạn sẽ bị bắt vào thời gian biên dịch.

Có gì để giới thiệu 1? Thừa nhận bản đồ < Integer, < Bản đồ < Chuỗi, < Bản đồ < ... Generics là một chút khó khăn để làm quen, nhưng với mắt tôi dễ hiểu hơn mã với bản đồ, danh sách bản đồ và bản đồ của danh sách bản đồ và các đối tượng tùy chỉnh đầy đủ các danh sách bản đồ.

+0

Tôi đã chỉnh sửa câu hỏi để thực hiện rõ ràng rằng một tùy chọn hậu Generics # 1 vẫn sẽ an toàn như tôi sẽ tham số Maps –

1

Tôi thích số 2. Nó là rõ ràng hơn những gì đang xảy ra, và là an toàn trong thời gian biên dịch (tôi thích có nhiều thứ sai trái trong thời gian biên dịch càng tốt, trái ngược với việc chúng xảy ra trong thời gian chạy ... nói chung tôi thích nó khi không có gì sai) .

Edit:

Vâng có hai cách mà tôi có thể nhìn thấy ... Tôi đoán nó phụ thuộc vào bạn sẽ sử dụng:

class Account 
{ 
    private Map<Region, TradeCollection> tradesByRegion; 
} 

class TradeCollection 
{ 
    private Map<Instrument, Trade> tradesByInstrument; 
} 

hoặc

class Account<R extends Region, I extends Instrument, T extends Trade, C extends TradeCollection<I, T>> 
{ 
    private Map<R, C> tradesByRegion; 
} 

class TradeCollection<I extends Instrument, T extends Trade> 
{ 
    private Map<I, T> tradesByInstrument; 
} 
+0

Tất nhiên; nhưng tôi có thể làm cho loại an toàn số 1 bằng cách bao gồm generics. Tôi sẽ sửa câu hỏi của tôi –

+0

Tôi bắt đầu nói điều đó. nhưng tôi đã làm cho nó chung chung tôi vết thương với cơ bản cùng một mã ... Tôi sẽ thử lại và xem những gì tôi nhận được – TofuBeer

2

Tôi đã thực hiện quy tắc đơn giản này cho tôi: Không bao giờ nhiều hơn hai < và hai dấu phẩy trong khai báo chung và tốt hơn là chỉ một dấu phẩy. Sau đó tôi giới thiệu các loại tùy chỉnh. Tôi nghĩ đây là điểm mà khả năng đọc đủ để đảm bảo các khái niệm bổ sung.

Có một lý do thực sự tốt để tránh generics quá sâu: Sự phức tạp không chỉ trong khai báo thực tế mà thường có xu hướng hiển thị như nhau trong logic xây dựng. Vì vậy, rất nhiều mã có xu hướng trở nên phức tạp nếu bạn lồng các khai báo này quá sâu. Tạo các lớp trung gian có thể giúp ích rất nhiều. Bí quyết thường là tìm ra các lớp trung gian thích hợp.

Tôi chắc chắn bạn nên quay trở lại một chút về tiêu chuẩn cũ của mình. Trên thực tế mẫu thứ hai của bạn là điểm đau chính xác, nơi tôi vẫn chấp nhận generics-only.

+0

Tôi sẽ không cho bạn thấy generics của tôi sau đó (tôi có một trong đó bao gồm khoảng 10 dòng để giữ cho nó có thể đọc được :-) – TofuBeer

+0

@TofuBeer Tốt hơn không nên làm điều đó. Đó là mã chỉ viết trong thế giới của tôi :) – krosenvold

+0

Tất nhiên, một vấn đề với # 1 là bạn sẽ hỏi rất nhiều câu hỏi như "TradeCollection một lần nữa là gì?" - Đó là, bạn cần phải duyệt mã nhiều hơn nữa từ lớp Tài khoản để hiểu cấu trúc của bộ sưu tập thực sự là –

2

Thông thường cũng sẽ có một số mã để hoạt động trên các bộ sưu tập. Khi điều này trở nên không thuận lợi, tôi gộp lại bộ sưu tập với hành vi trong một lớp mới. Càng làm tổ càng sâu thì càng có nhiều khả năng xảy ra trường hợp này.

4

Kết hợp cả hai. Trong khi bạn có thể sử dụng Generics để thay thế các lớp tùy chỉnh, bạn vẫn sẽ muốn sử dụng một lớp để đóng gói các khái niệm của bạn. Nếu bạn chỉ cần chuyển các bản đồ của bản đồ các bản đồ của danh sách cho tất cả mọi thứ, những người kiểm soát những gì bạn có thể thêm? người kiểm soát những gì bạn có thể xóa?

Để giữ dữ liệu, generics là một điều tuyệt vời. Nhưng bạn vẫn muốn các phương thức xác thực khi bạn thêm một giao dịch, hoặc thêm một tài khoản, và không có một loại lớp nào đó bao gồm các bộ sưu tập của bạn, không ai kiểm soát điều đó.

+0

Tôi chắc chắn đồng ý: Tôi nghĩ rằng các bộ sưu tập là một chi tiết triển khai và tôi không chuyển chúng vào hoặc hiển thị chúng trong API công khai –

2

Tôi nghĩ tốt hơn là nên lưu ý đến các đối tượng và nhấn mạnh các bộ sưu tập ít hơn một chút. Cải cách là bạn của bạn.

Ví dụ: đối tượng Sinh viên và Khóa học là điều tự nhiên nếu bạn đang lập mô hình hệ thống cho trường học. Điểm số sẽ được ghi ở đâu? Tôi cho rằng họ thuộc về một đối tượng mà Sinh viên và Khóa học gặp nhau - một ReportCard. Tôi sẽ không có điểm số lớp. Cung cấp cho nó một số hành vi thực sự.

+0

I đồng ý: ReportCard vs GradeCollection là một ví dụ rất hay về lựa chọn thiết kế tốt trong cuốn sách của tôi. – javashlook

1

Tôi nghĩ câu trả lời cho điều này là nó phụ thuộc vào tình huống. Nói chung, việc giới thiệu loại là hữu ích nếu điều đó cũng giới thiệu các phương pháp liên quan đến loại, nếu các loại trung gian đó được truyền độc lập, v.v.

Bạn có thể tìm thấy lời khuyên này từ Rich Hickey (tác giả của Clojure) về việc tạo thư viện tương thích loại thú vị:

Nó dự định như là lời khuyên cụ thể cho các nhà văn thư viện Clojure nhưng tôi nghĩ là thực phẩm thú vị cho các tư tưởng ngay cả trong Java.

Các vấn đề liên quan