2012-12-19 3 views
5

Tôi có một ứng dụng thực hiện các thuật toán phân tích khác nhau trên đồ thị của các nút và các cạnh G (N, E). Các thuộc tính của các nút và các cạnh khác nhau với ứng dụng và tạo thành một hệ thống phân cấp thừa kế dựa trên loại biểu đồ và bản chất của các thuộc tính. Ví dụ, thư mục gốc của hệ thống phân cấp Node có thể đại diện cho các đồ thị Cyclic không theo định hướng chung nhất (NcgNode). Một lớp con của NcgNode có thể đại diện cho các đồ thị theo chu kỳ trực tiếp (DcgNode), tiếp theo là DagNode, vv Các thuật toán có thể áp dụng cho DAG khác với NCG, nhưng không phải là thị thực. Một hành vi quan trọng của thư mục gốc của cây là thêm và lấy các nút liền kề của biểu đồ. Câu hỏi đặt ra là làm thế nào để làm điều này mà không tạo ra một ngoại lệ "không được kiểm soát"?Thừa kế và generics

Một phiên bản ngắn gọn của mã có thể trông như thế này:

import java.util.ArrayList; 
import java.util.List; 

public class NcgNode { 
    private List<NcgNode> nodeList_ = null; 
    private List<? extends NcgNode> nodeListSrc_ = null; 
    private List<? super NcgNode> nodeListSink_ = null; 

    public <N extends NcgNode> void addNode(N node) { 
     if (nodeList_ == null) { 
      nodeList_ = new ArrayList<NcgNode>(); 
      nodeListSrc_ = nodeList_; 
      nodeListSink_ = nodeList_; 
     } 
     nodeListSink_.add(node); 
    } 

    @SuppressWarnings("unchecked") 
    // Any way to avoid this? 
    public <N extends NcgNode> N getNode(int n) { 
     if ((nodeList_ == null) || (n >= nodeList_.size())) 
      return null; 
     // causes unchecked warning: 
     return (N) nodeListSrc_.get(n); 
    } 
} 

class DcgNode extends NcgNode { 
    // enables DCG algorithms, etc 
} 

class DagNode extends DcgNode { 
    // enables DAG algorithms, etc. 
} 

Có cách nào tốt hơn để thiết kế này?

Trả lời

0

sửa đổi phương pháp của bạn như vậy dưới đây:

public NcgNode getNode(int n) { 
    if ((nodeList_ == null) || (n >= nodeList_.size())) { 
    return null; 
} 

return (NcgNode) nodeListSrc_.get(n); 
} 
+3

Giải pháp này không cho phép người gọi sử dụng các chi tiết cụ thể của lớp con cụ thể mà nó trả về mà không thực hiện một diễn viên không an toàn. Đánh lừa lon có thể xuống đường. –

0

Check-out "loại tự giới hạn". (EDIT: không chắc là tôi hiểu được xuống votes đây)

lớp gốc của bạn nên được trừu tượng và các loại nút thực tế N nên là một loại tham số đến lớp, như trong

public abstract class AbstractNode< N extends AbstractNode<N> > { 
    private List<N> nodeList_ = null; 

    public synchronized void addNode(N node) { 
     if (nodeList_ == null) 
      nodeList_ = new ArrayList<N>(); 
     nodeList_.add(node); 
    } 

    public N getNode(int n) { 
     if (nodeList_ == null || n >= nodeList_.size()) 
      throw new NoSuchElementException(); 
     return nodeList_.get(n); 
    } 
} 

lớp con bê tông có thể sau đó cung cấp các kiểu của riêng chúng như N. Đối với các hệ thống phân cấp thừa kế sâu, hãy giữ "My Type" còn sống với một lớp trừu tượng khác.

class NcgNode extends AbstractNode<NcgNode> { 
} 

abstract class AbstractDcgNode< N extends AbstractDcgNode<N> > extends AbstractNode<N> { 
    // enables DCG algorithms, etc 
} 

class DcgNode extends AbstractDcgNode<DcgNode> { 
} 

class DagNode extends AbstractDcgNode<DagNode> { 
    // enables DAG algorithms, etc 
} 
+0

1) "loại tự giới hạn" không hoạt động trong Java. 2) nếu bạn thay thế 'AbstractNode > 'với' AbstractNode 'và' AbstractDcgNode > 'với' AbstractDcgNode ' nó sẽ làm việc cùng một cách – newacct

+0

Bạn có thể cụ thể hơn về bình luận 1) ?Người ta không thể thực thi chính xác rằng một tham số kiểu ràng buộc lớp khai báo nó, nhưng nó gần hơn bình luận 2) cho phép các chương trình biên dịch nghiêm ngặt hơn tôi - và nhiều hơn OP đang tìm kiếm. –

1

Chỉ cần chắc danh sách của bạn có loại NcgNode, ví dụ:

private List<NcgNode> nodeListSrc_ = null; 

Bạn vẫn có thể đặt lớp con của NcgNode vào danh sách này.

1

Bạn nên làm điều gì đó như sau. Có các phương thức được định nghĩa trong một lớp trừu tượng (NcgNode), được tham số hóa trên kiểu của các con. Do đó, addNodegetNode có thể dễ dàng được viết. Sau đó, bạn sẽ có triển khai cụ thể (tôi đã sử dụng DcgNodeDagNode; không chắc chắn nếu đây là những gì bạn muốn) là một phân lớp của điều này, tham số trên chính nó. Điều này cho phép bạn có các thuật toán sau (xem bên dưới) yêu cầu các nút của một nút là cùng loại với nút.

public abstract class NcgNode<N> { 
    private List<N> nodeList_ = null; 

    public void addNode(N node) { 
     if (nodeList_ == null) { 
      nodeList_ = new ArrayList<N>(); 
     } 
     nodeList_.add(node); 
    } 

    // Any way to avoid this? 
    public N getNode(int n) { 
     if ((nodeList_ == null) || (n >= nodeList_.size())) 
      return null; 
     return nodeList_.get(n); 
    } 
} 

class DcgNode extends NcgNode<DcgNode> { 
    // enables DCG algorithms, etc 
} 

class DagNode extends NcgNode<DagNode> { 
    // enables DAG algorithms, etc. 
} 

//... 
static <N extends NcgNode<N>> void someAlgorithm(N node) { } 

Ý tưởng của bạn của DagNode là một lớp con của DcgNode không thể được an toàn, bởi vì nếu một DagNode "is-a" DcgNode, sau đó có nghĩa là bạn có thể đặt bất kỳ DcgNode vào nó như con của mình, mà không phải là những gì bạn muốn.

+0

Nếu bạn muốn mở rộng DcgNode hoặc DagNode thì sao? – Sarevok

+0

Nếu tôi muốn lưu trữ một Danh sách có thể lưu trữ cả DcgNode và DagNode, tôi có nên khai báo nó không? Trình biên dịch cho thấy một cảnh báo nếu tôi khai báo nó như thế vì tôi đang sử dụng kiểu thô. – Sarevok