Theրագրակազմի ձևավորում. Մոդուլներ, դասեր և գործառույթներ այնպես, որ երբ նոր ֆունկցիոնալություն է անհրաժեշտ, մենք չպետք է փոփոխենք գոյություն ունեցող ծածկագիրը, այլ գրենք նոր կոդ, որը կօգտագործվի գործող կոդի կողմից: Սա կարող է տարօրինակ թվալ, հատկապես այնպիսի լեզուներով, ինչպիսիք են Java, C, C ++ կամ C #, որտեղ դա վերաբերում է ոչ միայն բուն աղբյուրին, այլև երկուականին: Մենք ուզում ենք ստեղծել նոր առանձնահատկություններ այն եղանակներով, որոնք չեն պահանջում առկա բինարների, գործարկելի կամ DLL- ների վերաբաշխում:
OCP- ը ԼՈՒOLՐ համատեքստում
Մենք արդեն տեսել ենք SRP- ի «Միասնական պատասխանատվության» սկզբունքը, որում ասվում է, որ մոդուլը փոխելու միայն մեկ պատճառ պետք է ունենա: OCP և SRP սկզբունքները լրացնում են միմյանց: ՊՊR սկզբունքի հիման վրա մշակված ծածկագիրը նույնպես հարգելու է OCP սկզբունքները: Երբ մենք ունենք կոդ, որը փոխելու միայն մեկ պատճառ ունի, նոր հատկության ներդրումը կստեղծի այդ փոփոխության երկրորդական պատճառ: Այսպիսով, և SRP- ն, և OCP- ն կխախտվեն: Նմանապես, եթե մենք ունենք կոդ, որը պետք է փոխվի միայն այն ժամանակ, երբ դրա հիմնական գործառույթը փոխվում է և պետք է մնա անփոփոխ, երբ նոր գործառույթ է ավելացվում, այդպիսով հարգելով OCP- ն, այն հիմնականում կհարգի նաև SRP- ն:
Սա չի նշանակում, որ ՊՊR-ն միշտ հանգեցնում է OCP- ի կամ հակառակը, բայց շատ դեպքերում, եթե դրանցից մեկը բավարարվում է, երկրորդին հասնելը բավականին պարզ է:
Aուտ տեխնիկական տեսանկյունից Բաց / Փակ սկզբունքը շատ պարզ է: Երկու դասերի պարզ հարաբերությունը, ինչպես ներքևում գտնվողը, խախտում է OCP սկզբունքը:
Օգտագործողի դասը ուղղակիորեն օգտագործում է Logic դասը: Եթե մեզ հարկավոր է իրականացնել երկրորդ Logic դաս այնպիսի եղանակով, որը մեզ հնարավորություն կտա օգտագործել ինչպես ընթացիկ, այնպես էլ նոր, առկա Logic դասը պետք է փոխվի: Օգտագործողը ուղղակիորեն կապված է տրամաբանության իրականացման հետ, մեզ համար ոչ մի կերպ չկա նոր տրամաբանություն տրամադրելու հնարավորություն ՝ առանց ազդելու ներկայիս տրամաբանության վրա: Եվ երբ մենք խոսում ենք ստատիկ մուտքագրված լեզուների մասին, շատ հավանական է, որ Օգտագործողի դասը նաև փոփոխություններ պահանջի: Եթե մենք խոսում ենք կազմված լեզուների մասին, անշուշտ և օգտագործողի գործադիրը, և Logic- ը կամ դինամիկ գրադարանը կպահանջեն վերամշակում և առաքում, նախընտրելի է խուսափել հնարավորության դեպքում:
Հաշվի առնելով նախորդ սխեմային, մենք կարող ենք եզրակացնել, որ ցանկացած դաս, որն ուղղակիորեն օգտագործում է մեկ այլ դաս, կարող է հանգեցնել Բաց / Փակ սկզբունքի խախտման:
Ենթադրենք, որ մենք ցանկանում ենք գրել դասարան, որն ի վիճակի կլինի ապահովել ներբեռնված ֆայլի «տոկոսով» առաջընթացը մեր ծրագրի միջոցով: Մենք կունենանք երկու հիմնական դաս ՝ Progress և File, և, կարծում եմ, կցանկանայինք դրանք օգտագործել հետևյալ կերպ.
ֆունկցիայի testItCanGetTheProgressOfAFileAsAPercent () {
$ ֆայլ = նոր Ֆայլ ();
$ ֆայլ-> երկարություն = 200;
$ ֆայլ-> ուղարկված = 100;
$ progress = new Progress ($ ֆայլ);
$ this-> assertEquals (50, $ progress-> getAsPercent ());
}
Այս ծածկագրում մենք առաջընթացի օգտվողներ ենք: Մենք ուզում ենք տոկոս ստանալ մի արժեք, անկախ ֆայլի իրական չափից: Մենք օգտագործում ենք Ֆայլը որպես տեղեկատվության աղբյուր: Ֆայլը ունի բայթերի երկարություն և ուղարկված դաշտ, որը ներկայացնում է ներբեռնողին ուղարկված տվյալների քանակը: Մեզ չի հետաքրքրում, թե ինչպես են այս արժեքները թարմացվում հայտում: Կարող ենք ենթադրել, որ կա ինչ-որ կախարդական տրամաբանություն, որը դա անում է մեզ համար, ուստի փորձության ժամանակ մենք կարող ենք հստակորեն սահմանել դրանք:
դաս File
$ $ երկարություն;
հրապարակային $ ուղարկված;
}
File դասը պարզապես տվյալների դաշտը պարունակող պարզ օբյեկտ է: Իհարկե, այն պետք է պարունակի նաև այլ տեղեկություններ և վարք, ինչպիսիք են ֆայլի անունը, ուղին, հարաբերական ուղին, ընթացիկ գրացուցակը, տեսակը, թույլտվությունները և այլն:
դասի առաջընթաց {
անձնական $ ֆայլ;
գործառույթը __construction (Պատկեր $ ֆայլ) {
$ այս-> ֆայլ = $ ֆայլ;
}
getAsPercent գործառույթ () {
վերադարձնել $ այս-> ֆայլ-> ուղարկված * 100 / $ այս-> ֆայլ-> երկարություն;
}
}
Առաջընթացը պարզապես դաս է, որն ընդունում է ֆայլը իր կոնստրուկտորում: Հստակության համար մենք կոնստրուկտորի պարամետրերում նշել ենք փոփոխականի տեսակը: Progress- ի վրա կա մեկ օգտակար մեթոդ, getAsPercent (), որը File- ից կվերցնի ուղարկված արժեքներն ու երկարությունը և դրանք կդարձնի տոկոսների: Պարզ է և ստացվում է:
Այս կոդը, կարծես, ճիշտ է, սակայն այն խախտում է Բաց / Փակ սկզբունքը:
Բայց ինչու?
Եվ ինչպե՞ս
Applicationամանակի ընթացքում զարգացող յուրաքանչյուր դիմումի համար անհրաժեշտ կլինեն նոր գործառույթներ: Մեր հավելվածի համար նոր առանձնահատկություն կարող է լինել երաժշտության հոսքը թույլատրելը `պարզապես ֆայլեր ներբեռնելու փոխարեն: Ֆայլի երկարությունը ներկայացված է բայթերով, երաժշտության տևողությունը վայրկյաններով: Մենք ուզում ենք առաջադիմության տող առաջարկել մեր ունկնդիրներին, բայց կարո՞ղ ենք վերօգտագործել վերևում գրված դասը:
Ոչ, մենք չենք կարող: Մեր առաջընթացը կապված է File- ի հետ: Այն կարող է կառավարել միայն ֆայլի տեղեկատվությունը, չնայած այն կարող է կիրառվել նաև երաժշտական բովանդակության վրա: Բայց դա անելու համար մենք պետք է փոփոխենք այն, մենք պետք է այնպես անենք, որ Progress- ն իմանա երաժշտությունն ու ֆայլերը: Եթե մեր դիզայնը համապատասխանում էր OCP- ին, ապա մեզ հարկավոր չէր դիպչել File- ին կամ Progress- ին: Մենք կարող էինք պարզապես վերօգտագործել առկա առաջընթացը և այն կիրառել երաժշտության վրա:
Դինամիկ մուտքագրված լեզուներն առավելություն ունեն գործառույթի ժամանակ օբյեկտի տեսակների հետ վարվելու առավելության: Սա թույլ է տալիս մեզ հեռացնել Progress կոնստրուկտորից տառատեսակը, և ծածկագիրը կշարունակի աշխատել:
դասի առաջընթաց {
անձնական $ ֆայլ;
գործառույթը __construction ($ ֆայլ) {
$ այս-> ֆայլ = $ ֆայլ;
}
getAsPercent գործառույթ () {
վերադարձնել $ այս-> ֆայլ-> ուղարկված * 100 / $ այս-> ֆայլ-> երկարություն;
}
}
Այժմ մենք կարող ենք ցանկացած բան գործարկել Progress- ում: Եվ ամեն ինչ ասելով, ես նկատի ունեմ բառացիորեն ցանկացած բան.
դաս երաժշտություն {
$ $ երկարություն;
հրապարակային $ ուղարկված;
հրապարակային $ նկարիչ;
հրապարակային $ ալբոմ;
հրապարակային $ releaseDate;
getAlbumCoverFile գործառույթ () {
վերադարձնել «Պատկերներ / ծածկոցներ»: $ սա-> նկարիչ: '/' $ այս-> ալբոմ: '.png';
}
}
Եվ վերոնշյալի նման երաժշտության դասը հիանալի կաշխատի: Մենք կարող ենք այն հեշտությամբ ստուգել File- ով շատ նման թեստով:
ֆունկցիայի testItCanGetTheProgressOfAMusicStreamAsAPercent () {
$ երաժշտություն = նոր երաժշտություն ();
$ երաժշտություն-> երկարություն = 200;
$ երաժշտություն-> ուղարկված = 100;
$ progress = new Progress ($ երաժշտություն);
$ this-> assertEquals (50, $ progress-> getAsPercent ());
}
Այսպիսով, հիմնականում ցանկացած չափելի բովանդակություն կարող է օգտագործվել Progress դասի հետ: Միգուցե մենք այն պետք է դնենք կոդի մեջ ՝ փոխելով նաև փոփոխականի անունը.
դասի առաջընթաց {
մասնավոր $ չափելի պարունակություն;
գործառույթը __construction ($ չափելիContent) {
$ this-> ՉափվողContent = $ ՉափվողContent;
}
getAsPercent գործառույթ () {
վերադարձնել $ այս-> չափելիԿոնցենտ-> ուղարկված * 100 / $ այս-> չափելիԿոնցենտ-> երկարություն;
}
}
Երբ մենք նշում էինք File- ը որպես տպագիր, մենք լավատես էինք այն հարցում, թե ինչ կարող է կարգավորել մեր դասը: Դա պարզ էր, և եթե ինչ-որ այլ բան գար, մի մեծ սխալ մեզ կասեր:
Una դաս, որը գերազանցում է բազային դասի այնպիսի եղանակը, որը հիմնական դասի պայմանագիրը չի հարգվում ստացված դասի կողմից:
Մենք չենք ուզում վերջապես փորձել զանգահարել մեթոդներ կամ մուտք գործել դաշտեր այն օբյեկտների վրա, որոնք չեն համապատասխանում մեր պայմանագրին: Երբ մենք ունեինք գրամեքենա, պայմանագիրը նշված էր դրանով: File դասի դաշտերն ու մեթոդները: Հիմա, երբ մենք ոչինչ չունենք, մենք կարող ենք ուղարկել ցանկացած բան, նույնիսկ տող, և դա կհանգեցնի վատ սխալի:
Թեև վերջնական արդյունքը երկու դեպքում էլ նույնն է, ինչը նշանակում է, որ կոդը կոտրվում է, առաջինը գեղեցիկ հաղորդագրություն է ստեղծել: Սա, սակայն, շատ մութ է։ Չկա որևէ կերպ իմանալու, թե որն է փոփոխականը, մեր դեպքում տողը, և ինչ հատկություններ են որոնվել և չեն գտնվել: Դժվար է վրիպազերծել և շտկել խնդիրը: Ծրագրավորողը պետք է բացի Progress դասը, կարդա և հասկանա այն: Պայմանագիրը, այս դեպքում, երբ դուք հստակորեն չեք նշում տառատեսակը, այն է defiառաջադիմության պահվածքից նվաստացած: Դա ենթադրյալ պայմանագիր է, որը հայտնի է միայն «Պրոգրես»-ին։ Մեր օրինակում այդպես է defiավարտվեց՝ մուտք գործելով երկու դաշտեր՝ ուղարկված և երկարություն, getAsPercent() մեթոդով: Իրական կյանքում ենթադրյալ պայմանագիրը կարող է լինել շատ բարդ և դժվար է բացահայտել՝ պարզապես մի քանի վայրկյան դասարանում փնտրելով:
Այս լուծումը առաջարկվում է միայն այն դեպքում, եթե ստորև ներկայացված այլ խորհուրդներից ոչ մեկը չի կարող հեշտությամբ կիրառվել, կամ եթե դրանք լուրջ ճարտարապետական փոփոխություններ են կատարում, որոնք ջանք չեն պահանջում:
Ercole Palmeri
Microsoft Excel-ը տվյալների վերլուծության հղման գործիքն է, քանի որ այն առաջարկում է բազմաթիվ հնարավորություններ տվյալների հավաքածուների կազմակերպման համար,…
Walliance-ը, SIM-ը և հարթակը 2017 թվականից ի վեր անշարժ գույքի քրաուդֆանդինգի ոլորտում Եվրոպայի առաջատարների շարքում հայտարարում է ավարտի մասին…
Filament-ը «արագացված» Laravel-ի զարգացման շրջանակ է, որն ապահովում է մի քանի ամբողջական փաթեթ բաղադրիչներ: Այն նախատեսված է պարզեցնելու գործընթացը…
«Ես պետք է վերադառնամ, որպեսզի ավարտեմ իմ էվոլյուցիան. ես կպրոյեկտեմ ինձ համակարգչի ներսում և կդառնամ մաքուր էներգիա: Մի անգամ հաստատվելով…
Google DeepMind-ը ներկայացնում է արհեստական ինտելեկտի իր մոդելի կատարելագործված տարբերակը։ Նոր բարելավված մոդելն ապահովում է ոչ միայն…
Laravel-ը, որը հայտնի է իր էլեգանտ շարահյուսությամբ և հզոր հատկանիշներով, նաև ամուր հիմք է ստեղծում մոդուլային ճարտարապետության համար: Այնտեղ…
Cisco-ն և Splunk-ն օգնում են հաճախորդներին արագացնել իրենց ճանապարհորդությունը դեպի ապագա Անվտանգության գործառնությունների կենտրոն (SOC)…
Ransomware-ը գերիշխում է նորությունների մեջ վերջին երկու տարիների ընթացքում: Շատերը լավ գիտեն, որ հարձակումները…