Problem haqqında ətraflı məlumat
Əvvəlcə köhnə sistemin davranışını simulyasiya edək. Deyək ki, bu, işə və ya məktəbə gecikmək üçün səbəblər yaradır. Bunun üçün , vəExcuse
üsullarını ehtiva edən bir interfeysimiz var . generateExcuse()
likeExcuse()
dislikeExcuse()
public interface Excuse {
String generateExcuse();
void likeExcuse(String excuse);
void dislikeExcuse(String excuse);
}
Bu interfeys sinif tərəfindən həyata keçirilir WorkExcuse
:
public class WorkExcuse implements Excuse {
private String[] reasonOptions = {"по невероятному стечению обстоятельств у нас в доме закончилась горячая вода и я ждал, пока солнечный свет, сконцентрированный через лупу, нагреет кружку воды, чтобы я мог умыться.",
"искусственный интеллект в моем будильнике подвел меня и разбудил на час раньше обычного. Поскольку сейчас зима, я думал что еще ночь и уснул. Дальше все How в тумане.",
"предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице."};
private String[] sorryOptions = {"Это, конечно, не повторится, мне очень жаль.", "Прошу меня извинить за непрофессиональное поведение.", "Нет оправдания моему поступку. Я недостоин этой должности."};
@Override
public String generateExcuse() { // Случайно выбираем отговорку из массива
String result = "Я сегодня опоздал, потому что " + reasonOptions[(int) Math.round(Math.random() + 1)] + "\n" +
sorryOptions[(int) Math.round(Math.random() + 1)];
return result;
}
@Override
public void likeExcuse(String excuse) {
// Дублируем элемент в массиве, чтобы шанс его выпадения был выше
}
@Override
public void dislikeExcuse(String excuse) {
// Удаляем элемент из массива
}
}
Nümunəni sınaqdan keçirək:
Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
Nəticə:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице.
Прошу меня извинить за непрофессиональное поведение.
İndi təsəvvür edək ki, siz xidməti işə saldınız, statistika topladınız və xidmət istifadəçilərinin əksəriyyətinin universitet tələbələri olduğunu gördünüz. Onu bu qrupun ehtiyacları üçün təkmilləşdirmək üçün siz onun üçün başqa bir tərtibatçıdan bəhanə yaratma sistemi sifariş etdiniz. İnkişaf qrupu araşdırma apardı, reytinqlər tərtib etdi, süni intellekti birləşdirdi, tıxaclar, hava şəraiti və s. ilə inteqrasiyanı əlavə etdi. İndi tələbələr üçün bəhanələr yaratmaq üçün kitabxananız var, lakin onunla qarşılıqlı əlaqə üçün interfeys fərqlidir - StudentExcuse
:
public interface StudentExcuse {
String generateExcuse();
void dislikeExcuse(String excuse);
}
İnterfeysdə iki üsul var: generateExcuse
, bəhanə yaradan və dislikeExcuse
, bəhanənin gələcəkdə görünməməsi üçün onu bloklayan. Üçüncü tərəf kitabxanası redaktə üçün bağlıdır - onun mənbə kodunu dəyişə bilməzsiniz. Nəticədə, sisteminizdə interfeysi həyata keçirən iki sinif və interfeysi həyata keçirən Excuse
sinfi olan bir kitabxana var : SuperStudentExcuse
StudentExcuse
public class SuperStudentExcuse implements StudentExcuse {
@Override
public String generateExcuse() {
// Логика нового функционала
return "Невероятная отговорка, адаптированная под текущее состояние погоды, пробки or сбои в расписании общественного транспорта.";
}
@Override
public void dislikeExcuse(String excuse) {
// Добавляет причину в черный список
}
}
Kod dəyişdirilə bilməz. Cari sxem belə görünəcək: Sistemin bu versiyası yalnız Bəhanə interfeysi ilə işləyir. Kodu yenidən yaza bilməzsiniz: böyük bir tətbiqdə bu cür dəyişikliklər uzun müddət çəkə və ya tətbiq məntiqini poza bilər. Siz əsas interfeysi təqdim etməyi və iyerarxiyanı artırmağı təklif edə bilərsiniz: Bunu etmək üçün interfeysin adını dəyişmək lazımdır Excuse
. Ancaq ciddi tətbiqlərdə əlavə iyerarxiya arzuolunmazdır: ümumi kök elementin təqdim edilməsi arxitekturanı pozur. Yeni və köhnə funksionallığı minimum itki ilə istifadə etməyə imkan verəcək ara sinif tətbiq etməlisiniz. Bir sözlə, bir adapter lazımdır .
Adapter nümunəsi necə işləyir
Adapter bir obyektdə metodlara edilən zəngləri digərinə başa düşülən edən ara obyektdir. Nümunəmiz üçün bir adapter tətbiq edək və onu çağıraqMiddleware
. Adapterimiz obyektlərdən biri ilə uyğun gələn interfeysi həyata keçirməlidir. Qoy olsun Excuse
. Bunun sayəsində Middleware
birinci obyektin metodlarını çağıra bilir. Middleware
zəngləri qəbul edir və onları uyğun formatda ikinci obyektə ötürür. Middleware
Metodlarla metodun tətbiqi belədir generateExcuse
və belə görünür dislikeExcuse
:
public class Middleware implements Excuse { // 1. Middleware становится совместимым с an objectом WorkExcuse через интерфейс Excuse
private StudentExcuse superStudentExcuse;
public Middleware(StudentExcuse excuse) { // 2. Получаем ссылку на адаптируемый an object
this.superStudentExcuse = excuse;
}
@Override
public String generateExcuse() {
return superStudentExcuse.generateExcuse(); // 3. Адаптер реализовывает метод интерфейса
}
@Override
public void dislikeExcuse(String excuse) {
// Метод предварительно помещает отговорку в черный список БД,
// Затем передает ее в метод dislikeExcuse an object superStudentExcuse.
}
// Метод likeExcuse появятся позже
}
Test (müştəri kodunda):
public class Test {
public static void main(String[] args) {
Excuse excuse = new WorkExcuse(); // Создаются an objectы классов,
StudentExcuse newExcuse = new SuperStudentExcuse(); // Которые должны быть совмещены.
System.out.println("Обычная причина для работника:");
System.out.println(excuse.generateExcuse());
System.out.println("\n");
Excuse adaptedStudentExcuse = new Middleware(newExcuse); // Оборачиваем новый функционал в an object-адаптер
System.out.println("Использование нового функционала с помощью адаптера:");
System.out.println(adaptedStudentExcuse.generateExcuse()); // Адаптер вызывает адаптированный метод
}
}
Nəticə:
Обычная причина для работника:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице.
Нет оправдания моему поступку. Я недостоин этой должности.
Использование нового функционала с помощью адаптера
Mövcud hava şəraitinə, tıxaclara və ya ictimai nəqliyyatın hərəkət cədvəlindəki pozuntulara uyğunlaşdırılmış inanılmaz bəhanə. Metod generateExcuse
əlavə çevrilmələr etmədən çağırışı sadəcə başqa obyektə ötürür. Metod dislikeExcuse
əvvəlcə bəhanənin verilənlər bazası qara siyahısına salınmasını tələb edirdi. Əlavə aralıq məlumat emalı Adapter modelinin sevilməsinin səbəbidir. likeExcuse
Bəs interfeysdə olan Excuse
, lakin içində olmayan üsul haqqında nə demək olar StudentExcuse
? Bu əməliyyat yeni funksionallıqda dəstəklənmir. Bu halda, onlar bir istisna ilə gəldilər UnsupportedOperationException
: tələb olunan əməliyyat dəstəklənmirsə atılır. Gəlin bundan istifadə edək. Yeni sinif tətbiqi belə görünür Middleware
:
public class Middleware implements Excuse {
private StudentExcuse superStudentExcuse;
public Middleware(StudentExcuse excuse) {
this.superStudentExcuse = excuse;
}
@Override
public String generateExcuse() {
return superStudentExcuse.generateExcuse();
}
@Override
public void likeExcuse(String excuse) {
throw new UnsupportedOperationException("Метод likeExcuse не поддерживается в новом функционале");
}
@Override
public void dislikeExcuse(String excuse) {
// Метод обращается за дополнительной информацией к БД,
// Затем передает ее в метод dislikeExcuse an object superStudentExcuse.
}
}
İlk baxışdan bu həll uğurlu görünmür, lakin funksionallığın simulyasiyası daha mürəkkəb vəziyyətə gətirib çıxara bilər. Müştəri diqqətlidirsə və adapter yaxşı sənədləşdirilibsə, bu həll məqbuldur.
Adapterdən nə vaxt istifadə edilməlidir
-
Üçüncü tərəf sinfindən istifadə etmək lazımdırsa, lakin onun interfeysi əsas proqrama uyğun gəlmir. Yuxarıdakı nümunə zəngləri hədəf obyekt üçün başa düşülən formatda əhatə edən şim obyektinin necə yaradıldığını göstərir.
-
Bir neçə mövcud alt sinif ümumi funksionallığa malik olmalıdır. Əlavə alt siniflər əvəzinə (onların yaradılması kodun təkrarlanmasına səbəb olacaq) adapterdən istifadə etmək daha yaxşıdır.
Yaxşı və pis tərəfləri
Üstünlük: Adapter bir obyektdən digərinə sorğuların işlənməsinin təfərrüatlarını müştəridən gizlədir. Müştəri kodu məlumatların formatlaşdırılması və ya hədəf metoduna edilən zənglərin idarə edilməsi haqqında düşünmür. Bu, çox mürəkkəbdir, proqramçılar isə tənbəldirlər :) Dezavantaj: Layihənin kod bazası əlavə siniflərlə mürəkkəbdir və çoxlu sayda uyğun olmayan nöqtələr varsa, onların sayı idarə olunmayan ölçülərə qədər arta bilər.Fasad və Dekorator ilə qarışdırılmamalıdır
Səthi yoxlamadan sonra Adapter Fasad və Dekorator nümunələri ilə qarışdırıla bilər. Adapterlə Fasad arasındakı fərq ondan ibarətdir ki, Fasad yeni interfeys təqdim edir və bütün alt sistemi əhatə edir. Yaxşı, Dekorator, Adapterdən fərqli olaraq, interfeysi deyil, obyektin özünü dəyişir.Addım-addım həyata keçirmə alqoritmi
-
Birincisi, bu nümunənin həll edə biləcəyi bir problem olduğundan əmin olun.
-
Başqa bir sinifin adından istifadə ediləcəyi müştəri interfeysini müəyyənləşdirin.
-
Əvvəlki addımda müəyyən edilmiş interfeys əsasında adapter sinfini həyata keçirin.
-
Adapter sinfində obyektə istinad saxlayan sahə yaradın. Bu istinad konstruktorda ötürülür.
-
Adapterdə bütün müştəri interfeysi üsullarını tətbiq edin. Metod ola bilər:
-
Zəngi dəyişdirmədən köçürmək;
-
Məlumatların dəyişdirilməsi, hədəf metoduna edilən zənglərin sayını artırmaq/azaltmaq, verilənlərin tərkibini daha da genişləndirmək və s.
-
Son çarə olaraq, müəyyən bir üsul uyğun gəlmirsə, ciddi şəkildə sənədləşdirilməli olan UnsupportedOperationException atın.
-
-
Tətbiq yalnız müştəri interfeysi vasitəsilə adapterdən istifadə edərsə (yuxarıdakı nümunədə olduğu kimi), bu, adapterlərin gələcəkdə ağrısız şəkildə uzadılmasına imkan verəcəkdir.
GO TO FULL VERSION