Giả sử chúng ta có giao diện đồ chơi sau:Java thực hành tốt nhất: đúc tượng vs giao diện
interface Speakable
{
public abstract void Speak();
}
interface Flyer
{
public abstract void Fly();
}
và chúng tôi có lớp mà thực hiện cả hai giao diện:
class Duck implements Speakable, Flyer
{
public void Speak()
{
System.out.println("quack quack don't eat me I taste bad.");
}
public void Fly()
{
System.out.println("I am flying");
}
}
Tại thời điểm này tôi thấy nhiều cách khác nhau để gọi các phương thức trên Duck
và tôi không thể quyết định phương pháp nào là phương pháp hay nhất. Hãy xem xét kịch bản này:
public class Lab
{
private static void DangerousSpeakAndFly(Object x)
{
Speakable temp = (Speakable) x;
temp.Speak();
Flyer temp2= (Flyer) x;
temp2.Fly();
}
public static void main(String[] args)
{
Duck daffy= new Duck();
DangerousSpeakAndFly(daffy);
}
}
Chương trình này sẽ cư xử như mong đợi, bởi vì đối tượng được truyền vào chức năng sẽ xảy ra là cast để Flyer
và Speakable
, nhưng tôi co rúm người lại khi tôi nhìn thấy mã như thế này vì nó không cho phép biên dịch kiểm tra kiểu thời gian và do khớp nối chặt chẽ nó có thể ném ngoại lệ bất ngờ ví dụ khi một đối tượng được nhập khác (không thể chuyển sang một trong hai hoặc một trong các giao diện) được chuyển thành tham số hoặc nếu thực hiện Duck
thay đổi xuống dòng. thực hiện dài hơn Flyer
.
Tôi thấy mã Java được viết như thế này mọi lúc, đôi khi trong sách giáo khoa (ví dụ: pg. 300 của "Mẫu thiết kế đầu tiên" bởi O'Reilly) vì vậy phải có một bằng khen trong đó tôi thiếu.
Nếu tôi viết mã tương tự, tôi sẽ cố gắng tránh downcasting sang một loại hoặc giao diện không được bảo đảm. ví dụ trong trường hợp này tôi sẽ làm một cái gì đó như thế này:
interface SpeakingFlyer extends Flyer, Speakable
{
}
class BuzzLightyear implements SpeakingFlyer
{
public void Speak()
{
System.out.println("My name is Buzz");
}
public void Fly()
{
System.out.println("To infinity and beyond!");
}
}
Trong đó sẽ cho phép tôi làm:
private static void SafeSpeakAndFly(SpeakingFlyer x)
{
x.Speak();
x.Fly();
}
public static void main(String[] args)
{
BuzzLightyear bly= new BuzzLightyear();
SafeSpeakAndFly(bly);
}
Đây có phải là một quá mức cần thiết không cần thiết? những cạm bẫy để làm điều này là gì?
Tôi cảm thấy thiết kế này tách chức năng SafeSpeakAndFly()
khỏi các tham số của nó và giữ các lỗi khó chịu khi bay do kiểm tra loại thời gian biên dịch.
Tại sao phương pháp đầu tiên được sử dụng rộng rãi trong thực tế và phương pháp sau không được sử dụng?
Tôi tự làm cho mình những câu hỏi giống nhau năm trước và bài đăng này ở đây là câu trả lời ... http://stackoverflow.com/a/384067/982161 –