2011-09-20 6 views
10

Tôi đang thiết kế một công cụ trò chơi bằng Java.Java: Thực hiện các đối tượng được liên kết gấp đôi

Tại cốt lõi của động cơ này tồn tại hai lớp Tài sản và Thuộc tính, trong đó Nội dung có danh sách Thuộc tính. Hầu hết các thuộc tính không cần liên kết sao lưu vào Thuộc tính của chúng, nghĩa là Thuộc tính có thể và thường xuất hiện trong danh sách nhiều hơn một Nội dung. Tuy nhiên, có một phần mở rộng thuộc tính được gọi là UniqueAttribute, là một triển khai thực hiện cho những thuộc tính cụ thể cho tài sản của họ và sử dụng một liên kết ngược lại.

  1. Một cách lý tưởng, phương pháp addAttribute Asset tôi sẽ giống như thế này nếu tôi cắt ra các mã khác:

    public void addAttribute(Attribute attribute){ 
        if(attribute instanceof UniqueAttribute) 
        ((UniqueAttribute)attribute).setAsset(this); 
        attributeList.add(attribute); 
    } 
    

    Thật không may, vì chúng sống trong các gói khác nhau, UniqueAttribute.setAsset() phải được công khai . Điều này rời khỏi phương pháp mở cho người dùng bên ngoài của động cơ để gây rối với, và trong khi tôi chỉ có thể handwave nó đi bằng cách nói cách sử dụng phương pháp này trực tiếp là một lỗi - nó có vẻ khá cẩu thả.

  2. Lựa chọn thứ hai là để cung cấp các UniqueAttribute với tài sản xây dựng, có nghĩa là các mã tại thời điểm tạo ra sẽ giống như thế này:

    asset.addAttribute(new UniqueAttribute(asset)); 
    

    Trong khi tôi có thể thêm một tấm séc-và- có thể ném hoặc khẳng định để xác nhận tài sản chính xác được chuyển vào, tôi về cơ bản dựa vào người dùng để kết nối hai, mà tôi cũng không muốn làm.

  3. Tùy chọn thứ ba là cắn viên đạn và đặt 50 tệp java vào cùng một gói để tôi chỉ có thể sử dụng độ nhớt chuẩn.

Có loại mô hình hoặc thứ gì đó sẽ giúp liên kết hai thứ này lại với nhau mà không lộ dây hoặc buộc tôi đưa mọi thứ vào một gói lớn không?

Không thích hợp: Tôi luôn không thích rằng khái niệm về các gói phụ trong java chưa thực sự được mở rộng theo bất kỳ cách có ý nghĩa nào. Một gói phụ, như xa như java là có liên quan chỉ đơn giản là một gói khác nhau, và đã có nhiều lần tôi có thể làm với các công cụ sửa đổi hiển thị trực tiếp liên quan đến điều này.

+0

có thể tùy chọn 2 với một số loại nhà máy biết về mối quan hệ giữa các thuộc tính và nội dung độc đáo? –

+0

Trong khi tôi cho rằng có các quy tắc đặc biệt cho các gói phụ có thể đã hoạt động, nó hầu như không cần thiết (vì bạn có thể sử dụng các hệ thống như Spring hoặc OSGi để thực thi sự tách biệt giữa giao diện và thực hiện) và sẽ làm mọi thứ phức tạp hơn rất nhiều ít được. Việc triển khai đơn giản, đáng tin cậy quan trọng hơn tính năng phức tạp "dễ thương". –

Trả lời

2

Đề xuất của tôi sẽ là Tài sản, Thuộc tính và UniqueAttribute phải nằm trong cùng một gói (có thể cùng với một vài lớp "động cơ" cốt lõi khác). Sau đó, bạn có thể sử dụng khả năng hiển thị gói chuẩn cho UniqueAttribute.setAsset.

Bạn không cần đặt tất cả các lớp khác trong cùng một gói - phương thức Asset.addAttribute của bạn phải công khai và có thể truy cập từ các gói khác để phần còn lại của ứng dụng của bạn có thể sử dụng trực tiếp.

Vì vậy, giải pháp có thể được gọi là "3-" trong phân loại của bạn.

Theo một số điểm tổng quát hơn, cũng cần cân nhắc:

  • Cho dù bạn thực sự cần sự phức tạp của cả hai thuộc tính và UniqueAttributes - Tôi không chắc chắn bạn thực sự, trước đó thực hiện một mô hình đối tượng trò chơi hợp lý phức tạp mà không cần cần bất cứ thứ gì trông giống như một UniqueAttribute. Nếu UniqueAttribute "cần một liên kết trở lại" thì có lẽ nó đang cố gắng quá thông minh/làm quá nhiều?
  • Thậm chí nếu bạn cần cả hai, bạn có thực sự muốn viết mã xử lý chúng theo cùng một cách/như một phần của cùng một chế độ thừa kế đối tượng không? chúng có vẻ khá khác biệt về khái niệm, và bạn sẽ kết thúc viết rất nhiều mã có điều kiện nếu bạn kết hợp cả hai .....
  • Có nhiều ưu điểm khác nhau của các thuộc tính được chia sẻ và không thay đổi liên tục - tốt hơn cho việc sử dụng bộ nhớ, đồng thời và thử nghiệm trong số những thứ khác. Và vì chúng có lẽ là khá nhỏ, chi phí của ngữ nghĩa sao chép trên ghi là tầm thường trong những trường hợp bạn cần nó.
+0

Trước đây tôi đã sử dụng phương pháp một ở trên, vì vậy UniqueAttribute không phải là mới - Tôi chỉ xem xét một số cải tiến cốt lõi. Hai điểm của bạn: Tôi cảm thấy tôi sẽ có quá nhiều mã có điều kiện nếu tôi tách riêng hai mã, vì có nhiều điểm trong đó danh sách Thuộc tính được lặp lại cho một loại hoặc loại cụ thể. Nó là sâu sắc tuy nhiên - Tôi sẽ suy nghĩ về nó nhiều hơn nữa. – Numeron

+0

Ah Tôi hiểu tại sao bạn lại muốn liên kết ngược lại! Nếu lặp qua tất cả các đối tượng với một thuộc tính cụ thể là vấn đề, thì bạn có thể muốn xem xét việc giữ một chỉ mục riêng biệt (HashSet có thể?) Của tất cả các đối tượng có thuộc tính quan trọng. Bạn có thể cập nhật bộ này khi các đối tượng được thêm/xóa hoặc khi các thuộc tính được thay đổi. Mặc dù bạn phải giữ cho chỉ mục này được đồng bộ hóa, điều này là hiệu quả, khá dễ dàng để kiểm tra và tránh sự cần thiết phải đặt logic phức tạp trong các Thuộc tính. – mikera

0

Vâng, về cơ bản bạn muốn làm 3 điều: Phương pháp setAsset

  1. làm hiển thị bên trong gói chứa lớp Asset
  2. phương pháp ẩn setAsset từ tất cả các gói khác
  3. không sử dụng các gói con để đạt được điều đó

Có một chút vấn đề: nếu bạn tuyên bố công khai phương thức đó trong lớp Thuộc tính tất cả các lớp khác bao gồm cả tại gói (chúng ta hãy gọi nó là AttributePackage), bạn không thể ngăn chặn người dùng đưa vào đâu đó gói đó.

Mặt khác bạn có thể làm như sau:

  1. tạo ra một giao diện chỉ chứa các phương pháp thuộc tính mà người dùng nên sử dụng, chúng ta hãy gọi nó AttributeInterface
  2. làm thuộc tính thực hiện mà giao diện
  3. thêm AttributeInterface vào gói mới

Người dùng muốn sử dụng Lớp thuộc tính nên sử dụng nó thông qua AttributeInterface while Tài sản sẽ sử dụng thuộc tính lớp trực tiếp để có quyền truy cập vào tất cả các phương pháp.

tôi sẽ làm một ví dụ:

//attribute interface package 
public interface AttributeInterface{ 
    public void publicAttributeMethodClientShouldUse(); 
} 

//attribute package 
public class Attribute{ 
    public void setAsset(Asset a); 
    public void publicAttributeMethodClientShouldUse(); 
} 

Asset sẽ tham khảo trực tiếp thuộc tính trong khi đó người dùng nên tham khảo AttributeInterface. Hy vọng được rõ ràng.

+0

Tôi không chắc chắn cách người dùng có thể tạo Thuộc tính với liên kết đến nội dung của nó trong trường hợp này? Việc thực hiện giao diện sẽ có nghĩa rằng nó chỉ là một thuộc tính tiêu chuẩn mà không truy cập vào getAsset() và mở rộng lớp có cùng vấn đề như tôi đã trình bày trong câu hỏi. – Numeron

2

tôi sẽ thêm một phương pháp gọi lại trong thuộc tính đó được gọi khi một thể hiện của thuộc tính được thêm vào một tài sản:

class Attribute { 
    protected void addedToAsset(Asset asset) { 
     // do nothing 
    } 
} 

Phương pháp này sẽ được gọi là trong phương pháp addAttribute

class Asset { 
    public void addAttribute(Attribute attribute) { 
     attributeList.add(attribute); 
     attribute.addedToAsset(this); 
    } 

} 

Và phương pháp sẽ được ghi đè trong UniqueAttribute để kiểm soát liên kết với Nội dung:

class UniqueAttribute extends Attribute { 
    Asset asset; 
    protected void addedToAsset(Asset asset) { 
     // manage the previous link if needed 
     if (this.asset != null) { ... } 
     this.asset = asset; 
    } 
} 

Wit giải pháp này, tài sản và thuộc tính nên được đặt trong cùng một gói. Nhưng UniqueAttribute có thể nằm trong bất cứ gói nào bạn muốn.

1

Sửa đổi tùy chọn scond bạn

asset.addAttribute(new UniqueAttribute(asset)); 

như thế này:

class UniqueAttribute { 
Asset asset; 
    public UniqueAttribute(Asset asset) { this.asset = asset; asset.addAttribute(this); } 
} 

Làm một cách tiếp cận tương tự cho các thuộc tính không độc đáo. Điều đó có nghĩa là thay vì sử dụng addAttribute() từ bên ngoài, chỉ sử dụng nó bên trong các hàm tạo.

Một tùy chọn khác là thêm hai phương thức nhà máy vào Nội dung: createAttribute() và createUniqueAttribute();

+0

Bằng cách này, tài sản của UniqueAttribute cũng có thể là cuối cùng, điều này sẽ làm giảm tính độc lập của UniqueAttributes. – OliverS

+0

Mặc dù điều này có nghĩa rằng tôi có cùng một vấn đề ở trên ngoại trừ tôi sẽ được tranh luận với sự hiển thị của addAttribute thay vì setAsset. – Numeron

0

Đầu tiên, các thực thể này do dường như có liên quan chặt chẽ đến mức được đặt trong cùng một gói. Tôi đặt chúng trong cùng một gói và làm cho addAttribute method-private. Hãy nhớ rằng mặc dù từ khi giới thiệu AccessibleObject trong Java, khả năng hiển thị và kiểm soát truy cập bằng ngôn ngữ đã trở thành chỉ là mỹ phẩm ... Bất cứ ai sử dụng thư viện của bạn cũng có thể lấy các lớp học của bạn và làm cho các phương thức và trường có thể truy cập và sửa đổi được! Địa ngục, họ thậm chí có thể sửa đổi final thành viên! Vì vậy, đừng chú trọng nhiều vào khía cạnh hiển thị và chỉ cần đảm bảo luồng mô hình và phương thức của bạn có ý nghĩa đối với người dùng của bạn và hoạt động chính xác.

+0

Xin lỗi, tôi có nghĩa là phương thức 'UniqueAttribute.setAsset()' được tạo thành gói riêng. – vagelis