Кіріспе
Объектіге бағытталған бағдарламалаудағы дизайн үлгісі. Объектіге бағытталған бағдарламалауда декоратор үлгісі – бұл мінез-құлқыны жеке объектіге динамикалық түрде, сол кластың басқа даналарының мінез-құлқына әсер етпей қосуға мүмкіндік беретін дизайн үлгісі. Декоратор үлгісі көбінесе Бір жауапкершілік қағидасын сақтау үшін пайдалы, себебі ол функционалдықты ерекше мақсаттары бар кластар арасында бөлуге, сондай-ақ Ашық-Жабық қағидасына сәйкес келуге мүмкіндік береді, кластың функционалдығын өзгертпей кеңейтуге болатындықтан. Декораторды қолдану, жаңа кластар құруға қарағанда тиімдірек болуы мүмкін, өйткені объектінің мінез-құлқы толығымен жаңа объектіні анықтамай-ақ кеңейтілуі мүмкін.
In object oriented programming, the decorator pattern is a design pattern that allows behavior to be added to an individual object, dynamically, without affecting the behavior of other instances of the same class. The decorator pattern is often useful for adhering to the Single Responsibility Principle, as it allows functionality to be divided between classes with unique areas of concern as well as to the Open Closed Principle, by allowing the functionality of a class to be extended without being modified. Decorator use can be more efficient than subclassing, because an object's behavior can be augmented without defining an entirely new object.
Шолу
Декораторлық дизайн үлгісі – жиырма үш жақсы танымал дизайн үлгілерінің бірі; олар қайталанатын дизайн мәселелерін шешудің және икемді әрі қайта пайдалануға болатын объектіге бағытталған бағдарламалық құралдарды жасаудың жолдарын сипаттайды, яғни іске асыру, өзгерту, тестілеу және қайта қолдану оңай объектілерді.
Ол қандай проблемаларды шеше алады?
Жауапкершіліктер объектіге орындалу кезінде динамикалық түрде қосылуы және алынуы тиіс. Функционалдықты кеңейту үшін, мұраға алуға икемді балама ұсынылуы керек. Мұраға алуды пайдаланғанда, әртүрлі түбір сыныптар бір сыныпты әртүрлі жолдармен кеңейтеді. Бірақ кеңейту компиляция кезінде сыныпқа бекітіледі және орындалу кезінде өзгертілмейді.
Мотивация
Мысалы, терезелер жүйесіндегі терезелерді қарастырайық. Терезенің мазмұнын жылжытуға мүмкіндік беру үшін, қажет болған жағдайда, оған көлденең немесе тік прокрутка жолақтарын қосуға болады. Терезелер терезе интерфейсінің мысалдарымен бейнеленеді деп есептейік және бұл кластың прокрутка жолақтарын қосу мүмкіндігі жоқ деп есептейік. Оларды қамтамасыз ететін ScrollingWindow кіші класын немесе осы мүмкіндікті бар терезе нысандарына қосатын ScrollingWindowDecorator құрастыруға болады. Бұл жағдайда екі шешім де жарайды. Енді, егер біреу терезелерге шекаралар қосу мүмкіндігін де қаласа деп есептейік. Бастапқы Window класының мұндай мүмкіндігі жоқ. ScrollingWindow кіші класы енді қиындық тудырады, өйткені ол жаңа терезе түрін жасады. Егер біреу көптеген, бірақ барлық терезелерге емес, шекара қолдауын қосуды қаласа, онда WindowWithBorder және ScrollingWindowWithBorder сияқты кіші кластарды құру керек. Бұл мәселе әрбір жаңа мүмкіндік немесе терезе түрі қосылған сайын нашарлай түседі. Декоратор шешімі үшін жаңа BorderedWindowDecorator құрылады. ScrollingWindowDecorator немесе BorderedWindowDecorator кез келген комбинациясы бар терезелерді безендіре алады. Егер мүмкіндікті барлық терезелерге қосу қажет болса, базалық класты өзгертуге болады. Алайда, кейде (мысалы, сыртқы құралдарды пайдаланғанда) базалық класты өзгерту мүмкін емес, рұқсат етілмейді немесе ыңғайлы емес. Алдыңғы мысалда SimpleWindow және WindowDecorator кластары терезе басқаруын безендіру үшін осы сценарийде қажетті draw әдісін және getDescription әдісін анықтайтын Window интерфейсін іске асырады.
Жасалған безендірушілер
Команда бойынша декораторларды қосу немесе алып тастау (мәселен, батырманы басу арқылы) – бұл жиі кездесетін пайдаланушы интерфейсінің үлгісі, көбінесе Командалық дизайн үлгісімен бірге жүзеге асырылады. Мысалы, мәтінді өңдеу бағдарламасында мәтінді белгілеуге арналған батырма болуы мүмкін. Батырманы басқанда, қазіргі уақытта таңдалған мәтіндік символдардың барлығы олардың суреттеу функциясын өзгертетін декораторлармен оралады, нәтижесінде олар белгіленген күйде суреттеледі (нақты іске асыру тиімділікті арттыру үшін демаркация жүйесін де пайдалануы мүмкін). Күй өзгерістеріне байланысты декораторларды қолдану немесе алып тастау – тағы бір кең таралған қолданыс жағдайы. Күйдің ауқымына байланысты, декораторларды бірден бірнешеуін қолдануға немесе алып тастауға болады. Сол сияқты, Күй дизайн үлгісін өзгертілген функционалдықты қамтитын, бөлек сыныптар емес, декораторлар арқылы жүзеге асыруға болады. Осылайша декораторларды қолдану Күй нысанының ішкі күйін және функционалдығын құралымдық тұрғыдан жақсартады және кез келген күрделілікті басқаруға мүмкіндік береді.
Ұш салмақты нысандардағы қолдану
Flyweight дизайны үлгісінде безендіру жиі қолданылады. Flyweight объектілері екі компонентке бөлінеді: барлық Flyweight объектілері арасында ортақ инвариантты компонент; және ішінара ортақ немесе толығымен бөлек болатын, безендірілген компонент. Мұндай бөлу Flyweight объектісінің жадты тұтынуын азайтуға бағытталған. Декораторлар әдетте кэште сақталады және қайта қолданылады. Барлық декораторлар ортақ, өзгермейтін объектіге ортақ сілтемеге ие болады. Егер безендірілген күйі тек ішінара өзгерсе, онда декораторларды да белгілі бір деңгейде бөлісуге болады, бірақ оларды қолданған кезде олардың күйін өзгертпеуге көңіл болу керек. iOS-тағы UITableView осылайша Flyweight үлгісін іске асырады – кестелік көріністің қайта пайдаланылатын жасушалары ортақ кестелік көрініс қатарына сілтемелерді қамтитын декораторлар болып табылады, ал жасушалар кэшке сақталады / қайта қолданылады.
Декораторлармен байланыс орнатудағы кедергілер
Декораторлардың комбинацияларын әртүрлі жолдармен нысандар жинағына қолдану, жинақпен байланыс жасауда, декораторлардың қосымша функционалдығын толыққанды пайдалануға мүмкіндік беретіндей қиындықтар тудыруы мүмкін. Мұндай жағдайларда Адаптер немесе Келуші үлгілерін қолдану пайдалы болуы мүмкін. Бірнеше қабат декораторлармен байланыс орнату қосымша қиындықтар келтіреді, сондықтан Адаптерлер мен Келушілердің логикасы осыны ескеретіндей етіп жобалануы керек.
Архитектуралық маңызы
Декораторлар функционалдықты кеңейту үшін иерархиялық, жоғарыдан төменге қарайғы тәсілге емес, композициялық тәсілге қолдау көрсетеді. Декоратор интерфейстің мінез-құлқысын орындалу барысында қосуға немесе өзгертуге мүмкіндік береді. Оларды нысандарды көп қабатты, кез келген комбинацияда орау үшін пайдалануға болады. Ал, бұл әрекетті тұқымдық сыныптар арқылы жасау бірнеше мұрагерліктердің күрделі желісін құруға алып келеді, бұл жадты тиімсіз пайдаланады және белгілі бір деңгейден кейін кеңейту мүмкін болмайды. Сондай-ақ, қасиеттер арқылы сол функционалдықты іске асыруға тырысу, әр нысанды қажетсіз қасиеттермен ауырлатады. Аталған себептерге байланысты, декораторлар көбінесе тұқымдық сыныптарға қарағанда жадты тиімдірек балама болып саналады. Декораторларды тұқымдауға болмайтын нысандарды, олардың қасиеттерін орындалу кезінде өзгерту қажет болғанда (басқа жерде айтылғандай) немесе жалпы алғанда, кейбір қажетті функционалдылығы жетіспейтін нысандарды мамандандыру үшін де қолдануға болады.
API-ді жақсартуда пайдалану
Декоратор үлгісі Фасад үлгісін де толықтыра алады. Фасад тек оны қоршаған күрделі жүйемен байланысу үшін жасалған, бірақ ол жүйеге жаңа мүмкіндіктер қоспайды. Дегенмен, күрделі жүйенің қаптамасы жүйедегі кіші компоненттердің үйлестірілуіне негізделген жаңа мүмкіндіктерді енгізуге арналған кеңістік береді. Мысалы, Фасад үлгісі әртүрлі тілдердегі көптеген сөздіктерді бірнеше тілді сөздік интерфейсінің астында біріктіре алады. Жаңа интерфейс сондай-ақ тілдер арасында сөздерді аударуға арналған жаңа функцияларды қамтамасыз ете алады. Бұл гибридтік үлгі – біріктірілген интерфейс толықтыруға мүмкіндік береді. Декораторларды жеке нысандарды ғана емес, сонымен қатар гибридтік тәсілмен нысандар жиынтығын қаптауға қабілетті деп ойлаңыз.
C++ тілінде
Мұнда екі нұсқа ұсынылады: біріншісі – динамикалық, орындалу кезінде құрастырылатын декоратор (егер тікелей прокси арқылы шақырылмаса, декорацияланған функцияларды шақыруда мәселелер туындайды), екіншісі – миксин мұрагерлігін пайдаланатын декоратор.