Көйгөй тууралуу көбүрөөк маалымат
Биринчиден, эски системанын жүрүм-турумун окшоштуралы. Бул жумушка же мектепке кечигип калуу себептерин жаратат дейли. Бул үчүн бизде , жана ыкмаларынExcuse
камтыган интерфейс бар . generateExcuse()
likeExcuse()
dislikeExcuse()
public interface Excuse {
String generateExcuse();
void likeExcuse(String excuse);
void dislikeExcuse(String excuse);
}
Бул интерфейс класс тарабынан ишке ашырылат 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) {
// Удаляем элемент из массива
}
}
Мисалды сынап көрөлү:
Excuse excuse = new WorkExcuse();
System.out.println(excuse.generateExcuse());
Жыйынтык:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице.
Прошу меня извинить за непрофессиональное поведение.
Эми сиз кызматты ишке киргизип, статистиканы чогултуп, кызматты колдонуучулардын көбү университеттин студенттери экенин байкадыңыз деп элестетип көрөлү. Аны бул топтун муктаждыктары үчүн жакшыртуу үчүн, сиз башка иштеп чыгуучудан ал үчүн атайын шылтоо түзүү системасын буйрутма бергенсиз. Иштеп чыгуучу топ изилдөө жүргүздү, рейтингдерди түздү, жасалма интеллектти туташтырды, тыгындар, аба ырайы жана башкалар менен интеграцияны кошту. Эми сизде студенттер үчүн шылтоолорду түзүү үчүн китепканаңыз бар, бирок аны менен иштешүү интерфейси башкача - StudentExcuse
:
public interface StudentExcuse {
String generateExcuse();
void dislikeExcuse(String excuse);
}
Интерфейстин эки ыкмасы бар: generateExcuse
, шылтоо жаратуучу жана dislikeExcuse
, шылтоо келечекте пайда болбошу үчүн бөгөт коюу. Үчүнчү тараптын китепканасы түзөтүү үчүн жабык - анын баштапкы codeун өзгөртө албайсыз. Натыйжада, сиздин системаңызда интерфейсти ишке ашырган эки класс жана интерфейсти ишке ашырган Excuse
классы бар китепкана бар : SuperStudentExcuse
StudentExcuse
public class SuperStudentExcuse implements StudentExcuse {
@Override
public String generateExcuse() {
// Логика нового функционала
return "Невероятная отговорка, адаптированная под текущее состояние погоды, пробки or сбои в расписании общественного транспорта.";
}
@Override
public void dislikeExcuse(String excuse) {
// Добавляет причину в черный список
}
}
Кодду өзгөртүү мүмкүн эмес. Учурдагы схема төмөнкүдөй болот: Системанын бул versionсы Excuse интерфейси менен гана иштейт. Кодду кайра жаза албайсыз: чоң тиркемеде мындай өзгөртүүлөр көп убакытка созулушу же колдонмонун логикасын бузушу мүмкүн. Сиз негизги интерфейсти киргизүүнү жана иерархияны көбөйтүүнү сунуштай аласыз: Бул үчүн интерфейстин атын өзгөртүү керек Excuse
. Бирок олуттуу колдонмолордо кошумча иерархия жагымсыз: жалпы тамыр элементин киргизүү архитектураны бузат. Сиз жаңы жана эски функцияларды минималдуу жоготуу менен колдонууга мүмкүндүк берүүчү орто классты ишке ашырышыңыз керек. Кыскасы, сизге адаптер керек .
Адаптердин үлгүсү кантип иштейт
Адаптер - бул бир an object боюнча методдорго чалууларды экинчисине түшүнүктүү кылган аралык an object. Биздин мисал үчүн адаптерди ишке ашырып, аны чакыралыMiddleware
. Биздин адаптер an objectтердин бирине шайкеш келген интерфейсти ишке ашырышы керек. Ошондой болсун Excuse
. Мунун аркасында Middleware
биринчи an objectтин ыкмаларын чакыра алат. Middleware
чалууларды кабыл алат жана аларды шайкеш форматта экинчи an objectке өткөрүп берет. Middleware
Методдор менен ыкманы ишке ашыруу мына ушундай generateExcuse
жана көрүнөт 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 появятся позже
}
Сыноо (кардар codeунда):
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()); // Адаптер вызывает адаптированный метод
}
}
Жыйынтык:
Обычная причина для работника:
Я сегодня опоздал, потому что предпраздничное настроение замедляет метаболические процессы в моем организме и приводит к подавленному состоянию и бессоннице.
Нет оправдания моему поступку. Я недостоин этой должности.
Использование нового функционала с помощью адаптера
Учурдагы аба ырайына, тыгындарга же коомдук транспорттун графигиндеги үзгүлтүккө ылайыкталган укмуштуудай шылтоо. Метод generateExcuse
чалууну кошумча трансформациясыз башка an objectке өткөрүп берет. Метод dislikeExcuse
адегенде шылтоону маалымат базасынын кара тизмесине киргизүүнү талап кылды. Кошумча аралык маалымат иштетүү Адаптер үлгүсү эмне үчүн сүйүктүү себеби болуп саналат. likeExcuse
Бирок интерфейсте Excuse
жок, бирок интерфейсте болгон ыкма жөнүндө эмне айтууга болот StudentExcuse
? Бул операция жаңы функцияда колдоого алынbyte. Мындай учурда, алар бир өзгөчөлүк менен келишти UnsupportedOperationException
: ал суралган операция колдоого алынбаса, ыргытылат. Муну колдонолу. Бул жаңы классты ишке ашыруунун көрүнүшү 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.
}
}
Бир караганда, бул чечим ийгorктүү көрүнбөйт, бирок функцияны симуляциялоо татаалыраак кырдаалга алып келиши мүмкүн. кардар кунт коюп жана адаптер жакшы documentтештирилген болсо, бул чечим кабыл алынат.
Адаптерди качан колдонуу керек
-
Эгер сиз үчүнчү жактын классын колдонушуңуз керек болсо, бирок анын интерфейси негизги тиркеме менен шайкеш келбейт. Жогорудагы мисалда чалууларды максаттуу an object үчүн түшүнүктүү форматта ороп турган чип an objectинин кантип түзүлгөнү көрсөтүлгөн.
-
Качан бир нече бар подкласстар жалпы функцияга ээ болушу керек. Кошумча класстардын ордуна (алардын түзүлүшү codeдун кайталанышына алып келет), адаптерди колдонуу жакшы.
Артыкчылыктары жана кемчorктери
Артыкчылыгы: Адаптер кардардан бир an objectтен экинчисине суроо-талаптарды иштетүү деталдарын жашырат. Кардар codeу маалыматтарды форматтоо же максаттуу ыкмага чалууларды башкаруу жөнүндө ойлонбойт. Бул өтө татаал, ал эми программисттер жалкоо :) Кемчorги: Долбоордун codeдук базасы кошумча класстар менен татаалданган, ал эми бири-бирине дал келбеген пункттардын саны көп болсо, алардын саны башкарылгыс өлчөмдөргө чейин өсүшү мүмкүн.Фасад жана жасалгалоочу менен чаташтырбоо керек
Үстүртөн кароодон кийин, Адаптерди Фасад жана Декоратор үлгүлөрү менен чаташтырууга болот. Адаптер менен Фасаддын айырмасы, Фасад жаңы интерфейсти киргизип, бүтүндөй подсистеманы камтыйт. Декоратор, адаптерден айырмаланып, интерфейсти эмес, an objectтин өзүн өзгөртөт.Этап-этабы менен ишке ашыруу алгоритми
-
Биринчиден, бул үлгү чече ала турган көйгөй бар экенин текшериңиз.
-
Башка класс колдонула турган кардар интерфейсин аныктаңыз.
-
Мурунку кадамда аныкталган интерфейстин негизинде адаптер классын ишке ашырыңыз.
-
Адаптер классында an objectке шилтемени сактаган талааны түзүңүз. Бул шилтеме конструктордо өткөрүлөт.
-
Адаптерде кардар интерфейсинин бардык ыкмаларын ишке ашырыңыз. Метод болот:
-
Чалууну өзгөртүүсүз өткөрүү;
-
Маалыматтарды өзгөртүү, максаттуу ыкмага чалуулардын санын көбөйтүү/азайтуу, маалыматтардын курамын андан ары кеңейтүү ж.б.
-
Акыркы чара катары, эгер белгилүү бир ыкма шайкеш келбесе, UnsupportedOperationException ыргытыңыз, ал катуу documentтештирorши керек.
-
-
Эгерде тиркеме адаптерди кардар интерфейси аркылуу гана колдонсо (жогоруда көрсөтүлгөндөй), бул адаптерлерди келечекте оорутпай узартууга мүмкүндүк берет.
GO TO FULL VERSION