Thay thế cho Java của Java?


10

Vì vậy, tôi khá mới để lập trình trong thế giới thực (bên ngoài các dự án học thuật) và đã bắt gặp rất nhiều bài đăng nói rằng sử dụng instanceoflà một điều xấu để sử dụng để xác định một đối tượng cụ thể là lớp nào.

Tình huống của tôi là tôi có ba lớp, một lớp sản phẩm cơ sở, một lớp mở rộng lớp đó và lớp khác kéo dài ra. Tất cả đều được lưu trữ trong cùng một bảng trong cơ sở dữ liệu và tôi có một số mã cần sử dụng các phương thức trên mỗi bảng để lấy dữ liệu khỏi chúng.

Thực hành tốt nhất để có được xung quanh cách làm này là gì? Tôi đã đọc một số điều về đa hình nhưng tôi không thể tìm thấy bất kỳ ví dụ nào khắc phục vấn đề tôi gặp phải. Tất cả chúng thường ghi đè lên một phương thức mà đối với tôi sẽ không hoạt động vì tôi cần phải kéo những thứ khác nhau từ các đối tượng khác nhau.

Có cách nào tốt hơn để làm điều này hay tôi bị mắc kẹt với việc sử dụng instanceofhoặc một số loại phản xạ để có được các trường cụ thể cho các đối tượng?


10
Không phải là từ khóa instanceofsai; cố gắng tìm lớp của một đối tượng thường là vấn đề. Không phải lúc nào cũng sai, nhưng có lẽ trong trường hợp của bạn là như vậy. Có thể nếu bạn cho chúng tôi biết những gì bạn đang cố gắng thực hiện, chúng tôi có thể đề xuất một giải pháp bằng cách sử dụng đa hình.
Andres F.

2
Được rồi, mỗi lớp có dữ liệu cụ thể cho nó. Tôi muốn lấy dữ liệu cụ thể từ những thứ này. Tôi nghĩ rằng tôi đã nhận ra câu trả lời với sự giúp đỡ tôi đã có. Một cái gì đó giống như một phương thức được gọi getSpecifics()là được triển khai khác nhau trên mỗi phương thức, với mỗi phương thức trả về dữ liệu cụ thể cho lớp?
Thomas Mitchell

Câu trả lời:


16

Lý do instanceofkhông được khuyến khích là nó không phải là OOP.

Không nên có lý do nào để người gọi / người dùng của một đối tượng biết lớp cụ thể nào là một thể hiện của loại biến được khai báo là loại nào.

Nếu bạn cần hành vi khác nhau trong các lớp con thêm một phương thức và thực hiện chúng khác nhau.


1
Vì vậy, một phương thức getSpecifics()(hoặc một cái gì đó tương tự) trên mỗi lớp sẽ trả về các chi tiết cụ thể cho từng lớp. Đây có phải là cách tiếp cận tốt nhất?
Thomas Mitchell

@Schmooo Bạn thực sự cần phải suy nghĩ về nơi chức năng chung tồn tại trong cây lớp và những hợp đồng tồn tại ở mỗi cấp.

3
Nhưng những gì về một trường hợp khi đối tượng của bạn chéo lớp và thông tin loại bị mất? Ví dụ tôi tạo a List. Tôi chuyển nó cho một đối tượng mà bất kỳ Iterable. Bây giờ đối tượng thứ hai chuyển nó đến một đối tượng thứ ba Listđể tối ưu hóa hoặc Iterablechậm hơn nhiều. Cái thứ hai không nên biết rằng đó là một danh sách, nhưng cái thứ ba rất muốn biết. Không nên kiểm tra đối tượng thứ ba cho thể hiện để xem liệu nó có thể áp dụng tối ưu hóa không? Xem ví dụ ổi FluentIterablechỉ làm điều đó.
Laurent Bourgault-Roy

1
Tôi muốn nói rằng không phải lúc nào bạn cũng phải thêm phương thức vào lớp. Ví dụ, một số mã có một ngoại lệ và được cho là làm một cái gì đó với nó tùy thuộc vào loại của nó. Nói, làm một báo cáo hoặc làm một cái gì đó để phục hồi từ lỗi. Loại chức năng này chắc chắn không phù hợp với ngoại lệ. Hoặc, nếu các lớp đến từ một số thư viện bên ngoài, thì bạn thậm chí không có phương tiện để sửa đổi các lớp này. Trong trường hợp này tôi nghĩ rằng nó hoàn toàn hợp lệ để dựa vào instanceof.
Malcolm

9

instanceof không hẳn là một điều xấu, tuy nhiên đó là điều mà người ta nên nhìn vào.

Một ví dụ về nơi nó hoạt động chính xác là ở một nơi mà người ta có được một bộ sưu tập các loại cơ sở và bạn chỉ muốn các kiểu của một kiểu con. Lấy địa chỉ mạng từ NetworkInterface.getNetworkInterfaces()trả về các đối tượng NetworkInterface có bộ sưu tập các đối tượng InetAddress, một số trong đó là Inet4Address và một số là Inet6Address. Nếu một người muốn lọc bộ sưu tập cho các đối tượng Inet4Address, thì cần phải sử dụng instanceof.

Trong tình huống đang được mô tả trong bài viết gốc, có một lớp Cơ sở, một cái gì đó mở rộng lớp cơ sở đó và một cái gì đó mở rộng lớp mở rộng. Trong khi không hoàn toàn thông tin, điều này dường như có nền tảng của một số ít hơn thiết kế lý tưởng.

Khi bạn trả về một lớp cơ sở trừ khi có lý do chính đáng để nó được thiết kế theo cách đó (khả năng tương thích ngược giữa các thông số kỹ thuật của phiên bản trước), bạn không nên cố gắng nhìn trộm các loại bên dưới. Nếu bạn được trả lại một Bộ, bạn biết bạn đang nhận được một bộ. Nó cho phép nhà phát triển sau đó thay đổi ý định của mình để trả về một loại cụ thể hơn (Sắp xếp) hoặc thay đổi loại cơ bản (Hashset thành Treeset) mà không phá vỡ bất cứ điều gì.

Xem xét lại thiết kế của bạn về cách các đối tượng được cấu trúc và phát minh để xem liệu người ta có thể tạo ra một mô hình lớp tốt hơn không yêu cầu phân biệt các loại.


Có thể việc giao diện chỉ định một isOfType(SomeEnum.IPv4)phương thức có thể là một cách tốt hơn để lọc các phẩm chất đó hơn là kiểm tra loại cụ thể thông qua instanceof. Điều gì sẽ xảy ra nếu bạn muốn tách lớp triển khai IPv4 của mình sau này? Không phải điều này luôn tốt hơn, nhưng đó là một sự cân nhắc.
Steven Schlansker

@StevenSchlansker Điều đó có thể làm việc cho lớp cụ thể đó. Nhưng điều gì sẽ xảy ra nếu người ta cần kiểm tra loại bê tông để xem liệu có thể đúc được không (hoặc người ta chỉ đúc và bắt ngoại lệ?) Inet6Address thực hiện nhiều phương thức hơn InetAddress. Nó sẽ khó làm việc với các giao diện (một enum liệt kê mọi lớp trong gói? Hoặc trình nạp lớp?) Và điều đó có nghĩa là phương thức sẽ cần được thực hiện bằng tay (hoặc một số mã phản chiếu trong Object). Xem xét làm thế nào để làm (o instanceof Serializable) || (o instanceof Externalizable). instanceof tốt hơn so với giải pháp thay thế

1

Bạn có thể sử dụng phương thức getClass ().

Bạn có chắc bạn cần ba lớp khác nhau? Có lẽ một lớp với một chuyển đổi bên trong sẽ phục vụ tốt hơn?


7
getClassinstanceofchia sẻ nhược điểm. Đa hình tốt hơn cả khi nó phù hợp và tôi không thấy nó không phù hợp với trường hợp sử dụng của OP.

Tôi không có gì chống lại câu đầu tiên của bạn. Nhưng điều thứ hai - xin lỗi, tôi không thể hiểu ý của bạn là gì cả.
Gangnus

1
Với getClasstôi vẫn không chia sẻ vấn đề tương tự như sử dụng instanceof? Tôi vẫn sẽ phải tìm ra những gì tôi có và sau đó gọi một bộ chức năng. Lý tưởng nhất là tôi muốn một phương thức trả về dữ liệu cụ thể cho lớp đó mà không cần truyền vào đối tượng đó.
Thomas Mitchell

Tôi phàn nàn về việc bạn bỏ qua Đa hình, vì nó thường là một lựa chọn tốt hơn. Tôi khá chắc chắn rằng trường hợp sử dụng trong câu hỏi có thể được thực hiện với đa hình, vì vậy tôi không thấy sự cần thiết phải sử dụng. (Ngoài ra, chỉ cần sao chép câu trả lời của người khác là không hay.)

2
@Gangus Tôi không nghĩ đây là một "cuộc tấn công", ý tôi là không có ý xúc phạm. Nhưng sao cũng được. Không, câu hỏi không phải là "những gì khác có thể được sử dụng", đó là "có cách nào tốt hơn để làm điều này". Trừ khi bạn muốn tranh luận getClasslà một cách tốt hơn để làm điều đó, không có doanh nghiệp nào chiếm phần lớn câu trả lời ;-)

1

Thông thường khi tôi thấy mình muốn biết loại của một cái gì đó có nghĩa là tôi đã thực hiện cấu trúc đối tượng của mình sai. Hầu hết những lần này đều vi phạm LSP .

Tuy nhiên, đôi khi tôi muốn có một cách để thực hiện công văn động và tiết kiệm một tấn mã tấm nồi hơi và tương lai cấu trúc đối tượng của tôi. C # cung cấp từ khóa động trong các phần mới hơn của khung công tác nhưng theo tôi biết Java vẫn không có gì tương tự.

Điều đó nói rằng, instanceof thường tốt hơn so với việc so sánh các lớp vì nó sẽ hỗ trợ kế thừa đúng cách. Bạn cũng có thể sử dụng các phương thức như isAssignableFrom và các phương thức khác từ API phản xạ. Nếu bạn muốn triển khai một cái gì đó như công văn động, nó có thể được thực hiện thông qua API phản chiếu nhưng hãy cẩn thận, nó sẽ bị chậm. Sử dụng một cách thận trọng, lý tưởng nhất là bạn nên sửa cấu trúc đối tượng và mong muốn ứng dụng của mình nếu có thể.

Hi vọng điêu nay co ich

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.