Có phải là quá mức để bọc một bộ sưu tập trong một lớp đơn giản chỉ vì mục đích dễ đọc hơn?


15

Tôi có bản đồ sau:

Map<Double, List<SoundEvent>> soundEventCells = new HashMap<Double, List<SoundEvent>>();

Điều này HashMapánh xạ doublecác giá trị (là các điểm theo thời gian) vào SoundEvent'ô' tương ứng : mỗi 'ô' có thể chứa một số SoundEvents. Đó là lý do tại sao nó được thực hiện như một List<SoundEvent>, bởi vì đó chính xác là những gì nó được.

Để dễ đọc mã hơn, tôi đã nghĩ đến việc triển khai một lớp bên trong tĩnh rất đơn giản như vậy:

private static class SoundEventCell {
    private List<SoundEvent> soundEvents = new ArrayList<SoundEvent>();
    public void addEvent(SoundEvent event){
        soundEvents.add(event);
    }
    public int getSize(){
        return soundEvents.size();
    }
    public SoundEvent getEvent(int index){
        return soundEvents.get(index);
    }
    // .. remove() method unneeded
}

Và hơn là khai báo bản đồ (và rất nhiều mã khác) sẽ trông tốt hơn, ví dụ:

Map<Double, SoundEventCell> soundEventCells = new HashMap<Double, SoundEventCell>();

Đây có phải là quá mức cần thiết? Bạn sẽ làm điều này trong các dự án của bạn?


người ta có thể lập luận rằng về mặt khái niệm, điều này đã được giải quyết trong Làm thế nào bạn biết nếu bạn đã viết mã dễ đọc và dễ bảo trì? Nếu đồng nghiệp của bạn cứ phàn nàn về cách làm việc của bạn, dù bằng cách này hay cách khác, bạn nên thay đổi để khiến họ cảm thấy tốt hơn
gnat

1
Điều gì làm cho danh sách các sự kiện âm thanh trở thành một "tế bào" chứ không phải là một danh sách? Liệu sự lựa chọn từ này có nghĩa là một tế bào có hoặc cuối cùng sẽ có hành vi khác với một danh sách?
x-code

@DocBrown Tại sao? Lớp này là private staticbởi vì nó sẽ chỉ được sử dụng bởi lớp bên ngoài, nhưng nó không liên quan đến bất kỳ trường hợp cụ thể nào của lớp bên ngoài. Đó không phải là chính xác cách sử dụng đúng private statickhông?
Aviv Cohn

2
@Doc Brown, Aviv Cohn: Không có thẻ chỉ định bất kỳ ngôn ngữ nào, vì vậy mọi thứ đều có thể đúng và sai cùng một lúc!
Emilio Garavaglia

@EmilioGaravaglia: Java (Tôi nghĩ nó khá rõ ràng vì đánh giá theo cú pháp nó có thể là Java hoặc C # và các quy ước được sử dụng thu hẹp nó thành Java;)).
Aviv Cohn

Câu trả lời:


12

Nó không quá mức cần thiết. Bắt đầu với các thao tác bạn cần, thay vì bắt đầu bằng "Tôi có thể sử dụng HashMap". Đôi khi một HashMap chỉ là những gì bạn cần.
Trong trường hợp của bạn, tôi nghi ngờ là không. Những gì bạn có thể muốn làm là một cái gì đó như thế này:

public class EventsByTime {
    public EventsByTime addEvent(double time, SoundEvent e);
    public List<SoundEvent> getEvents(double time);
    // ... more methods specific to your use ...
}

Bạn chắc chắn không muốn có một loạt mã nói điều này:

List<SoundEvent> events = eventMap.get(time);
if (events == null) {
   events = new ArrayList<SoundEvent>();
   eventMap.put(time, events);
}

Hoặc có lẽ bạn chỉ có thể sử dụng một trong các triển khai Guava Multimap .


Vì vậy, bạn ủng hộ việc sử dụng một lớp, về cơ bản là một cơ chế che giấu thông tin, như là một ... cơ chế che giấu thông tin? Kinh dị.
Robert Harvey

1
Trên thực tế, tôi có một TimeLinelớp chính xác cho loại điều đó :) Đó là một lớp bọc mỏng xung quanh một HashMap<Double, SoundEventCell>(cuối cùng tôi đã đi với ý tưởng SoundEventCellthay vì List<SoundEvent>). Vì vậy, tôi chỉ có thể làm timeline.addEvent(4.5, new SoundEvent(..))và có các công cụ cấp thấp hơn được gói gọn :)
Aviv Cohn

14

Mặc dù nó có thể hỗ trợ khả năng đọc ở một số khu vực, nhưng nó cũng có thể làm phức tạp mọi thứ. Cá nhân tôi tránh xa việc gói hoặc mở rộng các bộ sưu tập vì mục đích lưu loát, vì trình bao bọc mới, khi đọc ban đầu, ngụ ý với tôi rằng có thể có hành vi tôi cần phải biết. Hãy coi đó là một sắc thái của Nguyên tắc bất ngờ tối thiểu.

Bám sát với việc thực hiện giao diện có nghĩa là tôi chỉ cần lo lắng về giao diện. Tất nhiên, việc triển khai cụ thể có thể là hành vi bổ sung, nhưng tôi không cần phải lo lắng về điều đó. Vì vậy, khi tôi đang cố gắng tìm đường đi qua mã của ai đó, tôi thích các giao diện đơn giản để dễ đọc hơn.

Mặt khác, nếu bạn đang tìm một trường hợp sử dụng lợi từ hành vi được thêm vào, thì bạn có một đối số để cải thiện mã bằng cách tạo một lớp đầy đủ.


11
Một trình bao bọc cũng có thể được sử dụng để loại bỏ (hoặc ẩn) hành vi không cần thiết.
Roman Reiner

4
@RomanReiner - Tôi thận trọng trước những điều như vậy. Hành vi không cần thiết ngày hôm nay thường là lập trình viên chửi rủa tên bạn vào ngày mai. Mọi người đều biết những gì a Listcó thể làm, và nó làm tất cả những điều đó vì một lý do tốt.
Telastyn

Tôi đánh giá cao mong muốn duy trì chức năng, mặc dù tôi nghĩ giải pháp là sự cân bằng cẩn thận giữa chức năng và sự trừu tượng. SoundEventCellcó thể triển khai Iterablecho SoundEvents, sẽ cung cấp trình lặp của soundEventsthành viên, vì vậy bạn có thể đọc (nhưng không viết) như bất kỳ danh sách nào. Tôi ngần ngại che giấu sự phức tạp gần như nhiều khi tôi ngần ngại sử dụng Listkhi tôi có thể cần một cái gì đó năng động hơn trong tương lai.
Neil

2

Việc gói nó giới hạn chức năng của bạn chỉ với những phương thức bạn quyết định viết, về cơ bản là tăng mã của bạn không có lợi. Ít nhất, tôi sẽ thử như sau:

private static class SoundEventCell : List<SoundEvent>
{
}

Bạn vẫn có thể viết mã từ ví dụ của bạn.

Map<Double, SoundEventCell> soundEventCells = new HashMap<Double, SoundEventCell>();

Điều đó nói rằng, tôi chỉ từng làm điều này khi có một số chức năng mà danh sách cần. Nhưng tôi nghĩ rằng phương pháp của bạn sẽ quá mức cho việc này. Trừ khi bạn có lý do để muốn giới hạn quyền truy cập vào hầu hết các phương thức của Danh sách.


-1

Một giải pháp khác có thể là định nghĩa lớp trình bao bọc của bạn bằng một phương thức duy nhất hiển thị danh sách:

private static class SoundEventCell
{
    private List<SoundEvent> events;

    public SoundEventCell(List<SoundEvent> events)
    {
        this.events = events;
    }

    public List<SoundEvent> getEvents()
    {
        return events;
    }
}

Điều này cung cấp cho bạn lớp được đặt tên tốt của bạn với mã tối thiểu, nhưng vẫn cung cấp cho bạn đóng gói, cho phép bạn ví dụ làm cho lớp không thay đổi (bằng cách thực hiện một bản sao phòng thủ trong hàm tạo và sử dụng Collections.unmodifiableListtrong trình truy cập).

(Tuy nhiên, nếu các danh sách này thực sự chỉ được sử dụng trong lớp này, tôi nghĩ rằng bạn nên thay thế Map<Double, List<SoundEvent>>bằng Multimap<Double, SoundEvent>( tài liệu ) của mình, vì điều đó thường giúp tiết kiệm rất nhiều logic và lỗi kiểm tra null.)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.