2012-08-04 26 views
9

Tôi đã bắt đầu chơi xung quanh với các đối tượng có giá trị bất biến trong Java trong khi làm việc trên một dự án trò chơi, sau khi "lĩnh vực thức cộng đồng" cách tiếp cận:Làm thế nào để mở rộng loại không thay đổi trong Java

public class Team { 
    public final String name, flag; 

    public Team(String name, String flag) { 
     this.name = name; 
     this.flag = flag; 
    } 
} 

này hoạt động khá tốt cho tôi cho đến nay, nhưng tôi cần các bộ thông tin bổ sung khác nhau về nhóm trong các trường hợp khác nhau. Ví dụ: một đội có màu đã đặt trong một trận đấu. Câu hỏi đặt ra là, cách tốt nhất để giải quyết những tập hợp thông tin mở rộng này là gì? Tôi biết đây là một câu hỏi khá chung chung, nhưng tôi muốn tiếp tục sử dụng các đối tượng bất biến và có thể ảnh hưởng đến giải pháp.

Dưới đây là các tùy chọn tôi đã đưa ra. Hầu hết trong số họ có lẽ là "đủ tốt", nhưng tôi muốn tìm hiểu một số lý lẽ cho và chống lại họ để tham khảo trong tương lai.

Lựa chọn 1: Tất cả mọi thứ trong một lớp

public class Team { 
    public final String name, flag, colorName; 
    public final int colorRgb; 

    public Team(String name, String flag, String colorName, int colorRgb) { 
     this.name = name; 
     this.flag = flag; 
     this.colorName = colorName; 
     this.colorRgb = colorRgb; 
    } 
} 

này có chỉ có một lớp học cho tất cả các mục đích sử dụng, nhưng không có loại dựa trên dấu hiệu của những dữ liệu thêm dự kiến ​​/ cung cấp.

Phương án 2: subclassing

public class TeamWithColor extends Team { 
    public final String colorName; 
    public final int colorRgb; 

    public Team(String name, String flag, String colorName, int colorRgb) { 
     super(name, flag); 
     this.colorName = colorName; 
     this.colorRgb = colorRgb; 
    } 
} 

Điều này có thể làm cho một bình đẳng dựa trên nội dung() thực hiện không thể.

Lựa chọn 3: Thành phần

public class TeamWithColor { 
    public final Team team; 
    public final String colorName; 
    public final int colorRgb; 

    public Team(Team team, String colorName, int colorRgb) { 
     this.team = team; 
     this.colorName = colorName; 
     this.colorRgb = colorRgb; 
    } 
} 

Ít mã sao chép/soạn sẵn nếu dữ liệu đội bóng và thêm dữ liệu thường xuyên thay đổi một cách độc lập.

Lựa chọn 4: Cặp/tuple (sử dụng một lớp Pair bất biến)

public class TeamColor { 
    public final String colorName; 
    public final int colorRgb; 

    public Team(String colorName, int colorRgb) { 
     this.colorName = colorName; 
     this.colorRgb = colorRgb; 
    } 
} 

Pair<Team, TeamColor> teamWithColor = Pair.create(team, teamColor); 

... hoặc với một lớp tùy chỉnh mà gắn Đội và TeamColor với nhau.

Tôi có xu hướng lựa chọn 3 hoặc 4, nhưng tôi quan tâm đến ý kiến ​​của bạn, lý lẽ và cảm xúc ruột :)

+1

Hoặc sử dụng * Giao diện * (ví dụ: 'ITeam',' ITeamColor') .. các nhà thầu không thể thống nhất anyway. –

+2

Nếu tất cả các đội của bạn có màu, thì tất cả các đội phải có mặt trong một lớp. – Strelok

+0

Nó không thực sự là một câu trả lời, nhưng tôi sẽ nói rằng bạn nên để cho khách hàng (mã đang sử dụng 'Team' đối tượng và màu sắc) lái xe thiết kế giao diện. Tức là, viết ứng dụng khách trước, chỉ cần đưa ra mô hình. Sau đó, sử dụng những gì bạn đã học để tinh chỉnh mô hình và hoàn thành việc triển khai mô hình. – erickson

Trả lời

6

Như bạn nói. Nhóm có thể xuất hiện trong các trường hợp khác nhau. Những trường hợp này là bối cảnh tạo cho nhóm các thuộc tính bổ sung.

Vì vậy, tôi khuyên bạn nên sử dụng bố cục cho từng ngữ cảnh khác nhau để thêm dữ liệu.

public class TeamWithColor { 
    public final Team team; 
    public final TeamColor teamColor; 

    public Team(Team team, TeamColor teamColor) { 
     this.team = team; 
     this.teamColor = teamColor; 
    } 
} 

Có lẽ bạn sẽ phải:

public class TeamDuringOlimpics{ 
    public final Team team; 
    public final TeamColor teamColor; 
    public final TeamFlag teamFlag; 

    public Team(Team team, TeamColor teamColor, TeamFlag teamFlagTeamFlag teamFlag) { 
     this.team = team; 
     this.teamColor = teamColor; 
     this.teamFlag = teamFlag; 
    }  
} 
2

Thành phần âm thanh như một lựa chọn tốt cho thêm dữ liệu theo ngữ cảnh mà bắt buộc phải có thể thay đổi.

Trong các lớp không thay đổi Java thường được đánh dấu final và không thể mở rộng. Xem String làm ví dụ. Đó là quy tắc số tùy chọn 2.

Hãy mệt mỏi khi sử dụng Cặp. Có nhiều lý do chính đáng mà loại Ghép chưa được thêm vào Java. Trong trường hợp này, dữ liệu của bạn được mô hình hóa tốt hơn bằng cách tạo một loại dữ liệu mới (tức là thành phần thông qua).

Đề xuất thực hành tốt nhất cho việc tạo ra các lớp học bất biến: http://www.javapractices.com/topic/TopicAction.do?Id=29

+0

Điểm tốt, nếu bạn quảng cáo một lớp là không thay đổi, có thể là một ý tưởng tốt để đảm bảo không thể có các lớp con có thể thay đổi được, mặc dù trong trường hợp này, những thứ duy nhất có thể hoạt động bất ngờ là các phương thức từ Object.Nhưng tôi đang hỏi một câu hỏi giả tạo, vì vậy tôi xứng đáng nhận được những câu trả lời: P – Medo42

0

Bạn có thể xem xét việc giữ mảnh thông tin này bên ngoài đối tượng Team. Ví dụ: bạn có thể có Bản đồ hoặc Bản đồ

Bằng cách này, bạn có thể làm phong phú thêm đối tượng của mình với nhiều giá trị bổ sung mà không cần giới thiệu các lớp mới hoặc sửa đổi các lớp hiện có. Hơn nữa, nó sẽ giữ tài sản bất biến của các đối tượng khác.

1

Nếu một lớp không thể thay đổi được kế thừa, hoặc nếu chứa các khía cạnh có loại có thể thay đổi, thì nó sẽ không có bảo mật chống nghịch ngợm. Một giao diện "bất biến" cũng sẽ không có bảo mật. Tương tự như vậy, nếu một đối tượng có bất kỳ thành viên nào của các loại có thể mở rộng và đối tượng được coi là có chứa bất kỳ thông tin nào trong các đối tượng được các thành viên đó nhắc đến. Việc quyết định xem đó có phải là vấn đề hay không. Các giao diện không thể thay đổi và các lớp có thể thay đổi mở rộng có thể linh hoạt hơn nhiều so với các lớp được niêm phong sâu; nếu một lớp học sẽ không bị phong ấn sâu, thì có rất ít lợi thế về an ninh để làm cho nó một phần như vậy.

Lưu ý rằng nó có thể cho một đối tượng sâu-bất biến để có một lĩnh vực mà là của một loại có thể thay đổi, nếu ngữ nghĩa của lĩnh vực này xác định rằng nó xác định, chứ không phải là chứa, các đối tượng trong câu hỏi. Ví dụ, nó có thể hữu ích khi có một đối tượng "snapshot" chứa tham chiếu đến một số đối tượng có thể thay đổi và, đối với mỗi đối tượng, một bản sao bất biến của trạng thái hiện tại của nó; đối tượng "snapshot" sau đó sẽ đưa ra một phương thức khôi phục từng đối tượng đến trạng thái mà nó có khi ảnh chụp được tạo ra. Đối tượng snapshot sẽ là "vô cùng bất biến" mặc dù nó tham chiếu đến một đối tượng có thể thay đổi được, vì các tham chiếu của snapshot đối với các đối tượng có thể thay đổi hoàn toàn là xác định chúng, và identities của các đối tượng đó sẽ không thay đổi ngay cả khi trạng thái của chúng.

Một mẫu mà tôi thích trong .net, cũng nên hoạt động trong Java, là có các giao diện như IReadableFooIImmutableFoo; người thứ hai sẽ thừa hưởng trước đây nhưng không thêm bất kỳ thành viên mới nào. Giao diện IReadableFoo nên chứa, ngoài các thành viên để đọc các thuộc tính của nó, một thành viên AsImmutable() sẽ trả lại một IImmutableFoo. Cách tiếp cận này cho phép mã sử dụng các loại có thể thay đổi khi thuận tiện, trong khi giảm thiểu việc sao lưu dự phòng (mã muốn tồn tại một cái gì đó phải gọi AsImmutable() trên đó; đã không thay đổi, không yêu cầu bản sao mới).

0

Tôi khuyên bạn nên sử dụng mẫu Trang trí.

public class TeamWithColor extends Team { 
    public final Team team; 
    public final String colorName; 
    public final int colorRgb; 

    public Team(Team team, String colorName, int colorRgb) { 
     this.team = team; 
     this.colorName = colorName; 
     this.colorRgb = colorRgb; 
    } 
} 

http://en.wikipedia.org/wiki/Decorator_pattern

+1

Đây không phải là một trang trí - vì điều đó, 'Team' sẽ phải là một giao diện. Nếu chúng ta chuyển sang sử dụng getters và interfaces, trang trí có thể sẽ kết hợp các ưu điểm của bố cục (ít sao chép) hơn với các thừa kế (có thể sử dụng 'TeamWithColor' ở khắp mọi nơi' Team' có thể được sử dụng). Mặt khác, bạn phải đặt các getters ủy nhiệm trong 'TeamWithColor', vì vậy bạn không thể thêm các trường vào' Team' mà không cần chỉnh sửa 'TeamWithColor'. Ngoài ra, nó sẽ yêu cầu mã nhiều hơn (hai giao diện, hai lớp, rất nhiều getters). – Medo42

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