Có một sự thay thế cho thể hiện khi lọc một luồng Java theo lớp không?


8

Tôi có một tình huống bất ngờ trong một dự án trong đó tất cả các kiểu mở rộng một lớp được đóng gói vào một bộ sưu tập Java; nhưng chỉ một phần mở rộng cụ thể của lớp đó chứa một phương thức bổ sung. Hãy gọi nó là "cũng ()"; và để tôi nói rõ rằng không có phần mở rộng nào khác có nó. Ngay trước khi thực hiện một nhiệm vụ trên mỗi mục trong bộ sưu tập đó, tôi cũng cần gọi () trên mỗi mục thực hiện nó.

Cách dễ nhất về phía trước là đây:

stuff.stream().filter(item -> item instanceof SpecificItem)
            .forEach(item -> ((SpecificItem)item).also()));
stuff.stream().forEach(item -> item.method());

Nó hoạt động tốt, nhưng tôi không thoải mái với "instanceof" trong đó. Đó thường là một dấu hiệu của mùi mã xấu. Rất có khả năng tôi sẽ cấu trúc lại lớp này chỉ để loại bỏ nó. Tuy nhiên, trước khi tôi làm điều gì đó ấn tượng, tôi nghĩ rằng tôi sẽ kiểm tra với cộng đồng và xem liệu ai đó có nhiều kinh nghiệm hơn với Luồng hoặc Bộ sưu tập có giải pháp đơn giản hơn không.

Như một ví dụ (chắc chắn không có kết luận), có thể có được chế độ xem bộ sưu tập lọc các mục theo lớp không?


2
Nếu bạn cần lọc SpecificItemvà đây là cách thích hợp để xác định vị ngữ, vậy tại sao bạn lại lúng túng về sự instanceoftồn tại ở đó?
Robert Harvey

Các đối tượng trong luồng có triển khai một số giao diện chung cho phép bạn phân biệt giữa các lớp không? Một số .getKind()hay .isSpecific()?
9000

@ 9000 Thật không may, và tôi tin rằng việc thêm một thứ như vậy sẽ làm nó lộn xộn hơn một chút.
Michael Eric Oberlin

8
Có một lý do mà SpecificItemviệc triển khai không chỉ gọi also()trước sau đó?
Tristan Burnside

1
@ LuísGuilherme Iterablekhông có stream()phương pháp, nhưng bạn có thể gọi forEach()trực tiếp trên Iterable.
shmosel

Câu trả lời:


3

Tôi khuyên .mapbạn nên thực hiện một cuộc gọi để thực hiện vai diễn cho bạn. Sau đó, mã sau này của bạn có thể sử dụng 'thực tế'.

Trước:

stuff.stream().filter(item -> item instanceof SpecificItem)
            .forEach(item -> ((SpecificItem)item).also()));

Sau:

stuff.stream().filter(item -> item instanceof SpecificItem)
            .map(item -> (SpecificItem)item)
            .forEach(specificItem -> specificItem.also()));

Điều này không hoàn hảo, nhưng dường như làm sạch mọi thứ một chút.


Sở thích của tôi là loại bỏ càng nhiều càng tốt khỏi mã công việc, và bạn nói đúng, bản đồ có ý nghĩa chính xác cho điều đó.
Michael Eric Oberlin

Nhiều chức năng hơn: stuff.stream().filter(item -> item instanceof SpecificItem).map(SpecificItem.class::cast).forEach(SpecificItem::also);
strickli

3

Tôi có một tình huống bất ngờ trong một dự án trong đó tất cả các kiểu mở rộng một lớp được đóng gói vào một bộ sưu tập Java; nhưng chỉ một phần mở rộng của lớp đó thực hiện một phương thức. Hãy gọi nó là "cũng ()". Ngay trước khi thực hiện một nhiệm vụ trên mỗi mục trong bộ sưu tập đó, tôi cũng cần gọi () trên mỗi mục thực hiện nó.

Đó rõ ràng là một thiết kế bị lỗi. Từ những gì bạn đã viết, nó không rõ ràng, có nghĩa là gì, rằng một lớp không thực hiện phương thức. Nếu nó chỉ đơn giản là không làm , nó sẽ không thành vấn đề, vì vậy tôi cho rằng có một tác dụng phụ không mong muốn.

Nó hoạt động tốt, nhưng tôi không thoải mái với "instanceof" trong đó.

Ruột của bạn là đúng Thiết kế hướng đối tượng tốt sẽ hoạt động mà không cần biết thêm chính xác đối tượng là gì, cho dù đó là một thể hiện của một loại đặc biệt.

Tuy nhiên, trước khi tôi làm điều gì đó ấn tượng, tôi nghĩ rằng tôi sẽ kiểm tra với cộng đồng và xem liệu ai đó có nhiều kinh nghiệm hơn với Luồng hoặc Bộ sưu tập có giải pháp đơn giản hơn không.

Tái cấu trúc là không kịch tính. Nó cải thiện chất lượng mã.

Với cơ sở mã đã cho của bạn, giải pháp đơn giản nhất là, để đảm bảo, bạn có hai bộ sưu tập riêng biệt, một với cha mẹ và một với lớp con. Nhưng điều đó không hoàn toàn sạch sẽ.


Tôi đã chỉnh sửa câu hỏi của mình để cụ thể hơn. Để làm rõ hơn, đây là một công việc crack cho một sự thay đổi cần thiết ngay lập tức; một phần mở rộng của lớp phải được tính đến. Về tái cấu trúc, hãy nói rằng đó là một phần thiết yếu của việc trở thành một lập trình viên. Tuy nhiên, tôi đang tìm kiếm bộ tái cấu trúc ít kịch tính nhất có thể.
Michael Eric Oberlin

Đối với câu hỏi của bạn, có một câu trả lời rõ ràng: nếu bộ lọc cần biết, với trường hợp nào nó phải xử lý, thì không có cách nào khác (ngoại trừ một loại phép thuật phản chiếu kỳ lạ, đó là một cách hỏi khó hiểu hơn ví dụ ). Nhưng thời gian bạn tiết kiệm ngay bây giờ cho một giải pháp nhanh chóng và bẩn thỉu được sử dụng sau này trong vòng đời sản phẩm gấp đôi để sửa lỗi do thiết kế xấu.
Thomas Junk

@MichaelEricOberlin: Vì vậy, nếu tôi nghe Thomas chính xác, các lựa chọn của bạn dường như là: thay đổi thiết kế hoặc để nguyên như vậy.
Robert Harvey

@RobertHarvey đặt nó theo cách này, nghe có vẻ tự nhiên;) nếu anh ta không muốn tái cấu trúc, không còn lựa chọn nào khác ngoài việc đi xuống con đường hiện tại.
Thomas Junk

2

Thật khó để đưa ra khuyến nghị cụ thể mà không biết những gì SpecificItemalso()thực sự là gì, nhưng:

Xác định also()trên siêu lớp của SpecificItem. Cung cấp cho nó một triển khai mặc định mà không làm gì cả (cung cấp cho nó một thân phương thức trống). Các lớp con riêng lẻ có thể ghi đè lên nó nếu muốn. Tùy thuộc vào những gì alsothực sự là, bạn có thể cần phải đổi tên nó thành một cái gì đó có ý nghĩa cho tất cả các lớp liên quan.


Điều đó khá hợp lý và cuối cùng tôi có thể tái cấu trúc để làm điều đó.
Michael Eric Oberlin

1

một thay thế:

  1. làm cho Cụ thể thực hiện một giao diện (nói "Có thể lọc")
  2. tạo một lớp mới mở rộng Stream
  3. tạo phương thức 'bộ lọc' mới chấp nhận đối tượng triển khai giao diện của bạn
  4. ghi đè phương thức luồng ban đầu và chuyển hướng nó đến triển khai của bạn (bằng cách chuyển tham số vị ngữ sang giao diện của bạn)

theo cách đó, chỉ những đối tượng triển khai giao diện của bạn mới có thể truyền các chủ đề cho phương thức của bạn ... không cần sử dụng thể hiện

public class MyStream extends Stream
{
    //...

    Stream<Filterable> filter(Predicate<? implements Filterable> predicate)
    {
         return super.filter(predicate);
    }
}

3
Đó không phải là cách: cải thiện thiết kế xấu bằng cách làm cho nó tồi tệ hơn.
Thomas Junk

Tôi phải đồng ý với Thomas Junk ở đây. Bước ba về cơ bản làm những gì tôi đã làm; và không sử dụng lại thể hiện, tôi không biết phương thức của bạn sẽ giải quyết vấn đề này như thế nào.
Michael Eric Oberlin

1
@MichaelEricOberlin: Đây chính xác là điều tôi lo lắng; tạo ra một Rube Goldberg chỉ để thỏa mãn ý tưởng về "cách thực hành tốt nhất" của ai đó.
Robert Harvey

1

Tôi hy vọng tôi không bỏ lỡ bất cứ điều gì rõ ràng ở đây (cũng như được đề xuất bởi nhận xét của @Tristan Burnside ), nhưng tại sao không thể SpecificItem.method()gọi also()trước?

public class SpecificItem extends Item {
    ...
    public void method() {
        also();
        super.method();
    }
}

Như một ví dụ (chắc chắn không có kết luận), có thể có được chế độ xem bộ sưu tập lọc các mục theo lớp không?

Một cách truyền phát mà tôi có thể nghĩ ra, với chi phí có thể là một số tác động hiệu suất (YMMV), là collect() thông qua Collectors.groupingBy()lớp làm khóa, sau đó chọn kết quả bạn muốn từ kết quả Map. Các giá trị được lưu trữ dưới dạng a List, vì vậy nếu bạn muốn thực hiện lọc như vậy trên a Setvà bạn hy vọng sẽ lọc được Setnó, thì bạn cũng sẽ cần một bước bổ sung để tiếp tục đưa các giá trị vào kết quả Set.


-1

Đây là cách tiếp cận của tôi:

stuff.stream().filter(item -> SpecificItem.class.isInstance(item)).map(item  -> SpecificItem.class.cast(item)).forEach(item -> item.also());
stuff.stream().forEach(item -> item.method());

Không có thể hiện , không có phôi rõ ràng (thực ra nó là một biểu mẫu rõ ràng, nhưng bị che bởi một lệnh gọi phương thức). Tôi nghĩ rằng điều này là tốt như nó có thể nhận được.


1
Đây không phải là một phiên bản ít đọc hơn của bản gốc sao?
grahamparks

Vâng, nó thực sự làm điều tương tự theo một cách an toàn. Nó có thể đơn giản hơn tùy thuộc vào ngữ cảnh của mã. Tôi sử dụng điều này để lọc một số loại nhất định trong danh sách chung, ngoại trừ phần forEach.
beto
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.