2013-04-26 18 views
5

Tôi đã sử dụng mẫu ủy quyền để bọc một đối tượng được tạo bởi một nhà máy trong thư viện của bên thứ ba. Gần đây, thư viện đã thêm một phương thức được bảo vệ trong lớp cơ sở và lớp trình bao bọc của tôi không còn hoạt động nữa. Có ai có một giải pháp tốt mà không cần phải suy nghĩ để phản ánh?Java: Mẫu ủy quyền và phương pháp được bảo vệ

Đây là trong thư viện bên thứ 3 và trong gói của họ,

public class Base { 
    public void foo(); 

    protected void bar(); // Newly added 
} 

này nằm trong gói của riêng tôi,

public class MyWrapper extends Base { 
    private Base delegate; 

    public MyWrapper(Base delegate) { 
     this.delegate = delegate; 
    } 

    public void foo() { 
     delegate.foo() 
    } 

    protected void bar() { 
     // Don't know what to do 
    } 
} 

EDIT: bài ban đầu của tôi là không rõ ràng. Hai lớp này nằm trong các gói khác nhau.

Để trả lời câu hỏi tại sao tôi cần ủy quyền. Đây là trường hợp sử dụng điển hình của mẫu Ủy quyền/Trình bao bọc và tôi không thể hiển thị nó ở đây trong một vài dòng mã. Thư viện trưng ra lớp cơ sở nhưng đối tượng thực sự từ nhà máy của chúng là lớp dẫn xuất của Base. Lớp thực tế thay đổi tùy thuộc vào cấu hình. Vì vậy, tôi không biết đại biểu là gì. Do đó mô hình kế thừa thẳng không hoạt động ở đây.

+0

Vâng, mục đích của phương pháp đó là gì? Bạn có thể bỏ qua nó không? Tôi đoán là không, khi bạn nói "không còn hoạt động nữa" ... bạn có thể gọi super.bar() không? Chỉ cần một shot vào màu xanh ... Bạn có bất cứ điều gì docu về phương pháp mới? – Fildor

+0

bạn đã cố gắng di chuyển lớp trình bao bọc của bạn thành một gói có cùng tên/đường dẫn hơn lớp cơ sở có ?? nó là một hack hơn là một giải pháp nhưng 'bảo vệ' phương pháp nên được truy cập trong cùng một gói –

+1

lớp cơ sở '' foo() 'và' bar() 'phương pháp trông giống như' Base' là một giao diện hoặc một lớp trừu tượng. Bạn có thể vui lòng chỉ định câu hỏi của bạn không? Bạn cần phản chiếu theo cách nào? Vì nó được bảo vệ, bạn có thể không cần phải ghi đè lên nó. –

Trả lời

4
Access Levels 
Modifier Class Package Subclass World 
public  Y   Y  Y   Y 
protected Y   Y  Y   N 
no modifier Y   Y  N   N 
private  Y   N  N   N 

protectedpackage truy cập quá, bạn có thấy bất kỳ vấn đề cụ thể với điều này:

class Base { 
     public void foo(){}; 

     protected void bar(){}; // Newly added 
    } 

    class MyWrapper { 
     private Base delegate; 

     public MyWrapper(Base delegate) { 
      this.delegate = delegate; 
     } 

     public void foo() { 
      delegate.foo(); 
     } 

     protected void bar() { 
      // Don't know what to do 
      delegate.bar(); //since its in same package, it can be referenced, do you expect compile time error? 
     } 
    } 

Tiếp tục trong khi sử dụng mô hình người ủy nhiệm tại sao lớp wrapper mở rộng Base lớp, tôi không thấy cần thiết phải cụ thể vì bạn đã có một phiên bản Base. Đối với tôi, nó có vẻ như là một người trang trí.

+0

Âm thanh hợp lý –

+0

Lớp Cơ sở nằm trong thư viện của bên thứ 3. Lớp của tôi ở trong một gói khác. –

+0

@ZZCoder bạn có thể tạo cùng một cấu trúc gói trong thư viện của riêng bạn và sau đó lớp trình bao bọc của bạn sẽ nằm trong gói _same_ như lớp 'Base', đó là loại hack và nó sẽ gây hiểu lầm cho mã máy khách của trình bao bọc của bạn , nhưng ít nhất nó sẽ cung cấp cho bạn quyền truy cập vào phương pháp được bảo vệ đó. Đó là ý tôi trong bình luận đầu tiên của tôi. –

1

Bạn không cần (hoặc không nên?) Ủy quyền cho phương thức thanh đó.

Nếu thư viện xác định phương thức được bảo vệ. Nó không muốn người dùng (tất nhiên trong gói khác nhau) để gọi phương thức đó, trừ khi tạo lớp con của loại đó. Bạn đang cố gắng phá vỡ quy tắc.

Nếu bạn muốn làm điều đó, có cách nào, bạn tạo một subtype của Base, nói SubBase, bạn tạo đối tượng của SubBase thay vì Base, sau đó vượt qua subBase để wrapper của bạn. sau đó bạn có thể trong wrapper của bạn bar() phương pháp viết delegate.bar() Bằng cách này, các SubBase thực sự là đại biểu, hoặc để nói wrapper của bạn được ủy SubBase không Base

Tôi nghĩ rằng bạn biết những gì tôi có ý nghĩa, vì vậy tôi chỉ không gõ mã ví dụ, chỉ dòng này tôi đoán là đủ:

//Wrapper 

private SubBase delegate; 

Bạn thấy trình bao bọc không cần thiết nữa nếu bạn có SubBase. Bạn thậm chí có thể xác định một số public void pubBar() trong số SubBase của mình và tại đó bạn gọi this.bar(). theo cách này, tất cả các đối tượng của SubBase đều có quyền truy cập vào phương thức được bảo vệ (via pubBar()), bất kể gói nào

+0

dovoter, xin cho lý do – Kent

1

Tôi có ấn tượng rằng lớp Base là giao diện hoặc lớp trừu tượng. Nếu vậy, bạn phải triển khai phương pháp bar(), ví dụ bằng cách sử dụng bất kỳ phương pháp nào trong số ba phương pháp được liệt kê bên dưới.

Side lưu ý, nếu Base là một lớp học bình thường, bạn không cần phải làm bất cứ điều gì (một cuộc gọi đến một thể hiện của MyWrapper.bar() thực sự sẽ dẫn đến một cuộc gọi đến Base.bar().


đại biểu cho đối tượng phụ huynh

Đây thường là một ý tưởng tốt nếu phương pháp bar() được sử dụng như một callback trong API bên thứ 3:

@Override 
protected void bar() { 
    delegate.bar(); 
} 

Không làm gì

Chỉ cần thêm một phương pháp có sản phẩm nào để tránh lỗi biên dịch:

@Override 
protected void bar() { 
    // silently ignored 
} 

Ném một ngoại lệ

dữ dội ngăn chặn bất kỳ việc sử dụng các mới phương pháp:

@Override 
protected void bar() { 
    throw new UnsupportedOperationException("not implemented"); 
} 

Là một mặt lưu ý, một cấu trúc mạnh mẽ hơn là để thích composition over inheritance để tách thực hiện của bạn từ việc thực hiện bên thứ 3, ví dụ

public class MyWrapper { // does not extend Base 
    private Base delegate; 

    public MyWrapper(Base delegate) { 
     this.delegate = delegate; 
    } 

    public void foo() { 
     delegate.foo() 
    } 

    // does not have to implement bar() 
} 
+0

Vì vậy, bạn cũng đang nói rằng ông không được ủy quyền 'bar'-Phương pháp, chính xác? Trong ví dụ của bạn, ông sẽ không có một sự lựa chọn nào. – Fildor

+0

@Fildor @ZZCoder Xem cập nhật của tôi. Vì lớp 'MyWrapper' thừa kế từ' Base' nó * phải * thực hiện phương thức 'bar()' nếu 'Base' là một lớp trừu tượng hoặc một giao diện. – matsev

+0

Có phải mở rộng 'Base' không? Nếu không, tôi sẽ đi cho wrapper matsev rằng tránh thừa kế. Nếu có, thì tất cả các khách hàng của bạn không biết về phương pháp mới, đúng không? Và tôi đoán bạn không đặt một tham chiếu đến nó vào lib bên thứ 3 ... vì vậy trong trường hợp đó tôi chỉ cần thực hiện một "giả" trống. – Fildor

0

Tôi đang sử dụng Spring để tiêm Wrapper "Đại biểu cơ sở" từ mô-đun khác và để ủy nhiệm tôi đang sử dụng nhà máy sản xuất pojo.

<bean id="interfaceDelegate" factory-bean="DelegatePojoFactory" 
    factory-method="getMyDelegateInstance"> 
    <constructor-arg index="0"> 
     <value>OnLine</value> 
    </constructor-arg> 
</bean> 

<bean id="wrapper" class="path.Wrapper"> 
     <property name="delegate" ref="interfaceDelegate"></property> 
</bean> 
0

Nếu bạn không cần người ủy nhiệm của bạn là một ví dụ thực tế của lớp cơ sở, bạn chỉ có thể loại bỏ mối quan hệ đó:

public class MyWrapper { 
    private Base delegate; 

    public MyWrapper(Base delegate) { 
     this.delegate = delegate; 
    } 

    public void foo() { 
     delegate.foo() 
    } 

} 

Cho dù làm việc cho bạn là phụ thuộc nhiều vào khác của bạn và nhu cầu của bạn không hoàn toàn rõ ràng với tôi ngay bây giờ. Nếu thư viện định nghĩa giao diện cung cấp phương thức công khai được lớp cơ sở trừu tượng triển khai, bạn có thể triển khai thực hiện giao diện đó một cách hợp lý mà không kế thừa từ lớp cơ sở trừu tượng, điều này cũng có thể đáp ứng nhu cầu của bạn.