Pola Desain Rantai Tanggung Jawab di Jawa

1. Perkenalan

Pada artikel ini, kita akan melihat pola desain perilaku yang banyak digunakan : Rantai Tanggung Jawab .

Kami dapat menemukan lebih banyak pola desain di artikel kami sebelumnya.

2. Rantai Tanggung Jawab

Wikipedia mendefinisikan Chain of Responsibility sebagai pola desain yang terdiri dari "sumber objek perintah dan serangkaian objek pemrosesan".

Setiap objek pemrosesan dalam rantai bertanggung jawab untuk jenis perintah tertentu, dan pemrosesan selesai, itu meneruskan perintah ke prosesor berikutnya dalam rantai.

Pola Rantai Tanggung Jawab berguna untuk:

  • Memisahkan pengirim dan penerima perintah
  • Memilih strategi pemrosesan pada waktu pemrosesan

Jadi, mari kita lihat contoh sederhana dari polanya.

3. Contoh

Kami akan menggunakan Chain of Responsibility untuk membuat rantai untuk menangani permintaan otentikasi.

Jadi, penyedia otentikasi input akan menjadi perintah , dan setiap prosesor otentikasi akan menjadi objek prosesor yang terpisah .

Mari pertama-tama buat kelas dasar abstrak untuk prosesor kita:

public abstract class AuthenticationProcessor { public AuthenticationProcessor nextProcessor; // standard constructors public abstract boolean isAuthorized(AuthenticationProvider authProvider); }

Selanjutnya, mari buat prosesor konkret yang memperluas AuthenticationProcessor :

public class OAuthProcessor extends AuthenticationProcessor { public OAuthProcessor(AuthenticationProcessor nextProcessor) { super(nextProcessor); } @Override public boolean isAuthorized(AuthenticationProvider authProvider) { if (authProvider instanceof OAuthTokenProvider) { return true; } else if (nextProcessor != null) { return nextProcessor.isAuthorized(authProvider); } return false; } }
public class UsernamePasswordProcessor extends AuthenticationProcessor { public UsernamePasswordProcessor(AuthenticationProcessor nextProcessor) { super(nextProcessor); } @Override public boolean isAuthorized(AuthenticationProvider authProvider) { if (authProvider instanceof UsernamePasswordProvider) { return true; } else if (nextProcessor != null) { return nextProcessor.isAuthorized(authProvider); } return false; } }

Di sini, kami membuat dua prosesor konkret untuk permintaan otorisasi yang masuk: UsernamePasswordProcessor dan OAuthProcessor .

Untuk masing-masing, kami mengganti metode isAuthorized .

Sekarang mari buat beberapa tes:

public class ChainOfResponsibilityTest { private static AuthenticationProcessor getChainOfAuthProcessor() { AuthenticationProcessor oAuthProcessor = new OAuthProcessor(null); return new UsernamePasswordProcessor(oAuthProcessor); } @Test public void givenOAuthProvider_whenCheckingAuthorized_thenSuccess() { AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor(); assertTrue(authProcessorChain.isAuthorized(new OAuthTokenProvider())); } @Test public void givenSamlProvider_whenCheckingAuthorized_thenSuccess() { AuthenticationProcessor authProcessorChain = getChainOfAuthProcessor(); assertFalse(authProcessorChain.isAuthorized(new SamlTokenProvider())); } }

Contoh di atas membuat rangkaian prosesor otentikasi: UsernamePasswordProcessor -> OAuthProcessor . Pada pengujian pertama, otorisasi berhasil, dan pengujian lainnya gagal.

Pertama, UsernamePasswordProcessor memeriksa untuk melihat apakah penyedia otentikasi adalah instance UsernamePasswordProvider .

Bukan masukan yang diharapkan, UsernamePasswordProcessor mendelegasikan ke OAuthProcessor .

Terakhir, OAuthProcessor memproses perintah tersebut. Pada tes pertama, ada pertandingan dan tes berhasil. Yang kedua, tidak ada lagi prosesor dalam rantai, dan akibatnya, pengujian gagal.

4. Prinsip Implementasi

Kami perlu mengingat beberapa prinsip penting saat menerapkan Rantai Tanggung Jawab:

  • Setiap prosesor dalam rantai akan memiliki implementasinya untuk memproses perintah
    • Dalam contoh kami di atas, semua prosesor menerapkan isAuthorized
  • Setiap prosesor dalam rangkaian harus memiliki referensi ke prosesor berikutnya
    • Di atas, UsernamePasswordProcessor didelegasikan ke OAuthProcessor
  • Setiap prosesor bertanggung jawab untuk mendelegasikan ke prosesor berikutnya, jadi waspadalah terhadap perintah yang dijatuhkan
    • Sekali lagi dalam contoh kami, jika perintah adalah turunan dari SamlProvider maka permintaan tersebut mungkin tidak diproses dan akan tidak sah
  • Prosesor tidak boleh membentuk siklus rekursif
    • Dalam contoh kami, kami tidak memiliki siklus dalam rantai kami: UsernamePasswordProcessor -> OAuthProcessor . Namun, jika kita secara eksplisit menetapkan UsernamePasswordProcessor sebagai prosesor OAuthProcessor berikutnya , maka kita berakhir dengan siklus dalam rantai kita : UsernamePasswordProcessor -> OAuthProcessor -> UsernamePasswordProcessor. Mengambil prosesor berikutnya dalam konstruktor dapat membantu dalam hal ini
  • Hanya satu prosesor dalam rantai yang menangani perintah yang diberikan
    • Dalam contoh kami, jika perintah masuk berisi instance OAuthTokenProvider , maka hanya OAuthProcessor yang akan menangani perintah tersebut.

5. Penggunaan di Dunia Nyata

Di dunia Jawa, kami mendapatkan keuntungan dari Chain of Responsibility setiap hari. Salah satu contoh klasik adalah Filter Servlet di Java yang memungkinkan beberapa filter untuk memproses permintaan HTTP. Meskipun demikian, setiap filter memanggil rantai, bukan filter berikutnya.

Mari kita lihat cuplikan kode di bawah ini untuk pemahaman yang lebih baik tentang pola ini di Filter Servlet :

public class CustomFilter implements Filter { public void doFilter( ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // process the request // pass the request (i.e. the command) along the filter chain chain.doFilter(request, response); } }

Seperti yang terlihat di potongan kode di atas, kita perlu untuk memanggil filterChain 's doFilter metode untuk lulus permintaan ke prosesor berikutnya dalam rantai.

6. Kekurangan

Dan sekarang setelah kita melihat betapa menariknya Rantai Tanggung Jawab, mari kita ingat beberapa kekurangannya:

  • Sebagian besar, itu dapat dengan mudah rusak:
    • jika prosesor gagal memanggil prosesor berikutnya, perintah akan dihapus
    • jika prosesor memanggil prosesor yang salah, ini dapat menyebabkan siklus
  • Ini dapat membuat pelacakan tumpukan dalam, yang dapat memengaruhi kinerja
  • Ini dapat menyebabkan kode duplikat di seluruh prosesor, meningkatkan pemeliharaan

7. Kesimpulan

Pada artikel ini, kami berbicara tentang Rantai Tanggung Jawab serta kekuatan dan kelemahannya dengan bantuan rantai untuk mengotorisasi permintaan otentikasi masuk.

Dan, seperti biasa, kode sumber dapat ditemukan di GitHub.