JavaRush /Java blogi /Random-UZ /Proksi dizayn namunasi

Proksi dizayn namunasi

Guruhda nashr etilgan
Dasturlashda dastur arxitekturasini to'g'ri rejalashtirish muhim ahamiyatga ega. Buning uchun ajralmas vosita dizayn naqshlari. Bugun biz Proksi yoki boshqacha qilib aytganda, Deputat haqida gaplashamiz.

Nega sizga deputat kerak?

Ushbu naqsh ob'ektga boshqariladigan kirish bilan bog'liq muammolarni hal qilishga yordam beradi. Sizda savol tug'ilishi mumkin: "Nima uchun bizga bunday boshqariladigan kirish kerak?" Keling, nima ekanligini aniqlashga yordam beradigan bir nechta vaziyatlarni ko'rib chiqaylik.

1-misol

Tasavvur qilaylik, bizda ma'lumotlar bazasidan hisobotlarni yuklab olish uchun mas'ul bo'lgan sinf mavjud eski kodlar to'plamiga ega katta loyihamiz bor. Sinf sinxron ishlaydi, ya'ni ma'lumotlar bazasi so'rovni qayta ishlayotganda butun tizim bo'sh qoladi. Hisobot o'rtacha 30 daqiqada tuziladi. Bu xususiyat tufayli uni yuklash soat 00:30 da boshlanadi va rahbariyat bu hisobotni ertalab oladi. Tahlil davomida ma'lum bo'lishicha, hisobot tuzilgandan so'ng darhol, ya'ni bir kun ichida qabul qilinishi kerak. Boshlanish vaqtini qayta rejalashtirish mumkin emas, chunki tizim ma'lumotlar bazasidan javob kutadi. Yechim yuklash va hisobot yaratishni alohida mavzuda boshlash orqali ishlash printsipini o'zgartirishdir. Ushbu yechim tizimning odatdagidek ishlashiga imkon beradi va rahbariyat yangi hisobotlarni oladi. Biroq, muammo bor: joriy kodni qayta yozib bo'lmaydi, chunki uning funktsiyalari tizimning boshqa qismlari tomonidan qo'llaniladi. Bunday holda, siz o'rinbosar namunasi yordamida oraliq proksi-klassni joriy qilishingiz mumkin, u hisobotni yuklash, boshlanish vaqtini qayd etish va alohida mavzuni ishga tushirish so'rovini oladi. Hisobot yaratilganda, ip o'z ishini yakunlaydi va hamma xursand bo'ladi.

2-misol

Rivojlanish guruhi afisha veb-saytini yaratadi. Yangi voqealar haqida ma'lumot olish uchun ular uchinchi tomon xizmatiga murojaat qilishadi, ular bilan o'zaro aloqa maxsus yopiq kutubxona orqali amalga oshiriladi. Rivojlanish jarayonida muammo yuzaga keldi: uchinchi tomon tizimi ma'lumotlarni kuniga bir marta yangilaydi va foydalanuvchi har safar sahifani yangilaganida unga so'rov paydo bo'ladi. Bu ko'p sonli so'rovlarni keltirib chiqaradi va xizmat javob berishni to'xtatadi. Yechim xizmat javobini keshlash va har bir qayta yuklashda tashrif buyuruvchilarga saqlangan natijani taqdim etish, kerak bo'lganda ushbu keshni yangilashdir. Bunday holda, o'rinbosar naqshidan foydalanish tugallangan funksiyani o'zgartirmasdan ajoyib echimdir.

Shakl qanday ishlaydi

Ushbu naqshni amalga oshirish uchun siz proksi-klassni yaratishingiz kerak. U mijoz kodi uchun xatti-harakatlarini taqlid qilib, xizmat ko'rsatish sinfi interfeysini amalga oshiradi. Shunday qilib, haqiqiy ob'ekt o'rniga mijoz o'z proksi bilan o'zaro aloqada bo'ladi. Odatda, barcha so'rovlar xizmat sinfiga uzatiladi, lekin qo'ng'iroq qilishdan oldin yoki keyin qo'shimcha harakatlar bilan. Oddiy qilib aytganda, bu proksi ob'ekt mijoz kodi va maqsadli ob'ekt o'rtasidagi qatlamdir. Juda sekin eski diskdan so'rovni keshlash misolini ko'rib chiqaylik. Ish printsipini o'zgartirib bo'lmaydigan qadimiy dasturda bu elektr poezdlar jadvali bo'lsin. Yangilangan jadvalga ega disk har kuni belgilangan vaqtda kiritiladi. Shunday qilib, bizda:
  1. Interfeys TimetableTrains.
  2. TimetableElectricTrainsUshbu interfeysni amalga oshiradigan sinf .
  3. Aynan shu sinf orqali mijoz kodi disk fayl tizimi bilan o'zaro ta'sir qiladi.
  4. Mijoz sinfi DisplayTimetable. Uning usuli printTimetable()ning usullaridan foydalanadi TimetableElectricTrains.
Sxema oddiy: Proksi dizayn namunasi - 2Hozirgi vaqtda har safar metod chaqirilganda printTimetable()sinf TimetableElectricTrainsdiskka kirishadi, ma'lumotlarni yuklaydi va mijozga beradi. Bu tizim yaxshi ishlaydi, lekin juda sekin. Shu sababli, keshlash mexanizmini qo'shish orqali tizim ish faoliyatini oshirishga qaror qilindi. Buni proksi-server namunasi yordamida amalga oshirish mumkin: Proksi dizayn namunasi - 3Shunday qilib, sinf oldingi DisplayTimetablesinf bilan emas, balki sinf bilan o'zaro aloqada ekanligini sezmaydi . TimetableElectricTrainsProxyYangi dastur jadvalni kuniga bir marta yuklaydi va takroriy so'rovlar bo'lsa, allaqachon yuklangan ob'ektni xotiradan qaytaradi.

Qaysi vazifalar uchun proksi-serverdan foydalanish yaxshiroq?

Mana, bu naqsh albatta yordam beradigan bir nechta vaziyatlar:
  1. Keshlash.
  2. Lazy amalga oshirish, shuningdek, dangasa amalga oshirish sifatida ham tanilgan. Nega ob'ektni bir vaqtning o'zida yuklash kerak, agar kerak bo'lsa, uni yuklashingiz mumkin?
  3. So'rovlarni ro'yxatga olish.
  4. Vaqtinchalik ma'lumotlar va kirish tekshiruvlari.
  5. Parallel ishlov berish iplarini ishga tushirish.
  6. Qo'ng'iroqlar tarixini yozib olish yoki hisoblash.
Boshqa foydalanish holatlari ham mavjud. Ushbu naqshning ishlash printsipini tushunib, siz o'zingiz uchun muvaffaqiyatli dasturni topishingiz mumkin. Bir qarashda, Deputat Fasad bilan bir xil narsani qiladi , lekin u emas. Proksi xizmat ko'rsatish ob'ekti bilan bir xil interfeysga ega. Bundan tashqari, naqshni Decorator yoki Adapter bilan aralashtirib yubormang . Dekorator kengaytirilgan interfeysni, adapter esa muqobil interfeysni taqdim etadi.

Afzalliklar va kamchiliklar

  • + Xizmat ob'ektiga kirishni xohlaganingizcha boshqarishingiz mumkin;
  • + Xizmat ko'rsatish ob'ektining hayot aylanishini boshqarish uchun qo'shimcha imkoniyatlar;
  • + Xizmat ko'rsatish ob'ektisiz ishlaydi;
  • + Kod ishlashi va xavfsizligini yaxshilaydi.
  • - qo'shimcha muolajalar tufayli ishlashning yomonlashishi xavfi mavjud;
  • -Dastur darslarining tuzilishini murakkablashtiradi.

Amalda o'rnini bosuvchi naqsh

Keling, siz bilan diskdan poezdlar jadvalini o'qiy oladigan tizimni joriy qilaylik:
public interface TimetableTrains {
   String[] getTimetable();
   String getTrainDepartureTime();
}
Asosiy interfeysni amalga oshiradigan sinf:
public class TimetableElectricTrains implements TimetableTrains {

   @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 "";
   }
}
Har safar barcha poezdlar jadvalini olishga harakat qilganingizda, dastur faylni diskdan o'qiydi. Ammo bu hali ham gullar. Fayl faqat bitta poyezd uchun jadvalni olishingiz kerak bo'lganda har safar o'qiladi! Bunday kod faqat yomon misollarda mavjudligi yaxshi :) Mijoz klassi:
public class DisplayTimetable {
   private TimetableTrains timetableTrains = new TimetableElectricTrains();

   public void printTimetable() {
       String[] timetable = timetableTrains.getTimetable();
       String[] tmpArr;
       System.out.println("Поезд\tОткуда\tКуда\t\tВремя отправления\tВремя прибытия\tВремя в пути");
       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]);
       }
   }
}
Misol fayl:

9B-6854;Лондон;Прага;13:43;21:15;07:32
BA-1404;Париж;Грац;14:25;21:25;07:00
9B-8710;Прага;Вена;04:48;08:49;04:01;
9B-8122;Прага;Грац;04:48;08:49;04:01
Keling, sinab ko'raylik:
public static void main(String[] args) {
   DisplayTimetable displayTimetable = new DisplayTimetable();
   displayTimetable.printTimetable();
}
Xulosa:

Поезд  Откуда  Куда   Время отправления Время прибытия    Время в пути
9B-6854  Лондон  Прага    13:43         21:15         07:32
BA-1404  Париж   Грац   14:25         21:25         07:00
9B-8710  Прага   Вена   04:48         08:49         04:01
9B-8122  Прага   Грац   04:48         08:49         04:01
Endi naqshimizni amalga oshirish bosqichlarini ko'rib chiqamiz:
  1. Asl ob'ekt o'rniga yangi proksi-serverdan foydalanish imkonini beruvchi interfeysni belgilang. Bizning misolimizda shunday TimetableTrains.

  2. Proksi-klass yarating. Unda xizmat ko'rsatish ob'ektiga havola bo'lishi kerak (sinfda yaratish yoki konstruktorda o'tish);

    Mana bizning proksi sinfimiz:

    public class TimetableElectricTrainsProxy implements TimetableTrains {
       // Ссылка на оригинальный an object
       private TimetableTrains timetableTrains = new TimetableElectricTrains();
    
       private String[] timetableCache = null
    
       @Override
       public String[] getTimetable() {
           return timetableTrains.getTimetable();
       }
    
       @Override
       public String getTrainDepartureTime(String trainId) {
           return timetableTrains.getTrainDepartureTime(trainId);
       }
    
       public void clearCache() {
           timetableTrains = null;
       }
    }

    Ushbu bosqichda biz shunchaki asl ob'ektga havola bilan sinf yaratamiz va unga barcha qo'ng'iroqlarni o'tkazamiz.

  3. Biz proksi-server sinfining mantiqini amalga oshiramiz. Asosan qo'ng'iroq har doim asl ob'ektga yo'naltiriladi.

    public class TimetableElectricTrainsProxy implements TimetableTrains {
       // Ссылка на оригинальный an object
       private TimetableTrains timetableTrains = new TimetableElectricTrains();
    
       private String[] timetableCache = null
    
       @Override
       public String[] getTimetable() {
           if(timetableCache == null) {
               timetableCache = timetableTrains.getTimetable();
           }
           return timetableCache;
       }
    
       @Override
       public String getTrainDepartureTime(String trainId) {
           if(timetableCache == null) {
               timetableCache = timetableTrains.getTimetable();
           }
           for(int i = 0; i < timetableCache.length; i++) {
               if(timetableCache[i].startsWith(trainId+";")) return timetableCache[i];
           }
           return "";
       }
    
       public void clearCache() {
           timetableTrains = null;
       }
    }

    Usul getTimetable()jadval massivining xotirada keshlanganligini tekshiradi. Agar yo'q bo'lsa, u natijani saqlagan holda diskdan ma'lumotlarni yuklash uchun so'rov yuboradi. Agar so'rov allaqachon ishlayotgan bo'lsa, u ob'ektni xotiradan tezda qaytaradi.

    Oddiy funksionalligi tufayli getTrainDepartireTime() usulini asl ob'ektga yo'naltirish shart emas edi. Biz shunchaki uning funksionalligini yangi usulga ko'chirdik.

    Siz buni qila olmaysiz. Agar siz kodni takrorlashingiz yoki shunga o'xshash manipulyatsiyalarni bajarishingiz kerak bo'lsa, demak, biror narsa noto'g'ri ketdi va siz muammoga boshqa tomondan qarashingiz kerak. Bizning oddiy misolimizda boshqa yo'l yo'q, lekin haqiqiy loyihalarda, ehtimol, kod yanada to'g'ri yoziladi.

  4. Mijoz kodidagi asl ob'ekt yaratilishini almashtirish ob'ekti bilan almashtiring:

    public class DisplayTimetable {
       // Измененная link
       private TimetableTrains timetableTrains = new TimetableElectricTrainsProxy();
    
       public void printTimetable() {
           String[] timetable = timetableTrains.getTimetable();
           String[] tmpArr;
           System.out.println("Поезд\tОткуда\tКуда\t\tВремя отправления\tВремя прибытия\tВремя в пути");
           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]);
           }
       }
    }

    Imtihon

    
    Поезд  Откуда  Куда   Время отправления Время прибытия    Время в пути
    9B-6854  Лондон  Прага    13:43         21:15         07:32
    BA-1404  Париж   Грац   14:25         21:25         07:00
    9B-8710  Прага   Вена   04:48         08:49         04:01
    9B-8122  Прага   Грац   04:48         08:49         04:01

    Ajoyib, u to'g'ri ishlaydi.

    Bundan tashqari, muayyan shartlarga qarab asl ob'ektni ham, o'zgartirish ob'ektini ham yaratadigan zavodni ko'rib chiqishingiz mumkin.

Nuqta o'rniga foydali havola

  1. Naqshlar haqida ajoyib maqola va "Deputat" haqida bir oz

Bugun hammasi shu! O'rganishga qaytib, yangi bilimlaringizni amalda sinab ko'rsangiz yaxshi bo'lardi :)
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION