2012-04-28 23 views
7

Tôi muốn tránh sử dụng các lớp được gắn thẻ và các khối if-else hoặc câu lệnh chuyển đổi và sử dụng đa hình với phân cấp lớp thay vào đó, mà tôi tin là thực hành tốt hơn.Tạo đối tượng và đa hình

Ví dụ, một cái gì đó giống như dưới đây, nơi mà sự lựa chọn của phương pháp thực hiện là phụ thuộc chỉ có một lĩnh vực của một đối tượng loại Actor.

switch(actor.getTagField()) 
{ 
    case 1: actor.act1(); break; 
    case 2: actor.act2(); break; 
    [...] 
} 

sẽ trở thành

actor.act(); 

và phương pháp hành động sẽ được ghi đè trong các lớp con của diễn viên.

Tuy nhiên, cách rõ ràng nhất để quyết định trong thời gian chạy mà lớp con để nhanh chóng trông hết sức tương tự với bản gốc:

Actor newActor(int type) 
{ 
    switch(type) 
    { 
     case 1: return new Actor1(); 
     case 2: return new Actor2(); 
     [...] 
    } 
} 

nên nó có vẻ như không có gì thực sự đã đạt được; logic đã được di chuyển.

Cách tốt hơn để làm điều này là gì? Cách duy nhất tôi có thể đưa ra liên quan đến việc thực hiện một lớp nhà máy cho mỗi phân lớp của Actor, nhưng điều này có vẻ khá cồng kềnh cho một vấn đề đơn giản như vậy.

Tôi có thấy quá mức này không? Nó chỉ có vẻ như không có điểm làm cho sự thay đổi ban đầu nếu tôi chỉ làm khá nhiều điều tương tự ở nơi khác.

Trả lời

4

Câu hỏi là "nếu" bạn cần một nhà máy. Nhà máy có nghĩa là quản lý việc tạo ra các cá thể không phải là quá nhiều hành vi của các cá thể liên quan.

Nếu không, bạn chỉ đang xem xét thừa kế cơ bản. Một cái gì đó như ..

class Actor{ 
    public void act(){ 
    System.out.println("I act.."); 
    } 
} 

class StuntActor extends Actor { 
    public void act(){ 
    System.out.println("I do fancy stunts.."); 
    } 
} 

class VoiceActor extends Actor { 
    public void act(){ 
    System.out.println("I make funny noises.."); 
    } 
} 

Để sử dụng, bạn chỉ có thể tạo nhanh loại diễn viên bạn cần trực tiếp.

Actor fred = new Actor(); 
Actor tom = new VoiceActor(); 
Actor sally = new StuntActor(); 

fred.act(); 
tom.act(); 
sally.act(); 

Output:

I act.. 
I make funny noises.. 
I do fancy stunts.. 

EDIT:

Nếu bạn cần phải tập trung sự sáng tạo của các Actors..aka vis một nhà máy, bạn sẽ không thể thoát khỏi một loại logic chuyển mạch - trong trường hợp này ..tôi thường sẽ sử dụng một điều tra để có thể đọc:

public class Actor{ 
    public enum Type{ REGULAR, VOICE, STUNT } 

    public static Actor Create(Actor.Type type){ 
    switch(type) { 
     case VOICE: 
     return new VoiceActor(); 
     case STUNT: 
     return new StuntActor(); 
     case REGULAR: 
     default: 
     return new Actor(); 
    } 
    } 

    public void act(){ 
    System.out.println("I act.."); 
    } 
} 

Cách sử dụng:

Actor some_actor = Actor.Create(Actor.Type.VOICE); 
some_actor.act(); 

Output:

I make funny noises.. 
+0

Xin lỗi, để làm rõ, tôi muốn chọn phân lớp để khởi tạo trong thời gian chạy, không phải lúc biên dịch như trong ví dụ của bạn. Điều này đòi hỏi một chuyển đổi lớn hoặc khối khác nếu tôi muốn tránh. Tôi bắt đầu nghĩ rằng điều đó là không cần thiết vì nó sẽ chỉ cần một lần khi sáng tạo. – flowsnake

+0

Hmm..chính hãng nhà máy có ít việc phải làm với biên dịch thời gian chạy/biên dịch mỗi lần, thay vì trách nhiệm và kiểm soát việc tạo ra các diễn viên. Ví dụ, nếu việc tạo ra các diễn viên ở trên xảy ra trong một sự kiện, nó sẽ không phải là thời gian chạy? –

+0

Những gì bạn đang làm là "quyết định" để tập trung việc tạo ra các diễn viên .. bạn muốn các diễn viên đến từ một nơi, trong trường hợp đó ... bạn không thể đi vòng quanh ... bởi vì đó là quyết định người dùng cuối cùng. –

1

Tôi tin rằng bạn có thể làm điều đó với Abstract factory pattern ...

Đây là một ví dụ:

abstract class Computer { 
    public abstract Parts getRAM(); 
    public abstract Parts getProcessor(); 
    public abstract Parts getMonitor(); 
} 

class Parts { 
    public String specification; 
    public Parts(String specification) { 
     this.specification = specification; 
    } 
    public String getSpecification() { 
     return specification; 
    } 
} 

Chúng tôi có hai lớp mà kéo dài Computer

class PC extends Computer { 
    public Parts getRAM() { 
     return new Parts("512 MB"); 
    } 
    public Parts getProcessor() { 
     return new Parts("Celeron"); 
    } 
    public Parts getMonitor() { 
     return new Parts("15 inches"); 
    } 
} 

class Workstation extends Computer { 
    public Parts getRAM() { 
     return new Parts("1 GB"); 
    } 
    public Parts getProcessor() { 
     return new Parts("Intel P 3"); 
    } 
    public Parts getMonitor() { 
     return new Parts("19 inches"); 
    } 
} 

Và cuối cùng chúng ta có ,

public class ComputerType { 
    private Computer comp; 
    public static void main(String[] args) { 
     ComputerType type = new ComputerType(); 
     Computer computer = type.getComputer("Workstation"); 
     System.out.println("Monitor: "+computer.getMonitor().getSpecification()); 
     System.out.println("RAM: "+computer.getRAM().getSpecification()); 
     System.out.println("Processor: "+computer.getProcessor().getSpecification()); 
    }  

    public Computer getComputer(String computerType) { 
     if (computerType.equals("PC")) 
      comp = new PC(); 
     else if(computerType.equals("Workstation")) 
      comp = new Workstation(); 
     return comp; 
    }  
} 
+0

Tôi đã tìm kiếm điều này trước, nhưng tôi nghĩ rằng nó có lẽ là không cần thiết phức tạp cho những gì tôi muốn làm. Tôi không chắc. – flowsnake

2

Chuyển báo cáo không phải là ác tinh khiết. Nó thực sự là sao chép mà bạn đang muốn loại bỏ với thiết kế tốt hơn. Thông thường, bạn sẽ thấy cùng một câu lệnh chuyển đổi hiển thị ở các vị trí khác nhau (xa) trong mã của bạn - không nhất thiết phải làm điều tương tự, nhưng chuyển đổi trên cùng một dữ liệu. Bằng cách giới thiệu đa hình, bạn kéo những thiết bị chuyển mạch với nhau như các phương pháp khác nhau của cùng một đối tượng.

Điều này làm hai việc, đầu tiên nó làm giảm một số công tắc thành một công tắc bên trong một nhà máy nó kéo cùng nhau trải ra logic có thể phụ thuộc vào dữ liệu tương tự. Dữ liệu đó sẽ biến thành biến thành viên trong đối tượng của bạn.

Cũng đáng lưu ý rằng bạn không phải lúc nào cũng kết thúc bằng tuyên bố chuyển đổi dưới mui xe của nhà máy. Có lẽ bạn có thể quét đường dẫn lớp khi khởi động và xây dựng một loại HashMap của các loại thực hiện giao diện. Ví dụ, hãy xem xét việc thực hiện giao thức socket như SMTP. Bạn có thể có các đối tượng có tên là HeloCommand, MailFromCommand, v.v ... và tìm đối tượng phù hợp để xử lý thông báo bằng cách khớp lệnh socket với tên lớp.

+0

Tôi thực sự đã cân nhắc làm điều gì đó như thế, nhưng sau đó bắt đầu đọc về cách phản ánh nên là phương sách cuối cùng. – flowsnake

+0

Phản ánh là một công cụ mạnh mẽ và có nhiều cách để sử dụng nó mà không bị mất hiệu suất. Ví dụ tôi mô tả trong câu trả lời của tôi sẽ chỉ sử dụng sự phản chiếu khi khởi động và sử dụng một 'HashMap' sau đó. –

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