2010-04-26 29 views
6

Tôi mới sử dụng Java và tôi đã gặp phải sự cố sau:Tôi nên trả về các kiểu khác nhau trong một phương thức dựa trên giá trị của một chuỗi trong Java như thế nào?

Tôi đã tạo một số lớp mà tất cả đều triển khai giao diện "Trình phân tích cú pháp". Tôi có một JavaParser, PythonParser, CParser và cuối cùng là một TextParser.

Tôi đang cố gắng viết một phương thức để nó sẽ lấy một tệp hoặc một chuỗi (đại diện cho tên tệp) và trả về trình phân tích cú pháp thích hợp cho phần mở rộng của tệp.

Dưới đây là một số psuedo-mã của những gì tôi đang cố gắng làm cơ bản:

public Parser getParser(String filename) 
{ 
    String extension = filename.substring(filename.lastIndexOf(".")); 

    switch(extension) 
    { 
     case "py": return new PythonParser(); 
     case "java": return new JavaParser(); 
     case "c": return new CParser(); 
     default: return new TextParser(); 
    } 
} 

Nói chung, đây là cách đúng đắn để xử lý tình huống này? Ngoài ra, làm thế nào tôi nên xử lý một thực tế là Java không cho phép chuyển đổi trên dây? Tôi có nên sử dụng giá trị .hashcode() của chuỗi không?

Tôi cảm thấy như có một số mẫu thiết kế hoặc một cái gì đó để xử lý điều này nhưng nó giúp tôi. Đây có phải là cách bạn sẽ làm điều đó?

Trả lời

8

Đây được gọi là Factory method pattern và có vẻ như đây là cách khá tốt để xử lý sự cố của bạn. Một cách bạn có thể giải quyết vấn đề "Java không cho phép chuyển đổi chuỗi" là sử dụng câu lệnh if ... else.

if (extension.equals("py")) { 
    return new PythonParser(); 
} 
else if(extension.equals("java")) { 
    return new JavaParser(); 
} 
else ... 
+1

Đối với OP: lưu ý việc sử dụng '.equals()' trái với '=='. Đó là quan trọng! Google "java string equals" hoặc một cái gì đó để xem tại sao. – MatrixFrog

+0

+1 để đề cập đến mẫu phương thức Nhà máy. – CoolBeans

11
  1. Bạn chỉ có thể sử dụng một vài if báo cáo cái khác.

  2. Bạn có thể tạo enum đặc biệt cho ngôn ngữ của mình và sử dụng trong tuyên ngôn chuyển đổi.

  3. Bạn có thể sử dụng Map nơi ngôn ngữ là khóa và nguyên mẫu của trình phân tích cú pháp là các giá trị.

Tùy chọn thứ ba có vẻ thú vị như đối với tôi. Mã này sẽ trông giống như:

return parsers.get(extention).newInstance(); 

Và đây là một chút thực hiện khéo léo của các tùy chọn thứ 2 với enum:

enum Language { 

    JAVA { 
     public Parser getParser() { 
      return new JavaParser(); 
     }}, 
    PYTHON { 
     public Parser getParser() { 
      return new PythonParser(); 
     }}, 
    TEXT { 
     public Parser getParser() { 
      return new TextParser(); 
     }}; 

    public Parser getParser() { 
     return null; 
    } 

    public static Language getLanguage (String extention) { 
     try { 
      return valueOf (extention); 
     } catch (IllegalArgumentException e) { 
      return TEXT; 
     } 
    } 
} 

... 

public Parser getParser(String filename) { 
    String extension = filename.substring(filename.lastIndexOf("."));  
    return Language.getLanguage (extension).getParser(); 
} 
+4

Cá nhân, tôi muốn thực hiện enum, vì nó cho phép chuyển đổi thích hợp và không cần giả định một hàm tạo không có arg. Mã không cần lâu hơn nữa: Parsers.valueOf (extension) .getParser(); – ig0774

+0

+1 để đề cập đến enum. – CoolBeans

0

Sử dụng giao diện là chính xác trong tình huống này. Giao diện của bạn nên trưng ra các phương thức để các lớp gọi không cần phải tự đưa chúng vào thực thi trình phân tích cú pháp cụ thể.

Về trường hợp chuyển đổi, nếu bạn đang sử dụng jdk1.5 hoặc cao hơn, bạn nên xác định enum cho các chuỗi này và bạn có thể sử dụng trường hợp swicth một cách dễ dàng.

1

bạn có thể sử dụng một enum để quyết định một lần mà ngôn ngữ được bạn xử lý và sau đó sử dụng nó xung quanh (cũng trong báo cáo chuyển đổi):

enum Type { JAVA, PYTHON, CPP, C, PERL }; 

Type getType(String filename) 
{ 
    // do your if chain here 
    return JAVA; 
} 

public Parser getParser(String filename) 
{ 
    switch(getType(filename)) 
    { 
     case PYTHON: return new PythonParser(); 
     case JAVA: return new JavaParser(); 
     case C: return new CParser(); 
     default: return new TextParser(); 
    } 
} 

Liên quan đến câu hỏi đầu tiên của bạn: Cách tiếp cận của bạn là OK, nó là gọi nhà máy mẫu khi bạn có một cái gì đó mà xây dựng nhiều loại triển khai cụ thể của một giao diện (trong trường hợp của bạn Parser) chọn cái nào tại thời gian chạy

+0

Bạn thậm chí có thể ẩn phương thức getType bên trong enum (và tạo mức cao nhất enum) để phân tách mối quan tâm mạnh mẽ hơn –

+0

Có, bạn được phép làm ngay bây giờ __enums__ có thể được sử dụng làm đối tượng thực .. – Jack

0

tôi sẽ:

public Parser getParser(String filename) { 
    String extension = filename.substring(filename.lastIndexOf(".")); 

    if("py".equals(extension) ) { return new PythonParser() } 
    if("java".equals(extension)) { return new JavaParser(); } 
    if("c".equals(extension) ) { return new CParser();  } 

    return new TextParser(); 
} 

Giới thiệu về câu hỏi trong tiêu đề của bạn

Làm thế nào tôi nên trở lại các loại khác nhau trong một phương pháp dựa trên giá trị của một chuỗi trong Java?

Bạn không thể chỉ phải trả lại một loại duy nhất. Những gì bạn có thể làm là trả về các kiểu con của kiểu đó, vì vậy nếu các trình phân tích cú pháp của bạn là các lớp con hoặc thực hiện lớp/giao diện Parser thì mã ở trên sẽ hoạt động hoàn hảo.

tức là.

public interface Parser { 
    //parser methods 
    ... 
} 
class PythonParser implements Parser { 
    // parser implementation 
    ... 
} 
class JavaParser implements Parser { 
    // parser implementation 
    ... 
} 
class CParser implements Parser { 
    // parser implementation 
    ... 
} 
1

Nói chung, đây là cách đúng đắn để xử lý tình huống này?

này có vẻ là đúng cách, cho rằng PythonParser, JavaParser vv dụng cụ hoặc là lớp con của Parser

Ngoài ra, làm thế nào tôi nên xử lý thực tế rằng Java không cho phép chuyển đổi trên dây?

Sử dụng if..else if; Bạn không phải sử dụng mã băm hoặc bất kỳ thứ gì. Kiểm tra phương thức equals() trên chuỗi.

tôi cảm thấy như có một số thiết kế mẫu hoặc một cái gì đó

yes

1

tất cả PythonParser, JavaParser, và CParser nên lớp con của Parser, hoặc Parser có thể là một giao diện mà tất cả họ đều triển khai thực hiện.

Bạn có thể dễ dàng vượt qua giới hạn các tuyên bố tình huống bằng cách sử dụng if/else if.

KHÔNG sử dụng mã băm của chuỗi. Nhiều chuỗi nhiều ánh xạ tới cùng một mã băm, vì vậy chỉ vì extension.hashCode() == "java" .hashCode() không nhất thiết có nghĩa là extension.equals ("java"). Chỉ với 3 chuỗi ở đây xác suất của một vụ va chạm ngẫu nhiên là nhỏ, nhưng các chương trình mà "phải làm việc hầu hết thời gian miễn là chúng ta may mắn" là tin xấu. Trong trường hợp này, chương trình có thể hoạt động hoàn toàn chính xác với bộ sưu tập chuỗi cụ thể này, và sau đó một thời gian sau đó bạn thêm CobolParser và đột nhiên nó ngừng hoạt động.

Ai đó đã đề cập đến việc sử dụng enums. Nói chung nó là tốt hơn để sử dụng enums để xác định "loại" của sự vật hơn là sử dụng dây. Nhưng trong trường hợp này, bạn đang giải nén chuỗi từ tên tệp, vì vậy bạn phải chạy nó thông qua if if else nếu block chuyển nó thành enum, và sau đó kiểm tra enum. Khi bạn nhanh chóng tạo một trình phân tích cú pháp theo loại cụ thể, có khả năng bạn sẽ không lưu lại enum hoặc bao giờ nhìn vào nó một lần nữa, vì vậy tôi không nghĩ bạn sẽ đạt được bất kỳ thứ gì.

+0

+1 không sử dụng mã băm – Pops

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