CodeGym /Blog Java /rawak /Corak reka bentuk proksi
John Squirrels
Tahap
San Francisco

Corak reka bentuk proksi

Diterbitkan dalam kumpulan
Dalam pengaturcaraan, adalah penting untuk merancang seni bina aplikasi anda dengan betul. Corak reka bentuk adalah cara yang sangat diperlukan untuk mencapai ini. Hari ini mari kita bercakap tentang proksi.

Mengapa anda memerlukan proksi?

Corak ini membantu menyelesaikan masalah yang berkaitan dengan akses terkawal kepada objek. Anda mungkin bertanya, "Mengapa kami memerlukan akses terkawal?" Mari lihat beberapa situasi yang akan membantu anda mengetahui apa itu.

Contoh 1

Bayangkan kita mempunyai projek besar dengan sekumpulan kod lama, di mana terdapat kelas yang bertanggungjawab untuk mengeksport laporan daripada pangkalan data. Kelas berfungsi serentak. Iaitu, keseluruhan sistem melahu sementara pangkalan data memproses permintaan. Secara purata, ia mengambil masa 30 minit untuk menghasilkan laporan. Sehubungan itu, proses eksport bermula pada 12:30 AM, dan pihak pengurusan menerima laporan pada waktu pagi. Audit mendedahkan bahawa adalah lebih baik untuk menerima laporan dengan segera pada waktu perniagaan biasa. Masa mula tidak boleh ditangguhkan, dan sistem tidak boleh menyekat sementara ia menunggu respons daripada pangkalan data. Penyelesaiannya ialah mengubah cara sistem berfungsi, menjana dan mengeksport laporan pada urutan yang berasingan. Penyelesaian ini akan membolehkan sistem berfungsi seperti biasa dan pengurusan akan menerima laporan baharu. Walau bagaimanapun, terdapat masalah: kod semasa tidak boleh ditulis semula, kerana bahagian lain sistem menggunakan fungsinya. Dalam kes ini, kita boleh menggunakan corak proksi untuk memperkenalkan kelas proksi perantaraan yang akan menerima permintaan untuk mengeksport laporan, log masa mula dan melancarkan urutan yang berasingan. Setelah laporan dijana, rangkaian ditamatkan dan semua orang gembira.

Contoh 2

Pasukan pembangunan sedang mencipta tapak web acara. Untuk mendapatkan data tentang acara baharu, pasukan bertanyakan perkhidmatan pihak ketiga. Perpustakaan persendirian khas memudahkan interaksi dengan perkhidmatan. Semasa pembangunan, masalah ditemui: sistem pihak ketiga mengemas kini datanya sekali sehari, tetapi permintaan dihantar kepadanya setiap kali pengguna memuat semula halaman. Ini menghasilkan sejumlah besar permintaan, dan perkhidmatan berhenti bertindak balas. Penyelesaiannya adalah untuk cache respons perkhidmatan dan mengembalikan hasil cache kepada pelawat apabila halaman dimuatkan semula, mengemas kini cache seperti yang diperlukan. Dalam kes ini, corak reka bentuk proksi adalah penyelesaian terbaik yang tidak mengubah fungsi sedia ada.

Prinsip di sebalik corak reka bentuk

Untuk melaksanakan corak ini, anda perlu membuat kelas proksi. Ia melaksanakan antara muka kelas perkhidmatan, meniru tingkah lakunya untuk kod klien. Dengan cara ini, pelanggan berinteraksi dengan proksi dan bukannya objek sebenar. Sebagai peraturan, semua permintaan dihantar ke kelas perkhidmatan, tetapi dengan tindakan tambahan sebelum atau selepas. Ringkasnya, proksi ialah lapisan antara kod klien dan objek sasaran. Pertimbangkan contoh caching hasil pertanyaan daripada cakera keras lama dan sangat perlahan. Katakan kita bercakap tentang jadual untuk kereta api elektrik dalam beberapa aplikasi purba yang logiknya tidak boleh diubah. Cakera dengan jadual waktu yang dikemas kini dimasukkan setiap hari pada masa yang tetap. Jadi, kami ada:
  1. TrainTimetableantara muka.
  2. ElectricTrainTimetable, yang melaksanakan antara muka ini.
  3. Kod klien berinteraksi dengan sistem fail melalui kelas ini.
  4. TimetableDisplaykelas pelanggan. Kaedahnya printTimetable()menggunakan kaedah kelas ElectricTrainTimetable.
Gambar rajah adalah mudah: Corak reka bentuk proksi: - 2Pada masa ini, dengan setiap panggilan kaedah printTimetable(), ElectricTrainTimetablekelas mengakses cakera, memuatkan data, dan membentangkannya kepada pelanggan. Sistem berfungsi dengan baik, tetapi ia sangat perlahan. Akibatnya, keputusan dibuat untuk meningkatkan prestasi sistem dengan menambah mekanisme caching. Ini boleh dilakukan menggunakan corak proksi: Corak reka bentuk proksi: - 3Oleh itu, TimetableDisplaykelas tidak menyedari bahawa ia berinteraksi dengan kelas ElectricTrainTimetableProxydan bukannya kelas lama. Pelaksanaan baharu memuatkan jadual waktu sekali sehari. Untuk permintaan ulangan, ia mengembalikan objek yang dimuatkan sebelum ini daripada memori.

Apakah tugas yang terbaik untuk proksi?

Berikut ialah beberapa situasi di mana corak ini pasti berguna:
  1. Caching
  2. Permulaan tertangguh atau malas Mengapa memuatkan objek dengan segera jika anda boleh memuatkannya mengikut keperluan?
  3. Permintaan pembalakan
  4. Pengesahan perantaraan data dan akses
  5. Memulakan benang pekerja
  6. Merakam akses kepada objek
Dan terdapat juga kes penggunaan lain. Memahami prinsip di sebalik corak ini, anda boleh mengenal pasti situasi di mana ia boleh digunakan dengan jayanya. Pada pandangan pertama, proksi melakukan perkara yang sama seperti fasad , tetapi bukan itu yang berlaku. Proksi mempunyai antara muka yang sama dengan objek perkhidmatan . Juga, jangan kelirukan corak ini dengan corak penghias atau Penyesuai . Penghias menyediakan antara muka lanjutan, dan penyesuai menyediakan antara muka alternatif.

Kelebihan dan kekurangan

  • + Anda boleh mengawal akses kepada objek perkhidmatan mengikut kehendak anda
  • + Kebolehan tambahan yang berkaitan dengan menguruskan kitaran hayat objek perkhidmatan
  • + Ia berfungsi tanpa objek perkhidmatan
  • + Ia meningkatkan prestasi dan keselamatan kod.
  • - Terdapat risiko bahawa prestasi mungkin menjadi lebih teruk disebabkan permintaan tambahan
  • - Ia menjadikan hierarki kelas lebih rumit

Corak proksi dalam amalan

Mari kita laksanakan sistem yang membaca jadual waktu kereta api daripada cakera keras:

public interface TrainTimetable {
   String[] getTimetable();
   String getTrainDepartureTime();
}
Berikut ialah kelas yang melaksanakan antara muka 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 mendapat jadual waktu kereta api, program membaca fail dari cakera. Tetapi itu hanya permulaan masalah kami. Keseluruhan fail dibaca setiap kali anda mendapat jadual waktu untuk kereta api tunggal! Adalah baik bahawa kod sedemikian wujud hanya dalam contoh perkara yang tidak boleh dilakukan :) Kelas pelanggan:

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 fail:

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();
}
Pengeluaran:

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 ikuti langkah-langkah yang diperlukan untuk memperkenalkan corak kami:
  1. Tentukan antara muka yang membenarkan penggunaan proksi dan bukannya objek asal. Dalam contoh kami, ini adalah TrainTimetable.

  2. Buat kelas proksi. Ia sepatutnya mempunyai rujukan kepada objek perkhidmatan (buat dalam kelas atau hantar kepada pembina).

    Inilah kelas proksi 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 peringkat ini, kami hanya mencipta kelas dengan rujukan kepada objek asal dan memajukan semua panggilan kepadanya.

  3. Mari kita laksanakan logik kelas proksi. Pada asasnya, panggilan sentiasa diubah hala ke objek asal.

    
    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;
       }
    }
    

    Semakan getTimetable()sama ada tatasusunan jadual waktu telah dicache dalam ingatan. Jika tidak, ia menghantar permintaan untuk memuatkan data dari cakera dan menyimpan hasilnya. Jika jadual waktu telah diminta, ia cepat mengembalikan objek dari ingatan.

    Terima kasih kepada fungsi mudahnya, kaedah getTrainDepartureTime() tidak perlu diubah hala ke objek asal. Kami hanya menduplikasi fungsinya dalam kaedah baharu.

    Jangan buat begini. Jika anda perlu menduplikasi kod atau melakukan sesuatu yang serupa, maka sesuatu telah berlaku, dan anda perlu melihat masalah itu semula dari sudut yang berbeza. Dalam contoh mudah kami, kami tidak mempunyai pilihan lain. Tetapi dalam projek sebenar, kod kemungkinan besar akan ditulis dengan lebih betul.

  4. Dalam kod klien, buat objek proksi dan bukannya objek asal:

    
    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]);
           }
       }
    }
    

    Semak

    
    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, ia berfungsi dengan betul.

    Anda juga boleh mempertimbangkan pilihan kilang yang mencipta kedua-dua objek asal dan objek proksi, bergantung pada syarat tertentu.

Sebelum kami mengucapkan selamat tinggal, berikut adalah pautan yang berguna

Itu sahaja untuk hari ini! Bukan idea yang buruk untuk kembali ke pelajaran dan mencuba pengetahuan baharu anda dalam amalan :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION