CodeGym /Java Blog /Acak /Pola desain proxy
John Squirrels
Level 41
San Francisco

Pola desain proxy

Dipublikasikan di grup Acak
Dalam pemrograman, penting untuk merencanakan arsitektur aplikasi Anda dengan benar. Pola desain adalah cara yang sangat diperlukan untuk mencapai hal ini. Hari ini mari kita bicara tentang proxy.

Mengapa Anda membutuhkan proxy?

Pola ini membantu memecahkan masalah yang terkait dengan akses terkontrol ke suatu objek. Anda mungkin bertanya, "Mengapa kita membutuhkan akses terkontrol?" Mari kita lihat beberapa situasi yang akan membantu Anda mengetahui apa itu.

Contoh 1

Bayangkan kita memiliki proyek besar dengan sekumpulan kode lama, di mana ada kelas yang bertanggung jawab untuk mengekspor laporan dari database. Kelas bekerja secara sinkron. Artinya, seluruh sistem tidak aktif saat database memproses permintaan. Rata-rata, dibutuhkan waktu 30 menit untuk menghasilkan laporan. Dengan demikian, proses ekspor dimulai pukul 12.30, dan manajemen menerima laporan pada pagi hari. Audit mengungkapkan bahwa akan lebih baik untuk dapat segera menerima laporan selama jam kerja normal. Waktu mulai tidak dapat ditunda, dan sistem tidak dapat memblokir saat menunggu respons dari database. Solusinya adalah mengubah cara kerja sistem, membuat dan mengekspor laporan di utas terpisah. Solusi ini akan membuat sistem berfungsi seperti biasa, dan manajemen akan menerima laporan baru. Namun, ada masalah: kode saat ini tidak dapat ditulis ulang, karena bagian lain dari sistem menggunakan fungsinya. Dalam hal ini, kita dapat menggunakan pola proxy untuk memperkenalkan kelas proxy perantara yang akan menerima permintaan untuk mengekspor laporan, mencatat waktu mulai, dan meluncurkan utas terpisah. Setelah laporan dibuat, utas diakhiri dan semua orang senang.

Contoh 2

Tim pengembangan sedang membuat situs web acara. Untuk mendapatkan data tentang acara baru, tim meminta layanan pihak ketiga. Perpustakaan pribadi khusus memfasilitasi interaksi dengan layanan. Selama pengembangan, masalah ditemukan: sistem pihak ketiga memperbarui datanya sekali sehari, tetapi permintaan dikirim ke sana setiap kali pengguna menyegarkan halaman. Ini menciptakan banyak permintaan, dan layanan berhenti merespons. Solusinya adalah meng-cache respons layanan dan mengembalikan hasil cache ke pengunjung saat halaman dimuat ulang, memperbarui cache sesuai kebutuhan. Dalam hal ini, pola desain proxy adalah solusi terbaik yang tidak mengubah fungsionalitas yang ada.

Prinsip di balik pola desain

Untuk menerapkan pola ini, Anda perlu membuat kelas proxy. Itu mengimplementasikan antarmuka kelas layanan, meniru perilakunya untuk kode klien. Dengan cara ini, klien berinteraksi dengan proxy alih-alih objek sebenarnya. Sebagai aturan, semua permintaan diteruskan ke kelas layanan, tetapi dengan tindakan tambahan sebelum atau sesudahnya. Sederhananya, proxy adalah lapisan antara kode klien dan objek target. Pertimbangkan contoh hasil kueri caching dari hard disk lama dan sangat lambat. Misalkan kita berbicara tentang jadwal kereta listrik di beberapa aplikasi kuno yang logikanya tidak dapat diubah. Disk dengan jadwal yang diperbarui dimasukkan setiap hari pada waktu yang tetap. Jadi kita punya:
  1. TrainTimetableantarmuka.
  2. ElectricTrainTimetable, yang mengimplementasikan antarmuka ini.
  3. Kode klien berinteraksi dengan sistem file melalui kelas ini.
  4. TimetableDisplaykelas klien. Metodenya printTimetable()menggunakan metode kelas ElectricTrainTimetable.
Diagramnya sederhana: Pola desain proxy: - 2Saat ini, dengan setiap pemanggilan metode printTimetable(), ElectricTrainTimetablekelas mengakses disk, memuat data, dan mempresentasikannya ke klien. Sistem berfungsi dengan baik, tetapi sangat lambat. Akibatnya, keputusan dibuat untuk meningkatkan kinerja sistem dengan menambahkan mekanisme caching. Ini dapat dilakukan dengan menggunakan pola proxy: Pola desain proxy: - 3Dengan demikian, TimetableDisplaykelas bahkan tidak menyadari bahwa ia berinteraksi dengan kelas, ElectricTrainTimetableProxybukan dengan kelas lama. Implementasi baru memuat jadwal sekali sehari. Untuk permintaan berulang, ini mengembalikan objek yang dimuat sebelumnya dari memori.

Tugas apa yang terbaik untuk proxy?

Berikut adalah beberapa situasi di mana pola ini pasti berguna:
  1. Caching
  2. Tertunda, atau malas, inisialisasi Mengapa langsung memuat objek jika Anda dapat memuatnya sesuai kebutuhan?
  3. Mencatat permintaan
  4. Verifikasi antara data dan akses
  5. Memulai utas pekerja
  6. Merekam akses ke objek
Dan ada juga kasus penggunaan lainnya. Memahami prinsip di balik pola ini, Anda dapat mengidentifikasi situasi yang dapat diterapkan dengan sukses. Sekilas, proxy melakukan hal yang sama seperti fasad , tapi bukan itu masalahnya. Proksi memiliki antarmuka yang sama dengan objek layanan. Juga, jangan bingung pola ini dengan pola dekorator atau Adaptor . Dekorator menyediakan antarmuka tambahan, dan adaptor menyediakan antarmuka alternatif.

Keuntungan dan kerugian

  • + Anda dapat mengontrol akses ke objek layanan sesuka Anda
  • + Kemampuan tambahan yang terkait dengan pengelolaan siklus hidup objek layanan
  • + Ini berfungsi tanpa objek layanan
  • + Ini meningkatkan kinerja dan keamanan kode.
  • - Ada risiko kinerja menjadi lebih buruk karena permintaan tambahan
  • - Itu membuat hierarki kelas lebih rumit

Pola proxy dalam praktek

Mari terapkan sistem yang membaca jadwal kereta dari hard disk:

public interface TrainTimetable {
   String[] getTimetable();
   String getTrainDepartureTime();
}
Inilah kelas yang mengimplementasikan antarmuka utama:

public class ElectricTrainTimetable implements TrainTimetable {

   @Override
   public String[] getTimetable() {
       ArrayList<String> list = new ArrayList<>();
       try {
           Scanner scanner = new Scanner(new FileReader(new File("/tmp/electric_trains.csv")));
           while (scanner.hasNextLine()) {
               String line = scanner.nextLine();
               list.add(line);
           }
       } catch (IOException e) {
           System.err.println("Error:  " + e);
       }
       return list.toArray(new String[list.size()]);
   }

   @Override
   public String getTrainDepartureTime(String trainId) {
       String[] timetable = getTimetable();
       for (int i = 0; i < timetable.length; i++) {
           if (timetable[i].startsWith(trainId+";")) return timetable[i];
       }
       return "";
   }
}
Setiap kali Anda mendapatkan jadwal kereta, program membaca file dari disk. Tapi itu hanya awal dari masalah kita. Seluruh file dibaca setiap kali Anda mendapatkan jadwal bahkan untuk satu kereta! Ada baiknya kode seperti itu hanya ada dalam contoh yang tidak boleh dilakukan :) Kelas klien:

public class TimetableDisplay {
   private TrainTimetable trainTimetable = new ElectricTrainTimetable();

   public void printTimetable() {
       String[] timetable = trainTimetable.getTimetable();
       String[] tmpArr;
       System.out.println("Train\\tFrom\\tTo\\t\\tDeparture time\\tArrival time\\tTravel time");
       for (int i = 0; i < timetable.length; i++) {
           tmpArr = timetable[i].split(";");
           System.out.printf("%s\t%s\t%s\t\t%s\t\t\t\t%s\t\t\t%s\n", tmpArr[0], tmpArr[1], tmpArr[2], tmpArr[3], tmpArr[4], tmpArr[5]);
       }
   }
}
Contoh berkas:

9B-6854;London;Prague;13:43;21:15;07:32
BA-1404;Paris;Graz;14:25;21:25;07:00
9B-8710;Prague;Vienna;04:48;08:49;04:01;
9B-8122;Prague;Graz;04:48;08:49;04:01
Mari kita uji:

public static void main(String[] args) {
   TimetableDisplay timetableDisplay = new timetableDisplay();
   timetableDisplay.printTimetable();
}
Keluaran:

Train  From  To  Departure time  Arrival time  Travel time
9B-6854  London  Prague  13:43  21:15  07:32
BA-1404  Paris  Graz  14:25  21:25  07:00
9B-8710  Prague  Vienna  04:48  08:49  04:01
9B-8122  Prague  Graz  04:48  08:49  04:01
Sekarang mari kita telusuri langkah-langkah yang diperlukan untuk memperkenalkan pola kita:
  1. Tentukan antarmuka yang memungkinkan penggunaan proxy alih-alih objek aslinya. Dalam contoh kita, ini adalah TrainTimetable.

  2. Buat kelas proxy. Itu harus memiliki referensi ke objek layanan (buat di kelas atau berikan ke konstruktor).

    Inilah kelas proxy kami:

    
    public class ElectricTrainTimetableProxy implements TrainTimetable {
       // Reference to the original object
       private TrainTimetable trainTimetable = new ElectricTrainTimetable();
      
       private String[] timetableCache = null
    
       @Override
       public String[] getTimetable() {
           return trainTimetable.getTimetable();
       }
    
       @Override
       public String getTrainDepartureTime(String trainId) {
           return trainTimetable.getTrainDepartureTime(trainId);
       }
      
       public void clearCache() {
           trainTimetable = null;
       }
    }
    

    Pada tahap ini, kami hanya membuat kelas dengan referensi ke objek asli dan meneruskan semua panggilan ke sana.

  3. Mari terapkan logika kelas proxy. Pada dasarnya, panggilan selalu dialihkan ke objek aslinya.

    
    public class ElectricTrainTimetableProxy implements TrainTimetable {
       // Reference to the original object
       private TrainTimetable trainTimetable = new ElectricTrainTimetable();
    
       private String[] timetableCache = null
    
       @Override
       public String[] getTimetable() {
           if (timetableCache == null) {
               timetableCache = trainTimetable.getTimetable();
           }
           return timetableCache;
       }
    
       @Override
       public String getTrainDepartureTime(String trainId) {
           if (timetableCache == null) {
               timetableCache = trainTimetable.getTimetable();
           }
           for (int i = 0; i < timetableCache.length; i++) {
               if (timetableCache[i].startsWith(trainId+";")) return timetableCache[i];
           }
           return "";
       }
    
       public void clearCache() {
           trainTimetable = null;
       }
    }
    

    Pemeriksaan getTimetable()apakah larik jadwal telah di-cache di memori. Jika tidak, ia mengirimkan permintaan untuk memuat data dari disk dan menyimpan hasilnya. Jika jadwal telah diminta, dengan cepat mengembalikan objek dari memori.

    Berkat fungsinya yang sederhana, metode getTrainDepartureTime() tidak harus dialihkan ke objek aslinya. Kami hanya menggandakan fungsinya dalam metode baru.

    Jangan lakukan ini. Jika Anda harus menggandakan kode atau melakukan sesuatu yang serupa, maka terjadi kesalahan, dan Anda perlu melihat masalahnya lagi dari sudut yang berbeda. Dalam contoh sederhana kami, kami tidak punya pilihan lain. Namun dalam proyek nyata, kode kemungkinan besar akan ditulis dengan lebih benar.

  4. Dalam kode klien, buat objek proksi alih-alih objek aslinya:

    
    public class TimetableDisplay {
       // Changed reference
       private TrainTimetable trainTimetable = new ElectricTrainTimetableProxy();
    
       public void printTimetable() {
           String[] timetable = trainTimetable.getTimetable();
           String[] tmpArr;
           System.out.println("Train\\tFrom\\tTo\\t\\tDeparture time\\tArrival time\\tTravel time");
           for (int i = 0; i < timetable.length; i++) {
               tmpArr = timetable[i].split(";");
               System.out.printf("%s\t%s\t%s\t\t%s\t\t\t\t%s\t\t\t%s\n", tmpArr[0], tmpArr[1], tmpArr[2], tmpArr[3], tmpArr[4], tmpArr[5]);
           }
       }
    }
    

    Memeriksa

    
    Train  From  To  Departure time  Arrival time  Travel time
    9B-6854  London  Prague  13:43  21:15  07:32
    BA-1404  Paris  Graz  14:25  21:25  07:00
    9B-8710  Prague  Vienna  04:48  08:49  04:01
    9B-8122  Prague  Graz  04:48  08:49  04:01
    

    Hebat, ini bekerja dengan benar.

    Anda juga dapat mempertimbangkan opsi pabrik yang membuat objek asli dan objek proksi, bergantung pada kondisi tertentu.

Sebelum kami mengucapkan selamat tinggal, berikut adalah tautan yang bermanfaat

Itu saja untuk hari ini! Bukan ide yang buruk untuk kembali ke pelajaran dan mencoba pengetahuan baru Anda dalam praktik :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION