2013-03-14 28 views
13

Tôi đang viết lại một số mã và tôi đã quyết định tạo lại lớp, vì có số tờ cố định, tôi đang tạo chúng dưới dạng enums . Đây là một quyết định dựa trên khả năng đọc của một nhà xây dựng patter vs một constructor telescoping.Tôi có thể sử dụng mẫu trình xây dựng trên Java Enum

Mã tôi lấy một số tệp .xls, thêm tiêu đề (và đọc một số từ các tệp .xls khác) và có lẽ một số trang phụ. Sau đó nó kết hợp một loạt các trang tính này lại với nhau theo một cách cụ thể để tạo các tab trên sổ làm việc chính của excel. Vấn đề của tôi là một số tab sổ làm việc có số lượng trang tính khác nhau là các đối số. Tôi đang cố gắng áp dụng các mô hình xây dựng. Đây là loại mã Tôi đang cố gắng để viết:

public enum workBookSheet { 
    mySheet1("Name1","mainSheet1.xls",true,1).addSubSheet("pathToSubSheet1.xls"), 
    mySheet2("Name2","mainSheet2.xls",true,2).addHeaderSheet("pathToHeaders.xls").addSubsheet("pathtoSubSheet2.xls"); 

    private String tabName; 
    private String mainSheetName; 
    private Boolean available; 
    private Integer order; 
    private String subSheetName; 
    private String headerSheetName; 

    private workBookSheet(String tabName, String mainSheetName, Boolean available, Integer order){ 
     this.tabName = tabName; 
     this.mainSheetName = mainSheetName; 
     this.available = available; 
     this.order = order; 
    } 
    public workBookSheet addSubSheet(String subSheetName){ 
     this.subSheetName = subSheetName; 
     return this; 
    } 
    public workBookSheet addHeaderSheet(String headerSheetName){ 
     this.headerSheetName = headerSheetName; 
     return this; 
    } 

} 

Các lỗi mà java là đem lại cho tôi dường như được nói rằng Java hy vọng khai enum của tôi (dấu phẩy phân cách danh sách các 'nhà xây dựng enum' ở đầu trang) để chỉ có hàm tạo trong đó, chứ không phải phương thức bổ sung. Tôi có thể di chuyển các phương pháp đó sang phương pháp 'người xây dựng' bên dưới, mà không cần khiếu nại.

public void buildSheets(){ 
    mySheet1.addSubSheet("pathToSubSheet1.xls"); 
    mySheet2.addHeaderSheet("pathToHeaders.xls").addSubSheet("pathtoSubSheet2.xls"); 
} 

Đây có phải là cách duy nhất để triển khai mẫu xây dựng trên nền tảng không? Nó đòi hỏi tôi phải chạy một phương pháp riêng biệt, mà không phải là quá nhiều rắc rối. Tôi cảm thấy như tôi đang phá vỡ mô hình mặc dù (tôi đoán, không phải là một điều xấu nếu điều này hoạt động.)

NB Tôi đã có một cái nhìn tốt để xem nếu có ai khác đã hỏi câu hỏi này, trên SO hoặc ở nơi khác trên web. Gần nhất tôi tìm thấy là một câu hỏi ở đây trên Enums và Nhà máy, nhưng điều đó không hoàn toàn trả lời câu hỏi của tôi. Ngoài ra tôi nhận thức được điều này không hoàn toàn là mô hình xây dựng, vì tôi không có một lớp riêng biệt mà sau đó chấp nhận một phương thức build() tạo ra một enum mới. Tôi đoán đây là gốc của vấn đề trong thiết kế ban đầu của tôi, nhưng tôi tương đối mới với Java.

Vì vậy, có cách nào tốt hơn để sử dụng mẫu xây dựng trên Java enum? Hoặc là những gì tôi có 'đủ gần'?

Trả lời

14

Mặc dù nó không hoàn toàn phù hợp với mẫu trình xây dựng, câu trả lời ngắn gọn là có. Sắp xếp.

Phần còn thiếu không thể gọi .build() để khởi tạo hằng số enum, vì build() không thể sử dụng new. Nhưng bạn có thể nhận được khá nhiều lợi ích của mô hình trình xây dựng.Và chúng ta hãy đối mặt với nó, bạn không thể sử dụng các phương thức factory tĩnh, và subclassing nội tuyến của hằng số enum là lạ.

Dưới đây là ví dụ bằng cách sử dụng Điều tra quốc gia.

package app; 

import org.apache.commons.lang.StringUtils; 
import javax.annotation.Nullable; 
import java.util.EnumSet; 
import java.util.Set; 
import static app.Language.*; 
import static com.google.common.base.Preconditions.*; 

enum Language { 
    ITALIAN, 
    ENGLISH, 
    MALTESE 
} 

public enum Country { 

    ITALY(new Builder(1, "Italy").addLanguage(ITALIAN)), 
    MALTA(new Builder(2, "Malta").addLanguages(MALTESE, ENGLISH, ITALIAN).setPopulation(450_000)); 

    final private int id; 
    final private String name; 
    final private Integer population; 
    final private Set<Language> languages; 

    private static class Builder { 

     private int id; 
     private String name; 
     private Integer population; 
     private Set<Language> languages = EnumSet.noneOf(Language.class); 

     public Builder(int id, String name) { 
      checkArgument(!StringUtils.isBlank(name)); 

      this.id = id; 
      this.name = name; 
     } 

     public Builder setPopulation(int population) { 
      checkArgument(population > 0); 

      this.population = population; 
      return this; 
     } 

     public Builder addLanguage(Language language) { 
      checkNotNull(language); 

      this.languages.add(language); 
      return this; 
     } 

     public Builder addLanguages(Language... language) { 
      checkNotNull(language); 

      this.languages.addAll(languages); 
      return this; 
     } 
    } 

    private Country(Builder builder) { 

     this.id = builder.id; 
     this.name = builder.name; 
     this.population = builder.population; 
     this.languages = builder.languages; 

     checkState(!this.languages.isEmpty()); 
    } 

    public int getId() { 
     return id; 
    } 

    public String getName() { 
     return name; 
    } 

    @Nullable 
    public Integer getPopulation() { 
     return population; 
    } 

    public Set<Language> getLanguages() { 
     return languages; 
    } 
} 

Bạn thậm chí có thể đặt phương thức nhà máy tĩnh trong trình tạo nếu bạn có cách phổ biến để tạo hằng số.

Vì vậy, nó không hoàn toàn là công cụ xây dựng của Bloch, nhưng nó khá gần.

+0

Đây có phải là thứ bạn đã sử dụng trước đây hay là mã mới này bạn đã viết làm ví dụ? – Pureferret

+3

Một chút của cả hai. Tôi muốn sử dụng một người xây dựng, tìm thấy một vài câu trả lời nhưng không thích họ, và đã làm theo cách này. Sau đó, tôi figured tôi chia sẻ giải pháp của tôi trong câu hỏi này trong trường hợp nó đã giúp một ai đó. –

+1

Cảm ơn bạn rất nhiều! Điều này làm cho lớp enum của tôi dễ đọc hơn nhiều. –

1

mySheet1, mySheet2, vv là hằng enum mà theo cú pháp JLS định nghĩa trong phần 8.9.1

EnumConstant: Annotationsopt Identifier Argumentsopt ClassBodyopt

Vì vậy, bạn có thể làm theo các enum liên tục bởi một danh sách đối số (các thông số để vượt qua để các nhà xây dựng) nhưng bạn không thể gọi một phương thức trên hằng số enum trong khi khai báo nó. Tối đa, bạn có thể thêm nội dung lớp cho nó. Bên cạnh đó, việc sử dụng mẫu builder của bạn để xây dựng các trường hợp enum là vấn đề khi nói chung mẫu xây dựng được sử dụng khi bạn có một số lượng lớn các trường hợp (kết hợp giá trị trường) tương phản với khái niệm về enums được sử dụng cho vài trường hợp.

+0

Cảm ơn bạn đã trả lời câu hỏi của bạn dcernahoschi, đặc biệt là để chỉ tôi đến Định nghĩa. Trong thực tế, tôi thực sự có 20-25 trường hợp enum lúc chơi, mỗi trường hợp có sự kết hợp tinh tế khác nhau của tiêu đề, trang phụ, v.v. Có bao nhiêu là đủ lớn để biện minh cho người xây dựng, cách 'ít' đủ cho một enum? Với sự phát triển hơn, điều này có thể thay đổi (các tiêu đề được mã hóa cứng sau này trong lớp có thể được chuyển đổi thành các trang header.xls), vì vậy mẫu này không phù hợp với tôi. – Pureferret

4

Bạn có thể sử dụng các khối dụ (thường sai gọi là "đôi initializers cú đúp") để tùy chỉnh xây dựng với mã tùy ý:

public enum workBookSheet { 

    mySheet1("Name1", "mainSheet1.xls", true, 1) {{ 
     addSubSheet("pathToSubSheet1.xls"); 
    }}, 
    mySheet2("Name2", "mainSheet2.xls", true, 2) {{ 
     // you can use the fluent interface: 
     addHeaderSheet("pathToHeaders.xls").addSubSheet("pathtoSubSheet2.xls"); 
     // but I would prefer coding separate statements: 
     addHeaderSheet("pathToHeaders.xls"); 
     addSubSheet("pathtoSubSheet2.xls"); 
    }}; 

    // rest of your class the same... 
} 

Sử dụng cú pháp này cho phép bạn làm việc xung quanh những hạn chế áp đặt bởi một enum nhưng vẫn có tính ngắn gọn, tiện lợi và linh hoạt của mô hình xây dựng/thông thạo.

+0

Đó là một điều rất thông minh! Câu hỏi duy nhất của tôi là: Tôi có phải sửa đổi các phương thức không, và tôi có thể viết các nội dung khối thể hiện dưới dạng 'this.methodName (...);', như tôi muốn rõ ràng hơn khi viết các phương thức. – Pureferret

+1

Bạn không * cần * để sửa đổi các phương thức, tuy nhiên tôi sẽ không bận tâm với phong cách thông thạo (trả về 'this') và tôi sẽ tạo thành' private', trừ khi bạn * cần * chúng hiển thị bên ngoài lớp của bạn. Bạn có thể viết 'this.', nhưng nó dư thừa và không được khuyến nghị từ một quan điểm kiểu dáng, đặc biệt là vì các phương thức' this' * không bao giờ * cần đủ điều kiện; chỉ các trường yêu cầu đủ điều kiện và chỉ khi chúng xung đột với tên tham số và không có tham số nào cho các khối mẫu. – Bohemian

+0

Bohemian, tôi đã cố gắng sử dụng các khối thể hiện, nhưng lớp enums bên trong là tĩnh, và đặt chúng vào vị trí có nghĩa là họ lỗi. Tôi sẽ để chúng như bây giờ, nhưng nếu tôi tìm thấy thời gian, tôi sẽ cố gắng giải quyết nó. Bây giờ, nếu bạn biết những gì các phương pháp sẽ như thế nào, bạn có thể bật chúng vào câu trả lời? – Pureferret

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