Үлгіні тастаңыз - Dispose pattern - Wikipedia

Жылы объектіге бағытталған бағдарламалау, қалыбын тастаңыз Бұл дизайн үлгісі үшін ресурстарды басқару. Бұл үлгіде а ресурс өткізеді объект, және әдеттегі қоңырау шалу арқылы шығарылды әдіс - деп аталады жабық, қоқысқа тастаңыз, Тегін, босату тілге байланысты - ол объектіде тұрған кез-келген ресурстарды шығарады. Көптеген тілдер кәдеге жарату әдісін жалпы жағдайда шақырудың алдын алу үшін тілдік құрылымдарды ұсынады.

Диспозиция үлгісі ең алдымен оның тілдерінде қолданылады жұмыс уақыты ортасы бар қоқысты автоматты түрде жинау (төмендегі уәжді қараңыз).

Мотивация

Ресурстарды объектілерге орау

Ресурстарды объектілерге орау объектінің бағытталған нысаны болып табылады инкапсуляция, және қоқысқа арналған үлгінің негізінде жатыр.

Ресурстар әдетте ұсынылады тұтқалар (дерексіз сілтемелер), әдетте ресурстарды қамтамасыз ететін сыртқы жүйемен байланыс орнатуға арналған бүтін сандар. Мысалы, файлдар операциялық жүйе (нақты файлдық жүйе ), ол көптеген жүйелерде ашық файлдарды ұсынады файл дескрипторы (файлды көрсететін бүтін сан).

Бұл тұтқаларды мәнді айнымалыда сақтау және ресурстарды пайдаланатын функцияларға аргумент ретінде беру арқылы тікелей қолдануға болады. Дегенмен, көбінесе тұтқадан деректеме жасау пайдалы (мысалы, әр түрлі операциялық жүйелер файлдарды басқаша көрсетсе) және қосымша көмекші деректерді тұтқамен бірге сақтау керек, сондықтан тұтқаларды өрісте өріс ретінде сақтауға болады жазба, басқа мәліметтермен бірге; егер бұл ан мөлдір емес мәліметтер түрі, содан кейін бұл қамтамасыз етеді ақпаратты жасыру және пайдаланушы нақты ұсынудан абстракцияланады.

Мысалы, in C файлын енгізу / шығару, файлдар. объектілері арқылы ұсынылған ФАЙЛ түрі (шатастырып «файл тұтқалары «: бұл файлға (амалдық жүйенің) дескрипторын сақтайтын тілдік деңгейдегі абстракция (мысалы файл дескрипторы ), қосалқы ақпарат сияқты енгізу-шығару режимі (оқу, жазу) және ағымдағы орны. Бұл нысандар шақыру арқылы жасалады фопен (объектіге бағытталған терминдерде, а конструктор ), ол ресурстарды алады және оған сілтегішті қайтарады; ресурс қоңырау арқылы шығарылады fclose көрсеткішіне ФАЙЛ объект.[1] Кодта:

ФАЙЛ *f = фопен(файл атауы, режимі);// f көмегімен бірдеңе жасаңыз.fclose(f);

Ескертіп қой fclose функциясы болып табылады ФАЙЛ * параметр. Нысанға бағытталған бағдарламалауда бұл орнына даналық әдіс Python сияқты файл нысанында:

f = ашық(файл атауы)# F көмегімен бірдеңе жасаңыз.f.жабық()

Бұл дәл диспозиция үлгісі, тек синтаксисі мен құрылымы бойынша ерекшеленеді[a] дәстүрлі файлды ашудан және жабудан. Басқа ресурстарды дәл осылай басқаруға болады: конструкторда немесе фабрикада сатып алу және оны ашық түрде шығару жабық немесе қоқысқа тастаңыз әдіс.

Жедел босату

Ресурстарды босатуды шешуге бағытталған негізгі проблема ресурстардың қымбат болуында (мысалы, ашық файлдар санында шектеу болуы мүмкін), сондықтан оларды тез арада шығару керек. Сонымен қатар, кейде кейбір аяқтау жұмыстары қажет, әсіресе енгізу-шығару үшін, мысалы, барлық деректердің шынымен жазылуын қамтамасыз ету үшін буферлерді тазарту.

Егер ресурс шектеусіз немесе тиімді шектеусіз болса және нақты аяқтау қажет болмаса, оны босату маңызды емес, ал шын мәнінде қысқа мерзімді бағдарламалар көбінесе ресурстарды ашық түрде босатпайды: қысқа мерзімге байланысты олар ресурстарды сарқып шығаруы екіталай , және олар жұмыс уақыты жүйесі немесе операциялық жүйе кез келген пысықтау.

Алайда, жалпы ресурстарды басқару керек (әсіресе ұзақ өмір сүретін бағдарламалар үшін, көптеген ресурстарды қолданатын бағдарламалар үшін немесе қауіпсіздікті сақтау үшін, деректердің жазылуын қамтамасыз ету үшін). Айқын кәдеге жарату ресурстарды аяқтау және шығару детерминирленген және жедел болатындығын білдіреді: қоқысқа тастаңыз әдісі аяқталғанға дейін аяқталмайды.

Нақты жоюды талап етудің баламасы ресурстарды басқаруды байланыстыру болып табылады объектінің қызмет ету мерзімі: ресурстар кезінде сатып алынады объектіні құру, және кезінде шығарылды объектіні жою. Бұл тәсіл белгілі Ресурстарды сатып алу инициализация болып табылады (RAII) идиома, және детерминирленген жадыны басқаратын тілдерде қолданылады (мысалы. C ++ ). Бұл жағдайда, жоғарыда келтірілген мысалда, ресурс файлдық объект құрылған кезде және айнымалының ауқымы болған кезде алынады f файлдың объектісі шыққан f сілтеме жойылды, және оның бөлігі ретінде ресурс шығарылады.

RAII объектінің қызмет ету мерзімінің детерминирленгендігіне негізделген; дегенмен, жадыны автоматты басқарумен, объектінің қызмет ету мерзімі бағдарламашыны алаңдатпайды: объектілер пайдаланылмай тұрғаннан кейін белгілі бір уақытта жойылады, бірақ қашан рефератталған. Шынында да, өмір көбінесе детерминирленбейді, бірақ егер ол мүмкін болса, мүмкін анықтамалық санау қолданылады. Шынында да, кейбір жағдайларда нысандар кепілдік бермейді мәңгі аяқталуы керек: бағдарлама аяқталған кезде объектілерді аяқтамауы мүмкін, оның орнына амалдық жүйеге жадыны қалпына келтіруге мүмкіндік береді; егер аяқтау қажет болса (мысалы, буферді жуу үшін), деректердің жоғалуы мүмкін.

Осылайша, ресурстарды басқару объектінің қызмет ету мерзімімен байланыстырылмай, кәдеге жаратуға мүмкіндік береді ресурстар жедел түрде босату керек, бұл жадыны басқаруға икемділік береді. Мұның құны ресурстарды қолмен басқару керек, бұл жалықтырғыш және қателіктерге ұрындыруы мүмкін.

Ерте шығу

Қоқысқа лақтырудың негізгі проблемасы мынада: қоқысқа тастаңыз әдіс шақырылмайды, ресурс ағып кетеді. Мұның жалпы себебі - ерте қайту немесе ерекшелікке байланысты функциядан ерте шығу.

Мысалға:

деф функциясы(файл атауы):    f = ашық(файл атауы)    егер а:        қайту х    f.жабық()    қайту ж

Егер функция бірінші қайтару кезінде оралса, файл ешқашан жабылмайды және ресурс ағып кетеді.

деф функциясы(файл атауы):    f = ашық(файл атауы)    ж(f)  # F көмегімен ерекше жағдай туындайтын нәрсе жасаңыз.    f.жабық()

Егер аралық код ерекше жағдай тудырса, функция ерте шығады және файл ешқашан жабылмайды, сондықтан ресурс ағып кетеді.

Бұлардың екеуін де а көріңіз ... ақыры соңғы сөйлем әрдайым шығу кезінде орындалуын қамтамасыз ететін construct:

деф функциясы(файл атауы):    тырысу:        f = ашық(файл атауы)        # Бірдеңе жаса.    ақыры:        f.жабық()

Неғұрлым жалпылама:

Ресурс ресурс = getResource();тырысу {    // Ресурс алынды; ресурстармен әрекеттерді орындау.    ...} ақыры {    // Ерекше жағдай жасалған болса да, ресурстарды босатыңыз.    ресурс.қоқысқа тастаңыз();}

The көріңіз ... ақыры салу үшін қажет ерекшелік қауіпсіздігі, бастап ақыры блок тазарту логикасын орындауға мүмкіндік береді, егер бұл жағдай ерекше жағдайға енгізілсе де, жоқ болса да тырысу блок.

Бұл тәсілдің бір кемшілігі - бұл бағдарламалаушыдан a-ға тазарту кодын нақты қосуды талап етеді ақыры блок. Бұл кодтың мөлшерінің өсуіне әкеледі, ал оны орындамау бағдарламада ресурстардың ағып кетуіне әкеледі.

Тілдік құрылымдар

Кәдеге жарату үлгісін қауіпсіз пайдалану үшін бірнеше тілде бірдей сақталған және шығарылатын ресурстарға арналған қолдаудың кейбір түрлері бар код блогы.

The C # тіл ерекшеліктері қолдану мәлімдеме [2] автоматты түрде қоңырау шалады Жою іске асыратын объектідегі әдіс Бір реттік интерфейс:

қолдану (Ресурс ресурс = GetResource()){    // Ресурспен әрекеттерді орындау.    ...}

ол тең:

Ресурс ресурс = GetResource()тырысу {    // Ресурспен әрекеттерді орындау.    ...}ақыры {    // Ресурс алынбауы немесе босатылуы мүмкін    егер (ресурс != нөл)         ((Бір реттік)ресурс).Жою(); }

Сол сияқты Python тілде а бар бірге а-мен ұқсас әсер ету үшін қолдануға болатын мәлімдеме контекст-менеджер объект. The мәтінмәндік менеджердің хаттамасы жүзеге асыруды қажет етеді __enter__ және __Шығу__ автоматты түрде шақырылатын әдістер бірге кодтың қайталануын болдырмау үшін операторды құру керек, әйтпесе тырысу/ақыры өрнек.[3]

бірге resource_context_manager() сияқты ресурс:    # Ресурспен әрекеттерді орындау.    ...# Ресурсты бөлуге кепілдік берілген басқа әрекеттерді орындаңыз....

The Java деп аталатын жаңа синтаксисті енгізді тырысу- Java 7 нұсқасындағы ресурстармен.[4] Оны AutoCloseable интерфейсін іске асыратын объектілерде қолдануға болады (бұл әдісті close () анықтайды):

тырысу (OutputStream х = жаңа OutputStream(...)) {    // x көмегімен бірдеңе жасаңыз} аулау (IOException бұрынғы) {    // Ерекше жағдайды өңдеу  // x ресурсы автоматты түрде жабылады} // тырысу

Мәселелер

Табыстар мен ерекшеліктер болған кезде ресурстарды дұрыс басқару және үйіндіге негізделген ресурстарды басқару (объектілерді олар құрылған жерден басқа көлемде орналастыру) болған кезде, кәдеге жарату заңдылығымен байланысты көптеген көптеген қиындықтар бар. Бұл проблемаларды көбіне болдырмайды RAII. Алайда қарапайым қарапайым қолданыста бұл қиындықтар туындамайды: бір ресурстарды сатып алыңыз, онымен бірдеңе жасаңыз, оны автоматты түрде босатыңыз.

Ресурсқа ие болу енді а инвариант (ресурс объектіні жасаудан бастап, ол жойылғанға дейін ұсталады, бірақ объект осы сәтте тірі болады), сондықтан ресурс оны пайдалануға тырысқанда, мысалы, жабық файлдан оқуға тырысқанда, ресурс қол жетімді болмауы мүмкін. Бұл дегеніміз, ресурстарды пайдаланатын объектідегі барлық әдістер сәтсіздікке ұшырайды, әдетте қатені қайтару немесе ерекше жағдай жасау арқылы. Іс жүзінде бұл шамалы, өйткені ресурстарды пайдалану басқа себептермен де сәтсіздікке ұшырауы мүмкін (мысалы, файл соңын оқуға тырысу), сондықтан бұл әдістер сәтсіздікке ұшырауы мүмкін, ал ресурстардың болмауы тағы бір мүмкін болатын ақаулықты қосады . Мұны іске асырудың стандартты тәсілі - бұл объектіге логикалық өрісті қосу деп аталады жойылдыарқылы орнатылады қоқысқа тастаңыз, және тексерді күзет ережесі барлық әдістерге (ресурстарды қолданатын), ерекшелікті көтеру (мысалы ObjectDisposedException егер объект жойылған болса .NET).[5]

Бұдан әрі қоңырау шалуға болады қоқысқа тастаңыз объектіде бірнеше рет. Бұл бағдарламалау қателігін көрсетуі мүмкін (бірақ ресурсқа ие әрбір объект орналастырылуы керек) дәл бір рет), бұл қарапайым, берік және, әдетте, бұл үшін қолайлы қоқысқа тастаңыз болу идемпотентті («бірнеше рет қоңырау шалу бір рет шақырумен бірдей» дегенді білдіреді).[5] Бұл бірдей логикалық сөзді қолдану арқылы оңай жүзеге асырылады жойылды өріс және оны қарауыл пунктінде тексеру кезінде қоқысқа тастаңыз, бұл жағдайда ерекшелікті емес, дереу оралу.[5] Java бір реттік түрлерін (іске асырылатын түрлерін) ажыратады Автожабылатын ) идопотентті болатын бір реттік типтерден (кіші типтен) Жабу ).

Ресурстарға ие объектілердің мұрасы мен құрамы болған жағдайда жою, жою / аяқтау сияқты проблемалар бар (деструкторлар немесе пысықтаушылар арқылы). Бұдан басқа, қоқысқа тастау үлгісі үшін бұған тілдік қолдау болмағандықтан, қазандық коды қажет. Біріншіден, егер туынды сынып а қоқысқа тастаңыз негізгі сыныптағы әдіс, шығарылған сыныптағы басым әдіс жалпыға қоңырау шалу керек қоқысқа тастаңыз базадағы ресурстарды дұрыс шығару үшін базалық сыныптағы әдіс. Екіншіден, егер объект ресурсты ұстайтын басқа объектімен «бар» қатынасқа ие болса (яғни, егер объект ресурстарды жанама түрде басқа ресурстарды пайдаланатын басқа объект арқылы пайдаланса), жанама түрде қолданатын объект бір реттік болуы керек пе? Бұл қатынастың бар-жоғына сәйкес келеді иелік ету (объектінің құрамы ) немесе қарау (объектіні біріктіру ), немесе тіпті жай қарым-қатынас (қауымдастық ), және екі конвенция да табылды (жанама пайдаланушы ресурс үшін жауап береді немесе жауап бермейді). Егер жанама пайдалану ресурс үшін жауап беретін болса, ол бір реттік болуы керек және иелік еткен объектілерді иеліктен шығарған кезде иеліктен шығаруы керек (меншікті объектілерді жоюға немесе аяқтауға ұқсас).

Композиция (иелену) қамтамасыз етеді инкапсуляция (тек пайдаланылатын объектіні қадағалау қажет), бірақ объектілер арасында одан әрі қатынастар болған кезде едәуір күрделіліктің құны бойынша, ал жинақтау (қарау) айтарлықтай қарапайым, ал инкапсуляция болмау есебінен. Жылы .NET, конвенция тек ресурстарды тікелей пайдаланушыға жүктелуі керек: «Сіз IDisposable бағдарламасын тек сіздің типіңіз басқарылмайтын ресурстарды тікелей қолданған жағдайда ғана жүзеге асырыңыз.»[6] Қараңыз ресурстарды басқару толығырақ және басқа мысалдар үшін.

Сондай-ақ қараңыз

Ескертулер

  1. ^ Жылы сыныпқа негізделген бағдарламалау, әдістері сыныпта айқындала отырып, анықталады бұл немесе өзіндік параметр, анық параметр қабылдайтын функциялар ретінде емес.

Әдебиеттер тізімі

  1. ^ stdio.h - негізгі анықтамаларға сілтеме, Бірыңғай UNIX спецификациясы, 7 шығарылым Ашық топ
  2. ^ Microsoft MSDN: (C # сілтемесі) мәлімдемесін қолдану
  3. ^ Гидо ван Россум, Ник Коглан (2011 ж. 13 маусым). «PEP 343:» «мәлімдемесімен». Python бағдарламалық қамтамасыздандыру қоры.
  4. ^ Oracle Java оқулығы: Ресурстармен қолдануға болатын мәлімдеме
  5. ^ а б c «Үлгіні тастаңыз».
  6. ^ «Бірегей интерфейс». Алынған 2016-04-03.

Әрі қарай оқу