Кіріспе
Жақсы анықталған функцияны қамтамасыз ететін кодты жазуға арналған қайта пайдаланылатын дизайн. Бағдарламалық жасақтауда, дизайн үлгісі компьютерлік бағдарламаның салыстырмалы түрде шағын, жақсы анықталған бөлігін (яғни функционалдығын) кодты қалай жазу тұрғысынан сипаттайды. Үлгіні қолданудың мақсаты – оны қайтадан ойлап табудың орнына, қолданыстағы түсінікті пайдалану болып табылады. Бұл бағдарламалық жасақтаманы әзірлеу уақытын қысқартуға және нәтижедегі бағдарламаның сапасын арттыруға мүмкіндік береді. Маңыздысы, үлгі – бұл бағдарламалық өнім емес. Бағдарламашы қолданатын көптеген даму ресурстары код базасын конфигурациялауды қамтиды, мысалы, кітапхана сияқты артефакттарды пайдалану (бір мысал келтірейік). Керісінше, үлгіні қолдану үшін бағдарламашы үлгіде сипатталғандай код жазады. Нәтиже әрқашан бірегей болады, тіпті нәтиже үлгіге негізделген болып танылса да. Кейбіреулер үлгілерді қолдануды бағдарламалық жасақтаманы жобалаудың ең жақсы тәжірибесі деп санайды. Ал кейбіреулер дизайн үлгілерін компьютерлік бағдарламалаудың құрылымдық тәсілі ретінде қарастырады. Теориялық тұрғыдан алғанда, дизайн үлгісі бағдарламалау парадигмасынан гөрі нақтырақ, ал алгоритмнен гөрі абстрактілірек деп сипаттауға болады.
In software engineering, a design pattern describes a relatively small, well defined aspect (i. e. functionality) of a computer program in terms of how to write the code. Using a pattern is intended to leverage an existing concept rather than re inventing it. This can decrease the time to develop software and increase the quality of the resulting program. Notably, a pattern does not consist of a software artifact. Most development resources that a programmer uses involve configuring the codebase to use an artifact such as a library (to name just one example). In contrast, to use a pattern, a programmer writes code as described by the pattern. The result is unique every time even though the result may be recognizable as based on the pattern. Some consider using patterns to be best practice for software design. Some consider using design patterns as a structured approach to computer programming. Conceptually, design pattern may be described as more specific than programming paradigm and less specific than algorithm.
Тарих
Үлгілер 1977 жылы Кристофер Александрдың сәулеттік тұжырымдамасы ретінде пайда болды (мысалы, "Көшелердің үлгісі", "ЖУРНАЛ АЙП", қыркүйек, 1966, 32-том, №5, 273–278 беттер). 1987 жылы Кент Бек және Уорд Каннингэм үлгілерді бағдарламалауға қолдану идеясын – әсіресе үлгілік тілдерді – тәжірибеден өткізе бастады және сол жылы OOPSLA конференциясында нәтижелерін ұсынды. Келесі жылдары Бек, Каннингэм және басқалар осы жұмысты жалғастырды. 1994 жылы "Төрттік" (Gamma et al.), жиі "GoF" деп қысқартылатын "Дизайн үлгілері: қайта пайдаланылатын объектілі бағдарламалық жасақтама элементтері" кітабы жарық көргеннен кейін дизайн үлгілері компьютерлік ғылымда кең танылды. Сол жылы бірінші Бағдарламалау тілдерінің үлгілері конференциясы өтті, ал келесі жылы дизайн үлгілерін құжаттау үшін Портленд үлгілері қоймасы құрылды. Бұл терминнің ауқымы әлі де даулы мәселе болып қалуда. Дизайн үлгілері жанрындағы танымал кітаптар:
Дизайн үлгілері көптен бері тәжірибеде қолданылып келсе де, осы тұжырымдаманы ресми түрде қалыптастыру бірнеше жылға созылды.
Практика
Дизайн үлгілері, дәлелденген даму парадигмаларын ұсына отырып, даму процесін жылдамдата алады. Тиімді бағдарламалық жасақтаманы жобалау үшін, іске асыру кезінде кейін ғана көрінетін мәселелерді ескеру қажет. Жаңадан жазылған кодта көрінбейтін, бірақ уақыт өте келе анықталатын, кейде үлкен проблемаларға әкелетін ұсақ-түйек мәселелер болуы мүмкін. Дизайн үлгілерін қайта пайдалану мұндай мәселелердің алдын алуға және осы үлгілермен таныс адамдар үшін кодты түсінуді жеңілдетуге көмектеседі. Бағдарламалық жасақтаманы жобалау техникаларын кең ауқымды мәселелерге қолдану қиын. Дизайн үлгілері, нақты бір мәселеге байланысты ерекшеліктерді қажет етпейтін форматта жазылған, жалпылама шешімдер ұсынады.
Нысан
Үлгі – бағдарлама құрауыштарының (мысалы, кластар, әдістер) жиынтығы және олардың өзара қатынастарын, яғни прототиптік микроархитектураны көрсетеді. Бағдарламашы үлгіде сипатталған мәселені шешу үшін осы үлгіні өз код базасына бейімдейді. Соның нәтижесінде алынған код таңдалған үлгіге ұқсас құрылым мен ұйымға ие болады.
Домендік үлгілер
Сондай-ақ, нақты бір салалардағы дизайн үлгілерін жүйелеуге күш-жігер жұмсалды, оның ішінде қолданыстағы дизайн үлгілерін және салаға тән дизайн үлгілерін пайдалану да қарастырылды. Мысалдарға пайдаланушы интерфейсі дизайн үлгілері, ақпаратты визуализациялау, қауіпсіздік дизайны, "қауіпсіз қолдану", веб-дизайн және бизнес-модель дизайны жатады. Жыл сайынғы Бағдарламалау тілдерінің үлгілері конференциясының материалдарында салаға тән үлгілердің көптеген мысалдары келтірілген.
Нысанға бағдарланған бағдарламалау
Объектіге бағытталған дизайн үлгілері әдетте кластар немесе объектілер арасындағы қатынастар мен өзара әрекеттесуді көрсетеді, бірақ қолданылатын соңғы кластар немесе объектілерді нақты көрсетпейді. Өзгертілетін күйге байланысты үлгілер функционалдық бағдарламалау тілдері үшін қолайсыз болуы мүмкін. Кейбір үлгілер оларды шешуге тырысатын мәселені шешуге арналған құралдары бар тілдерде қажетсіз болуы мүмкін, ал объектіге бағытталған үлгілер объектіге бағытталмаған тілдерге міндетті түрде сәйкес келмейді.
Мысалдар
Дизайн үлгілерін олар шешетін проблеманың түріне қарай топтастыруға болады. Жасау үлгілері объектілерді құрайды. Құрылымдық үлгілер кластар мен объектілерді ұйымдастырып, жаңа мүмкіндіктер беретін ірі құрылымдарды қалыптастырады. Мінез-құлқы үлгілері объектілер арасындағы байланысты қамтамасыз етеді және осы үлгілерді іске асыруға мүмкіндік береді.
Шығармашылық үлгілер
Атауы Сипаттама Дизайн үлгілерінде Кодта Толық басқа Абстракт фабрика Қатысты немесе тәуелді объектілердің отбасыларын нақты сыныптарын көрсетпей құруға мүмкіндік беретін интерфейс ұсынады. Құрылысшы Күрделі объектіні құру процесін оның өрнегінен бөліп, бір құрылыс процесі арқылы әртүрлі өрнектерді жасауға мүмкіндік береді. Тәуелділік инъекциясы Сынып объектіні тікелей құрудың орнына инжектордан қажетті объектілерді қабылдайды. Зауыт әдісі Бір объектіні құруға арналған интерфейсті анықтайды, бірақ субкласс қай сыныпты инстанциялау керектігін шешеді. Зауыт әдісі сыныптың инстанциялауын субклассқа қалдыруға мүмкіндік береді. Кешіктірілген инициализация Объектіні құруды, мәнді есептеуді немесе басқа да қымбат процестерді олар алғаш рет қажет болғанға дейін кешіктіру тактикасы. Бұл үлгі GoF каталогында "виртуалды прокси" ретінде, Прокси үлгісінің іске асыру стратегиясы ретінде келтірілген. Multiton Сыныптың тек атаулы инстанциялары бар екеніне кепілдік беріп, оларға жаһандық қол жеткізу нүктесін қамтамасыз етеді. Объектілер жиыны Пайдаланылмаған объектілерді қайта пайдалану арқылы қымбат ресурстарды алу және босатудан аулақ болыңыз. Қосылымдар мен жиектер жиынының жалпылама үлгісі ретінде қарастырылуы мүмкін. Прототип Прототиптік инстанцияны пайдаланып жасалатын объектілердің түрлерін анықтайды және қолданыстағы объектінің "негізінде" жаңа объектілерді құру арқылы өнімділікті арттырып, жадты үнемдейді. Ресурсты алу – инициализация (RAII) Ресурстарды тиісінше босатуды қамтамасыз ету үшін оларды сәйкес объектілердің өмір сүру циклімен байланыстырады. Синглтон Сыныптың тек бір ғана инстанциясы бар екеніне кепілдік беріп, оған жаһандық қол жеткізу нүктесін қамтамасыз етеді.
Әдеп-тәрбие үлгілері
Атауы Сипаттамасы Құрылымдық үлгілерде Кодта Басқа белсенді нысан Өзінің басқару тізбегінде орналасқан әдіс шақырудан әдіс орындауын ажыратады. Мақсаты – асинхронды әдіс шақыруды және сұрауларды өңдеу үшін жоспарлауды пайдалану арқылы бірқатарлылықты енгізу. Балкинг Объект белгілі бір күйде болған кезде ғана объектіге әрекет етеді. Байланысты қасиеттер Бірнеше бақылаушыларды біріктіріп, әртүрлі нысандардың қасиеттерін қандай да бір жолмен синхрондауға немесе үйлестіруге мәжбүрлейді. Есептеу ядросы Параллельде бірнеше рет бірдей есептеу, бүтақталмаған сілтеме математикасымен ортақ массивтерге, мысалы GPU-ға оңтайландырылған матрица көбейту немесе конволюциялық нейрондық желіге қолданылатын бүтін параметрлермен айырмашылығы бар. Екі рет тексерілген құлыптау Бұғаттау критерийін ("құлыптау нұсқауы") қауіпсіз емес түрде сынап, құлыптауды алудың жалпы шығынын азайту; егер бұл сәтті болса, ғана нақты құлыптау логикасы жалғасады. Кейбір тіл/аппараттық комбинацияларда іске асырылған кезде қауіпсіз болмауы мүмкін. Сондықтан оны кейде анти-үлгі деп қарастыруға болады. Оқиғаға негізделген асинхронды Көп тірісті бағдарламаларда туындайтын асинхронды үлгідегі проблемаларды шешеді. Қадағалаулы күту Операцияны орындау үшін құлыптауды және алдын ала шартты қанағаттандыруды талап ететін операцияларды басқарады. Қосылу Үлгісі хабарламаларды беру арқылы бір мезгілде, қатар және үлестірілген бағдарламаларды жазудың жолын ұсынады. Тақырыптар мен тізбектерді пайдаланумен салыстырғанда, бұл жоғары деңгейдегі бағдарламалау моделі. Құлыптау Бір тізбек ресурсқа "құлыптау" қояды, басқа тізбектердің оған кіруіне немесе оны өзгертуіне кедергі жасайды. PoEAA Сеансқа арналған тізбек деп те аталады. Тізбек шоғыры Бірнеше тапсырмаларды орындау үшін бірнеше тізбектер құрылады, олар әдетте кезекке орналастырылады. Әдетте, тапсырмалар тізбектерден көп болады. Объекттер жинағына арналған үлгінің ерекше жағдайы ретінде қарастыруға болады. Тізбекке тән сақтау Тізбекке жергілікті статикалық немесе "жаһандық" жад. Эксклюзивті меншікпен қауіпсіз бірқатарлылық, бірқатарлылық механизмдерінің қажеттілігін болдырмау, өйткені эксклюзивті меншік дәлелденуі мүмкін. Бұл Rust тілінің ерекше қабілеті, бірақ компиляция уақытын тексеру ғана емес, бағдарламашы мұндай үлгілерді кодқа қолмен жобалайды, өйткені бағдарламашы берілген айнымалыға ешқашан бірқатарлы қол жеткізілмейді деп бағалайды. CPU атомдық операциясы x86 және басқа CPU архитектуралары бастапқы мәндерді (толық сандарды) өзгерту және оларға қол жеткізу үшін жад қауіпсіздігін қамтамасыз ететін атомдық нұсқаулардың қатарын қолдайды. Мысалы, екі тізбек те санаушыны қауіпсіз түрде арттыруы мүмкін. Бұл мүмкіндіктер жоғарыда көрсетілген басқа да бірқатарлылық үлгілері үшін тетіктерді іске асыру үшін де пайдаланылуы мүмкін. C# тілінде бұл мүмкіндіктер үшін Interlocked класы қолданылады.
Құжаттамалық
Құрастыру үлгісінің құжаттамасы үлгі қолданылатын жағдайды, осы жағдайдағы үлгі шешуге тырысатын мәселелерді және ұсынылатын шешімді сипаттайды. Дизайн үлгілерін құжаттау үшін бірыңғай стандартты формат жоқ. Керісінше, әртүрлі үлгі авторлары әртүрлі форматтарды пайдаланған. Алайда, Мартин Фаулердің айтуынша, кейбір үлгілер басқаларына қарағанда көбірек танымал болды және нәтижесінде жаңа үлгілерді жазу үшін жиі қолданылатын бастапқы нүктеге айналды. Көп қолданылатын құжаттама форматтарының бір мысалы – Эрих Гамма, Ричард Хелм, Ральф Джонсон және Джон Виссидес өздерінің «Дизайн үлгілері» кітабында қолданған формат. Онда келесі бөлімдер бар:
Үлгінің аты және жіктелуі: Үлгіні анықтауға және сілтеме жасауға көмектесетін сипаттамалық және бірегей атау. Мақсаты: Үлгінің артындағы мақсат және оны қолдану себебі. Басқаша атаулары: Үлгінің басқа атаулары. Мотивация (Күштер): Бұл үлгіні қолдануға болатын проблема мен жағдайдан тұратын сценарий. Қолданылу облысы: Бұл үлгіні қолдануға болатын жағдайлар; үлгі үшін жағдай. Құрылымы: Үлгінің графикалық бейнесі. Бұл мақсатта сынып диаграммалары мен өзара әрекеттесу диаграммаларын пайдалануға болады. Қатысушылар: Үлгіде қолданылатын кластар мен объектілердің тізімі және олардың жобадағы рөлі. Ынтымақтастық: Үлгіде қолданылатын кластар мен объектілердің бір-бірімен қалай өзара әрекеттесетінін сипаттау. Салдары: Үлгіні қолдану нәтижесінде туындайтын нәтижелер, жанама әсерлер және компромистердің сипаттамасы. Іске асыру: Үлгінің іске асырылуының сипаттамасы; үлгінің шешім бөлігі. Мысал код: Үлгінің бағдарламалау тілінде қалай қолданылатынын көрсететін мысал. Белгілі қолданылулары: Үлгінің нақты қолданылу мысалдары. Қатысты үлгілер: Үлгімен байланысы бар басқа үлгілер; үлгі мен ұқсас үлгілер арасындағы айырмашылықтарды талқылау.
Сын
Кейбіреулер дизайн үлгілері белгілі бір бағдарламалау тілінде (мысалы, Java немесе C++) жетіспейтін мүмкіндіктердің белгісі болуы мүмкін деп санайды. Питер Норвиг Design Patterns кітабындағы 23 үлгінің 16-сы (негізінен C++ тіліне бағытталған) Lisp немесе Dylan тілдерінде жеңілдетілгенін немесе жойылғанын көрсетті. Ханнеман мен Кицалес 23 дизайн үлгісінің бірнешеуін аспектіге бағытталған бағдарламалау тілі (AspectJ) арқылы іске асырып, 23 дизайн үлгісінің 17-сі бойынша код деңгейіндегі тәуелділіктерді жойғанын және аспектіге бағытталған бағдарламалау дизайн үлгілерін іске асыруды жеңілдете алатынын көрсетті. Сондай-ақ Пол Грэмнің "Нердтердің кек алуы" атты эссесін қараңыз. Үлгілерді тиісінше қолданбау қажетсіз күрделілікті арттыруы мүмкін. Анықтама бойынша, үлгі оны пайдаланатын әрбір бағдарламаға жаңадан енгізілуі керек. Кейбір авторлар мұны компоненттер арқылы қамтамасыз етілген бағдарламалық құралды қайта пайдаланудан бір қадам артқа шегіну деп есептейді, сондықтан зерттеушілер үлгілерді компоненттерге айналдыруға тырысты. Мейер мен Арноут өздері сынаған үлгілердің үштен екісін толық немесе ішінара компоненттеуге қол жеткізді. Икемділікті қамтамасыз ету үшін дизайн үлгілері қосымша аралық деңгейлерді енгізе алады, бұл нәтижесінде дизайнды күрделілендіріп, жұмыс істеу жылдамдығын төмендетуі мүмкін.