2015-05-26 13 views
5

Tôi gặp vấn đề về thiết kế trong một tiện ích chung mà chúng tôi sử dụng trong dự án Java của chúng tôi nơi tôi muốn đảm bảo rằng tất cả người gọi của một phương pháp cụ thể A được bao bọc bởi phương pháp khác B. Dạng chung của mã này như tôi đã viết hôm nay là:đảm bảo ngăn xếp cuộc gọi của một phương thức luôn bao gồm một phương thức khác trong Java

x.B(new Runnable() { 
    y.A(); 
}); 

Runnable đang được B thực hiện có thể có mã tùy ý, và có thể gọi A nhiều lần, vì vậy tôi không thể loại bỏ các runnable trong mã này bằng cách thêm các cuộc gọi đến A trực tiếp vào B. Ngoài ra, A là mã của bên thứ ba, vì vậy chúng tôi không thể sửa đổi nó. Có thể là runnable có thể gọi B một lần nữa với một cuộc gọi lồng nhau đến A, nhưng hôm nay điều đó không bao giờ xảy ra vì vậy tôi ok bỏ qua trường hợp đó ngay bây giờ.

Tôi thấy một vài lựa chọn:

  1. Khai A() throws BlahException và làm cho nó để B là catcher duy nhất của ngoại lệ đó. Điều này là xấu bởi vì không có bất kỳ ngoại lệ nào nên thực sự được ném, nhưng nó tốt đẹp bởi vì trình biên dịch sẽ đảm bảo phân cấp cuộc gọi cho tôi.
  2. Viết một số loại công cụ phân tích tĩnh để đảm bảo quy tắc này cho tôi. Tôi đã không điều tra trường hợp này nhiều, nhưng nó có vẻ như công việc nhiều hơn bất cứ điều gì khác (nhưng có thể có một công cụ từ trước có thể làm điều này?).
  3. Thêm xác nhận vào "đầu A" (thực sự, mã này sẽ phải hoạt động trong phiên bản Runnble tùy chỉnh vì tôi không thể sửa đổi trực tiếp) mà chúng tôi đang chạy bên trong cuộc gọi đến B. Điều này có thể hoặc sử dụng một số trạng thái thread-/object-local bổ sung hoặc duyệt qua ngăn xếp cuộc gọi, cả hai đều xấu xí.

Có các tùy chọn nào khác mà tôi chưa xem xét không?

+1

Đây là một mô hình rất chống. Phương pháp 'A' không nên quan tâm ai gọi nó. Tại sao bạn nghĩ rằng bạn cần phải làm điều này? –

+1

Bạn đã thử sử dụng mẫu Proxy chưa? – MaxZoom

+0

@KevinKrumwiede - Có thể cho cả hai 'A' là bất khả tri của người gọi của nó và dự án muốn tất cả các cuộc gọi đến' A' được bao bọc. –

Trả lời

2

Bạn đã cân nhắc sử dụng AspectJ hoặc một số công cụ lập trình hướng-khía cạnh khác (AOP)? Sau đó, bạn có thể chặn mọi cuộc gọi của phương thức A, kiểm tra phương thức B trong ngăn xếp. Nếu nó không có, bạn có thể ném ngoại lệ ngăn chặn thực hiện A, hoặc viết một lỗi để đăng nhập, hoặc làm bất cứ điều gì bạn thích. Một cái gì đó như thế này:

@Aspect 
public class CheckInsideMethodBAspect { 

    @Around("execution(* com.example.AClass.A(..))") 
    public void checkNestedMethod(ProceedingJoinPoint joinPoint) { 

     // checking for method B in the call stack 
     boolean isInsideB = false; 
     StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 
     for (StackTraceElement element: stackTraceElements) { 
      if (element.getClassName().equals("ClassB") && element.getMethodName().equals("B")) { 
       isInsideB = true; 
       break; 
      } 
     } 

     // if not inside B, throwing exception 
     if (!isInsideB) { 
      throw new NotInsideBException(); 
     } 

     // if inside B, then proceeding with method A execution 
     joinPoint.proceed(); 
    } 

} 
+1

Bất kể lý do nào đằng sau yêu cầu phương thức 'B' nằm trong ngăn xếp cuộc gọi - nghĩa là bất kỳ phương thức' B' nào quan trọng đến vậy - có thể đạt được trực tiếp với phương pháp này, để 'B' ra khỏi nó. –

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