2011-07-06 33 views
10

Có sử dụng từ khóa instanceof không dựa trên bản chất của object oriented programming không? Tôi có nghĩa là nó là một thực hành lập trình xấu? Tôi đọc ở đâu đó rằng việc sử dụng từ khóa instanceof có nghĩa là thiết kế có thể không tốt. Bất kỳ giải pháp nào tốt hơn?thể hiện sử dụng từ khóa

+0

trường hợp bạn đang sử dụng nó là gì? khó có thể giải quyết nếu vấn đề không được liệt kê. – Kal

+0

@aps bạn có thể hiển thị cách sử dụng 'instanceof' khiến bạn lo lắng không? –

+0

Tôi không sử dụng. Nhưng tôi chỉ hỏi tại sao nó được coi là không tốt lập trình nếu ai đó sử dụng instanceof? – aps

Trả lời

14

Nói chung có. Tốt nhất là giữ tất cả mã phụ thuộc vào việc là một lớp cụ thể trong lớp đó và sử dụng instanceof thường có nghĩa là bạn đã đặt một số mã bên ngoài lớp đó.

Nhìn vào ví dụ rất đơn giản này:

public class Animal 
{ 
} 

public class Dog extends Animal 
{ 
} 

public class Cat extends Animal 
{ 
} 

public class SomeOtherClass 
{ 
    public abstract String speak(Animal a) 
    { 
    String word = ""; 

    if (a instanceof Dog) 
    { 
     word = "woof"; 
    } 
    else if (a instanceof Cat) 
    { 
     word = "miaow"; 
    } 

    return word; 
    } 
} 

Lý tưởng nhất, chúng tôi muốn tất cả các hành vi cụ thể cho những con chó được chứa trong lớp Dog, chứ không phải lây lan xung quanh chương trình của chúng tôi. Chúng ta có thể thay đổi điều đó bằng cách viết lại chương trình của chúng tôi như thế này:

public abstract class Animal 
{ 
    public String speak(); 
} 

public class Dog extends Animal 
{ 
    public String speak() 
    { 
    return "woof"; 
    } 
} 

public class Cat extends Animal 
{ 
    public String speak() 
    { 
    return "miaow"; 
    } 
} 

public class SomeOtherClass 
{ 
    public String speak(Animal a) 
    { 
    return a.speak(); 
    } 
} 

Chúng tôi đã xác định rằng một Animal phải có một phương pháp speak. Bây giờ SomeOtherClass không cần biết chi tiết cụ thể của từng loại động vật - nó có thể đưa nó ra cho lớp con của Animal.

+2

Giống như một phụ Điểm: Như đã nói trong câu trả lời này, một vấn đề với 'instanceof' là bạn cần phải xác định subtype. Điều gì sẽ xảy ra nếu các loại phụ thay đổi? Sau đó, bạn cần phải viết lại các bài kiểm tra 'instanceof'. Nhưng nếu bạn sử dụng ràng buộc năng động và đa hình, nó sẽ không tạo ra sự khác biệt và nó sẽ vẫn hoạt động. – adamjmarkham

+0

+1: Vì phần "cách-bạn-nên-thực sự-làm": D –

+0

Nên 'nói' là' trừu tượng' trong Động vật, hay mọi Động vật bắt đầu tắt tiếng? –

2

Nó chán nản vì mọi người có thể sử dụng nó để làm điều gì đó như thế này:

if(myAnimal instanceof Dog) 
    ((Dog)myAnimal).bark(); 
else(myAnimal instanceof Cat) 
    ((Cat)myAnimal).meow(); 

Thay vào đó, Animal nên có một phương pháp speak()DogCat kế thừa. Trong OOP thích hợp với đa hình và năng động ràng buộc, sau đó bạn sẽ chỉ cần làm

myAnimal.speak(); 

Tuy nhiên, có một số trường hợp trong đó bạn phải sử dụng instanceof để xác định loại cụ thể của một đối tượng. Có lẽ bạn có danh sách Animals trong nhà của bạn và chỉ những người bạn muốn đưa ra cho một số walk()Dog s. Trong trường hợp đó bạn sẽ lặp qua danh sách của bạn và chỉ walk() những con chó.

+2

Tôi thích thực tế rằng chúng tôi đã viết những điều này cùng một lúc và cả hai đã đi cho các ví dụ động vật :) –

+2

Tôi vừa mới nhận xét về chính xác điều tương tự trên bài đăng của bạn giống như bạn đã nhận xét về tôi :) – tskuzzy

3

Đa hình ủng hộ và liên kết động với downcasting và instanceof. Đây là "OO Way" và cho phép bạn viết mã mà không cần biết về các kiểu con.

VÍ DỤ

abstract class Animal { 
    public abstract void talk(); 
    //... 
} 

class Dog extends Animal { 
    public void talk() { 
     System.out.println("Woof!"); 
    } 
    //... 
} 

class Cat extends Animal { 
    public void talk() { 
     System.out.println("Meow!"); 
    } 
    //... 
} 

class Hippopotamus extends Animal { 
    public void talk() { 
     System.out.println("Roar!"); 
    } 
    //... 
} 

class Main { 

    public static void main(String[] args) { 

     makeItTalk(new Cat()); 
     makeItTalk(new Dog()); 
     makeItTalk(new Hippopotamus()); 
    } 

    public static void makeItTalk(Animal animal) { 

     animal.talk(); 
    } 
} 
+2

Tôi nghĩ 'dưới đây' sẽ là một âm vị thích hợp hơn cho một hà mã :). Tôi sẽ phân lớp và ghi đè hành vi mặc định. 1 cho thiết kế của bạn cho phép tôi có thể. – Perception

3

Sử dụng instanceof không được khuyến khích khi cùng hiệu quả có thể đạt được thông qua các phương pháp ảo, như trong ví dụ của thomson_matt. Tuy nhiên, cần phải sử dụng instanceof trong một số trường hợp. Ví dụ: khi mã của bạn lấy Object từ nguồn bên ngoài, ví dụ: mạng hoặc API của bên thứ ba trả lại Object và bạn phải quyết định loại đối tượng này là gì và hành động phù hợp.

4

Có nhiều câu trả lời hay để quảng bá các phương pháp ảo, nhưng instanceof cũng có các cách sử dụng của nó. Hãy tưởng tượng rằng bạn lặp lại trên List<Event>, để nhận tất cả các đối tượng Urgent. Bạn có thể làm điều đó bằng cách sử dụng isUrgent() nhưng tôi không chắc chắn liệu nó có nhất thiết hay ngắn gọn hơn hay không.Ngoài ra, isUrgent() sẽ yêu cầu làm cho Event biết rằng các lớp con của nó có thể sở hữu thuộc tính tương ứng, có thể:

  • được coi là điều gì đó chống lại các nguyên tắc mô-đun;
  • thậm chí không thể, nếu Event thuộc về một số thư viện không thể sửa đổi được.
  • 3

    Điều quan trọng là không thấy instanceof như là một phần của "thực hành bình thường" thông thường. Giống như nhìn chung, instanceof là một công cụ đặc biệt để sử dụng đặc biệt, hoàn cảnh không điển hình. Bất cứ khi nào bạn sử dụng 'instanceof', bạn cũng có thể tìm thấy chính mình bằng cách sử dụng các phần 'đặc biệt' khác của nền tảng như phản ánh chung hơn.

    Vì vậy, miễn là bất cứ khi nào bạn thấy mình sử dụng nó, bạn chấp nhận rằng những gì bạn đang làm là một kludge trong trường hợp không có một sự thay thế thanh lịch/thực tế hơn, thì đó là tốt.

    Điều đó nói rằng, những trường hợp điển hình nhất trong các chương trình hàng ngày có lẽ là:

    • bình đẳng thực hiện()
    • đọc đối tượng serialized
    • một vài trường hợp khác mà bạn đang đưa ra một mảng/tập hợp các các mục, ví dụ liệt kê JComponents trong một khung/container và sau đó thực hiện hành động tùy thuộc vào loại.

    Quy tắc chung mà bạn có thể thử và tuân thủ là không yêu cầu người dùng thư viện phải sử dụng 'instanceof', nhưng thay vào đó có bất kỳ trường hợp 'instanceof' nào bên trong thư viện.

    Hoặc đặt một cách khác, bạn nên định khung lại câu hỏi của mình: "Các trường hợp 'intsanceof' là cách giải quyết cho?"

    +0

    thomson_matt đã đưa ra một ví dụ tốt về việc sử dụng không đúng đối tượng của instanceof. Bây giờ tôi có một tình huống, nơi mà tất cả các điều kiện ông nói, đều đúng. Say Animal là lớp trừu tượng, Cat và Dog là các lớp con của nó. Vì vậy, tự nhiên những gì âm thanh mỗi con vật nên làm phải được đóng gói trong chính lớp riêng của nó. Nhưng chúng ta hãy nói rằng tôi có một lớp khác được gọi là Chuột người phản ứng với động vật khác nhau theo những cách khác nhau.Nếu nó là một con chó, con chuột không làm bất cứ điều gì nhiều ngoại trừ tránh con chó của con đường.Nếu nó là một con mèo, sau đó nó cố gắng để ẩn. Trong tình huống như vậy, nó là ok để instanceof, hoặc là có một số phương pháp tốt hơn? – aps

    +2

    Bạn có thể có nhiều phương thức reactTo (...) trên đối tượng Chuột, một cho mỗi loại động vật và truyền động vật bạn muốn chuột phản ứng lại. –

    0

    Làm thế nào về trường hợp của một nhà máy sáng tạo (Xem bên dưới)? Trong trường hợp này, tôi không nghĩ rằng nó là thích hợp cho một phân lớp động vật để biết làm thế nào để xây dựng một cái lồng cho chính nó. Dường như ngoài phạm vi của Động vật là gì và buộc các phân lớp động vật phải thực hiện các hành vi không thực chất đối với Động vật là gì.

    public static Cage createCage(Animal animal) { 
        if (animal instanceof Dog) 
        return new DogHouse(); 
        else if (animal instanceof Lion) 
        return new SteelCage(); 
        else if (animal instanceof Chicken) 
        return new ChickenWiredCage(); 
        else if (animal instanceof AlienPreditor) 
        return new ForceFieldCage(); 
        ... 
        else 
        return new GenericCage(); 
    } 
    
    0

    Cách sử dụng khác của thao tác instaceOf có thể bị lỗi. Nếu bạn có xử lý lỗi tương tự cho trường hợp ngoại lệ, và bạn muốn có nó tất cả trong một nơi mà bạn có thể sử dụng:

    public void handleError(Throwable t, HttpServletRequest req) { 
        if (t instaceOf ValidationException) { 
           ...doSomewthing...... 
        } else if (t instaceOf DataException) { 
           ...doSomewthing...... 
        } else if (t instaceOf DataException) { 
           ...doSomewthing...... 
        } else { 
           ...doSomewthing...... 
        } 
    
    } 
    

    với mã trên, bạn tránh để có nhiều

    } catch <Exception> { 
    

    khối và thay vào đó có chỉ là một

    } catch (Throwable t) { 
        handleError(t, request); 
        return "errorPage" or whateveryouwant; 
    } 
    

    Ngoài ra, một điều nữa là, là bạn kiểm tra mã nguồn java, bạn sẽ tìm thấy rất nhiều tập quán của instaceof ..

    Và một liên kết tốt: article about usage of instaceof

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