2013-05-19 29 views
5

Tôi chắc chắn điều này phải được yêu cầu trước nhưng tôi dường như không thể tìm thấy một ví dụ tương tự. Tôi hiểu rõ tính đa hình và phương pháp quá tải, nhưng đây là một kịch bản dường như đơn giản với một giải pháp thoát khỏi tôi:xử lý giống đa hình các tham số - OO đơn giản?

giả sử tôi có một lớp cơ sở với một số lớp dẫn xuất. Tôi sẽ sử dụng hình dạng ví dụ này

base Shape 
derived Circle extends Shape 
derived LineSeg extends Shape 

, vv

Bây giờ, hình dáng có một phương pháp gọi là giao nhau (khác) rằng các xét nghiệm đối với hình dạng khác để xem nếu họ giao nhau. Với tính đa hình, dễ dàng thấy cách Circle, LineSeg, v.v. có thể thực hiện các phương thức "giao nhau" của riêng chúng, và với quá tải phương thức, tôi có thể dễ dàng thực hiện tất cả các kết hợp cần thiết. ví dụ,

Circle.intersect(LineSeg) 
Circle.intersect(Circle) 
LineSeg.intersect(Circle) 

, vv

cho đến nay rất tốt.

vấn đề là, nếu tôi giữ một danh sách trung tâm của hình dạng, tôi muốn làm điều này:

for some shape s 
Foreach shape in Shapes 
    if (s.intersect(shape)) - do something 

Hiện nay, tôi không chắc chắn cách này là có thể, kể từ khi phương pháp quá tải chọn "giao nhau" để phù hợp với loại hình cơ sở, và không phải là kiểu tham số thích hợp. Làm thế nào tôi có thể thực hiện điều này mà không có một chuỗi nếu-else kiểm tra các loại và xuống đúc?

BTW, tôi đang sử dụng Java, nhưng tôi không chắc chắn rằng ngôn ngữ là hoàn toàn có liên quan vì nó có vẻ là một câu hỏi thiết kế cơ bản. Dường như đơn giản, tôi đang thiếu gì?

Cảm ơn!


Giải quyết bên dưới (Cảm ơn!), Xem chi tiết ở đó. Về cơ bản, bằng cách gọi lại trong các lớp dẫn xuất, sau đó gọi phương thức thích hợp (mẫu khách truy cập?), Bạn có thể sử dụng từ khóa "này" để gọi phương thức giao nhau thích hợp, vì nó có kiểu thích hợp cần thiết.

+1

Một số ngôn ngữ lập trình hỗ trợ quá tải trực tiếp trên các loại đối số.Ví dụ, LISP hỗ trợ * multimethods *, và tôi cho rằng một số ngôn ngữ lập trình hàm hỗ trợ giống nhau. Trong Java, điều này thường được gọi là * double dispatch *, và mô hình GoF Visitor là con đường để đi. –

+1

Không để nitpick thiết kế của bạn nhưng thừa kế của bạn là một chút sai. Phân đoạn đường không thực sự là hình dạng. Chúng tạo nên hình dạng. Bạn sẽ kiểm tra giao điểm của bất kỳ một trong nhiều, tùy thuộc vào hình dạng, các đoạn thẳng tạo thành hai hình dạng được đề cập :) – ChiefTwoPencils

+0

@ C.Lang, bắt tốt, nhưng nếu tôi đổi tên lineSeg thành "wall" thì sao? thats về cơ bản nó được sử dụng như thế nào, nhưng gọi nó là lineSeg làm cho việc khái niệm hóa dễ dàng hơn bằng cách sử dụng nó theo các hình dạng phức tạp hơn – user1922401

Trả lời

3

Suy nghĩ đầu tiên của tôi là mẫu khách truy cập, khá nhiều cho mỗi hình dạng hai phương pháp, tôi sẽ gọi intersect(Shape) và một phương pháp doIntersect() cho mỗi loại hình dạng.

Nó sẽ trông như thế này về:

interface Shape { 
    public abstract Intersection intersect(Shape other); 

    public abstract Intersection doIntersect(Circle circle); 

    public abstract Intersection doIntersect(LineSeg line); 
} 
class LineSeg implements Shape { 
    @Override 
    public Intersection intersect(Shape other) { 
     return other.doIntersect(this); 
    } 

    Intersection doIntersect(Circle circle) { 
     // Code to intersect with Circle 
    } 

    Intersection doIntersect(LineSeg other) { 
     // Code to intersect with another Lineseg 
    } 
} 

class Circle implements Shape { 
    @Override 
    public Intersection intersect(Shape other) { 
     return other.doIntersect(this); 
    } 

    public Intersection doIntersect(Circle other) { 
     // Code to intersect with another Circle 
    } 

    public Intersection doIntersect(LineSeg segment) { 
     // Code to intersect with LineSeg 
    } 
} 

Bạn có thể muốn các phương pháp doIntersect được gói tin hoặc chọn tên gọi khác nhau hơn so với những mặc dù.

+0

Điều này thật tuyệt vời, cảm ơn. Đã khắc phục sự cố của tôi một cách nhanh chóng và dễ dàng. Tôi cần phải thêm tất cả các khả năng kiểu tham số làm nguyên mẫu trong lớp cơ sở, buộc trẻ phải xử lý bất kỳ khả năng nào. – user1922401

+0

Một sàng lọc bổ sung: Bạn có thể đặt tên cho tất cả các phương thức 'intersect()' thay vì đặt tên cho các phương thức 'doIntersect()' cụ thể. Theo như tôi biết trình biên dịch chọn quá tải cụ thể nhất phù hợp với đầu tiên. – confusopoly

+0

Cảm ơn - Tôi đã làm điều đó, nhưng quyết định để lại đề xuất của bạn vì nó có thể ít gây nhầm lẫn. Tôi cũng đã cố gắng đặt nó trong lớp cơ sở để chỉ có một là bắt buộc, nhưng sử dụng "this" trong một phương thức lớp cơ sở có kiểu lớp cơ sở, không may (tôi thấy tại sao, mặc dù) – user1922401

0

Xem Generics Jdk5

Đối với mỗi hình dạng trong Shapes <>

0

lớp hình dạng của bạn phải là một lớp trừu tượng, có nghĩa là nó không nhận được khởi tạo, chỉ có vòng tròn các lớp thừa kế và lineseg có trường hợp. Phương pháp giao nhau phải là hình dạng ảo để khi bạn lặp qua tất cả các hình dạng, phương pháp giao nhau của từng hình dạng được gọi là

public abstract class Shape { 

    boolean intersect(Shape s); 
} 

public class Circle extends Shape { 

    boolean intersect(Shape s) { 
     ... 
     if(s instanceOf Circle) { 
      .... // Circle intersects cicrcle 
     } else if(s instanceOf Lineseg) { 
      .... // Circle intersects Lneseg 
     } else { 
      throw RuntimeException("Unrecognized shape"); 
     } 

    } 

} 

public class Lineseg extends Shape { 

    boolean intersect(Shape s) { 
     ... 
     if(s instanceOf Circle) { 
      .... // Lineseg intersects circle 
     } else if(s instanceOf Lineseg) { 
      .... // Lineseg intersects lineseg 
     } else { 
      throw RuntimeException("Unrecognized shape"); 
     } 
    } 

} 
+0

Xin lỗi, tôi đã yêu cầu một câu trả lời mà không cần nếu if-else chuỗi kiểm tra kiểu – user1922401

+0

@ user1922401 Nhưng bạn sẵn sàng viết một phương thức cho mỗi lớp dẫn xuất trong mỗi lớp dẫn xuất, giống nhau. Chỉ có cách này là cách OO cổ điển để xử lý đa hình. – ilomambo

+0

nó không giống nhau, như thông qua mô hình khách truy cập, bạn chỉ có thêm một hướng dẫn. Với chuỗi if-else, bạn có lúc kiểm tra tệ nhất n mỗi khi bạn gọi phương thức. Hơn nữa, giải pháp được đề xuất là an toàn hơn một chút. Nếu tôi thêm một kiểu mới, tôi phải thêm tiêu đề giao nhau đã nhập vào lớp cơ sở hoặc nó sẽ không biên dịch, và nó buộc tất cả các kiểu hình dạng khác xử lý nó - trong giải pháp của bạn, tôi có thể quên nó một cách vô tình. Mặc dù bạn đề xuất có một if-else trong mỗi lớp, điều này có thể được tập trung – user1922401

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