2012-12-28 44 views
6

Xem xét vấn đề, trong đó tôi đang phát triển một cây như Bộ sưu tập.Bộ sưu tập lười biếng trong Java

Một trong những chức năng chính của Bộ sưu tập của tôi là để theo dõi tất cả các mục được lưu trữ từng người một và sau đó gọi một chức năng nhất định cho từng hạng mục cho đến khi một tiêu chí được đưa đã được đáp ứng (lười biếng Collection).

Vì vậy, các chức năng cần phải có chữ ký sau đây:

void Trace(function func, criteria crit) 
{ 
    item i = firstItem(); 
    while (i != endItem()) 
    { 
     i = nextItem(); 
     func(i); 
     if (crit(i)) 
      return; 
    } 
} 

trong C++ con trỏ chức năng có thể được sử dụng cho funccrit.
trong số C#, yield từ khóa chính xác là giải pháp cho vấn đề này, tôi tin.

Làm cách nào để có được điều tương tự trong Java?

+1

Vòng lặp của bạn có lỗi. Nó không xử lý phần tử cuối cùng. Xem xét danh sách nếu độ dài 1 - vòng lặp while sẽ không được nhập. – Bohemian

+0

Điểm tốt :) Nhưng may thay, điều đó không liên quan gì đến vấn đề này :) – MBZ

Trả lời

1

Tạo giao diện khai báo các phương thức và yêu cầu tham chiếu đến đối tượng triển khai giao diện làm đối số. Người gọi có thể tạo đối tượng bằng cách sử dụng một lớp bên trong vô danh.

2

Trong Java, bạn sẽ vượt qua tham chiếu đến đối tượng của lớp mà thực hiện chức năng áp dụng, hoặc sử dụng Commons Bộ sưu tập thay vì:

  • Sử dụng Predicate triển khai cho các phần crit.
  • Sử dụng Closure triển khai cho phần func.

Ví dụ:

Closure c = new Closure() { 
    public void execute(Object obj) { 
     ... 
    } 
}; 

Predicate p = new Predicate() { 
    public boolean evaluate(Object obj) { 
     ... 
    } 
} 

Trace(c, p); 
+0

+1 và nếu bạn thích gắn bó với Java lõi, [Có thể gọi] (http://docs.oracle.com/javase/ 7/docs/api/java/util/concurrent/Callable.html) cung cấp giao diện chung hợp lý cho những thứ giống như đóng có thể trả về một giá trị. –

+0

@RyanStewart, vấn đề của tôi với 'Callable' là nó không cung cấp API mà OP muốn. Phương thức 'call()' nhận không có tham số, có nghĩa là bạn phải tạo một cá thể mới của việc thực hiện 'Callable' của bạn với mỗi lần lặp. – Isaac

2

Những gì bạn đang tìm kiếm ở đây là mô hình Strategy thiết kế.

Mục tiêu của mẫu này để trừu tượng hóa việc triển khai thuật toán thành đối tượng Chiến lược. Ở đây, các thuật toán của bạn là funccrit chức năng mà bạn đang tìm kiếm để vượt qua trong.

Vì vậy, bạn muốn có một giao diện được gọi là một cái gì đó giống như TraceStrategy. Sau đó, bạn sẽ chuyển các triển khai của giao diện này vào bộ sưu tập của bạn. Mã của bạn sau đó sẽ giống như

void Trace(TraceStrategy traceStrategy) 
{ 
    item i = firstItem(); 
    while (i != endItem()) 
    { 
     i = nextItem(); 
     traceStrategy.func(i); 
     if (traceStrategy.crit(i)) 
      return; 
    } 
} 

interface TraceStrategy { 
    public boolean crit(item i); 

    public void func(item i); 
} 

Bạn có thể muốn làm cho điều này chung chung, do đó bạn không được gắn với item ... nhưng bạn sẽ có được ý tưởng.

+1

Vấn đề với cách tiếp cận này là sẽ luôn có một sự liên kết giữa 'crit' và' func'. Nếu bạn có 'x' khả năng cho' crit' và 'y' khả năng cho' func', bạn có thể sẽ tạo 'x * y' triển khai' TraceStrategy' ... do đó, tham số hóa là một cách tiếp cận IMO tốt hơn một chút. – Isaac

+0

@Isaac, điểm tuyệt vời. Bạn có thể tạo một 'TraceStrategyFactory' lấy các đối tượng' CritStrategy' và 'FuncStrategy' và trả về một đối tượng hỗn hợp gồm hai đối tượng đó ... nhưng điểm của bạn về việc ghép hai hàm này là rất apropos – Dancrumb

+0

Có. Tôi đồng ý rằng một sự kết hợp của mô hình chiến lược & tham số hóa sẽ là phù hợp nhất cho nhu cầu của OP tổng thể. – Isaac

1

Bạn có thể làm trace chức năng công việc này chỉ tốt trong Java bằng cách kết hợp một vài kỹ thuật:

  • Thay vì "con trỏ chức năng", các thông số của bạn funccrit nên thể hiện đối tượng mà thực hiện một giao diện cụ thể. Sau đó bạn có thể gọi một hàm trong giao diện này trên đối tượng i. Trong thực tế, đây là một mẫu Vistor với hai tham số vistor khác nhau.
  • Bạn cũng cần một số cách để đi qua cây. Bạn có thể thực hiện một Iterator - điều này mang lại cho bạn một cách tốt đẹp để đi qua toàn bộ cấu trúc. Hoặc bạn có thể làm cho trace đệ quy (nó tự gọi mình trên nhánh trái và phải của cây) và sau đó bạn sẽ không cần một trình lặp.

Phiên bản iterator sẽ giống như thế này:

public void trace(IFunction func, ICriteria crit) { 
    for (T i: this) { 
     func.call(i); 
     if (crit.test(i)) return; 
    } 
} 

Đây T là loại mục của bộ sưu tập, và calltest là các định nghĩa chức năng trong giao diện IFunctionICriteria tương ứng.

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