Saturday, 7 January 2017

ობიეკტზე ორიენტირებული პროგრამირება. ნაწილი 1. მემკვიდრეობა



           ობიეკტზე ორიენტირებული პროგრამირება - OOP



სანამ OOP-ზე ფუნდამენტურად დავიწყებდეთ საუბარს ერთ მნიშვნელოვან ფაკტორს მინდა გაუსვა ხაზი, ობიეკტზე ორიენტირებული პროგრამირება ნებისმიერი ჯავა პროგრამისტის მოვალეობა გახლავთ, რადგან მთლიანი პრინციპი ჯავა პროგრამირების ამ იდეაზეა აგებული. ყველაფერი რასაც აკეთებთ კოდის წერის დროს ემსახურება ერთი დიდი პროგრამული ხის შექმნას სადაც ერთი ობიეკტი, მეთოდი თუ ცვლადი ემსახურება მეორეს. Simula პირველი პროგრამული ენაა რომელიც oop პრინციპებით შეიქნა ნორვეგიაში 1960 წელს Ole Johan Dahl და Kristen Nygaard-ის მიერ. შემდგომ შეიქმნა Smalltalk 1970 წელს და დღესდღეობით მათ მიერ შექმნილი პარადიგმებით ხელმძღვანელობენ ისეთი პოპულარული oop ენები, როგორიც გახლავთ java, c++, python, ruby, perl, Delphi და სხვანი. 

ობიეკტზე ორიენტირებული პროგრამირების შექმნის იდეა ემსახურება პროგრამისტისთვის კოდის გაგების სიმარტივეს, თუნდაც ეს კოდი მის მიერ იყოს შექმნილი, მთავარი პრობლემა რომელსაც პროგრამირების დროს აწყდება პროგრამისტი გახლავთ გაურკვევლობა, წარმოიდგინეთ წერთ კოდს, და მას უბრუნდებით თვეების ან წლების შემდგომ, 99%-ის თავისივე კოდი გაუგებარია, არ ახსოვს ეს რატომ დაწერა ან რას ემსახურებოდა მის მიერ შექმნილი კოდი. ამ პრობლემის გადაჭრის მიზნით შეიქმნა oop, რომელიც გვაძლევს საშუალებას კოდი ხელმეორეოდ გამოვიყენოთ და განვაახლოთ. სანამ ოოპ შეიქმნებოდა ყველა წერდა სტრუკტურულად(პროცედურულად) პროგრამირების ენაზე, დღესაც ბევრი ენა სტრუკტურულად ორიენტირებულია რაც ნიშნავს იმას რომ ყველაფერი რაც გაგაჩნია გაქვს ერთ „კლასში“ და მთლიანი კოდის კონტროლს ახდენ code flow-ის მეშვეობით. (if else statmenets, swich statements და ა.შ) ეს ერთის მხრივ მარტივი გზა არის რადგან ქმნი კოდს, რომელიც იდეალურად მუშაობს, რითაც ყველა კმაყოფილია მაგრამ დროთა განმავლობაში შენი ნამუშევარის მოდიფიცირება რო გინდება ვერ ახერხებ, იმიტომ რო ძალიან რთულია დებაგირება, რთულია კოდის ხელმეორედ გამოყენება, რთულია შესწორებების შეტანა, შესაბამისად ყველაფერი ერთმანეთზეა მიბმული, , ყველაფერი ზემოთ თქმული იკავებს უამრავ დროს რაც შეუთავსებელია მოთხოვნასთან და შემოსავალთან. შედეგად დგება დრო რომელსაც სოფტ კრიზისი ქვია, oop-ს შექმნით, შეიქმნა კოდის წერის სტრუკტურა რომელიც იდეალურად იმუშავებდა და ამავდროულად იქნებოდა მარტივად გამოყენებადი, ცვლადი და განახლებადი. 

ობიეკტზე ორიენტირებული პროგრამირების მეშვეობით პროგრამისტი ახდენს რეალური ცხოვრების მოდელირებას რაც თავის მხრივ ამარტივებს რთული და კომპლექსური სისტემების აგებას. რა თქმა უნდა ის სტრუკტურულად პროგრამირების მემკვიდრეა და ამის გამო ის, მას მთლიანად ითავსებს.

მთლიანი იდეა და სხვაობები თუ გაინტერესებთ წერის სტრუკტურებს შორის შეგიძლიათ მოიძიოთ მასალა. მე კი მთავარს დაუბრუნდები. ჯავაში ობიეკტზე ორიენტირებული პროგრამირება დგას 4 ფუნდამენტზე. ესენია:

1. მემკვიდრეობა. (inheritance) 

2. აბსტრაქცია (abstraction)

3. ენკაპსულაცია (encapsulaiton)

4. პოლიმორფიზმი (polymorphism)



მემკვიდრეობა(inheritance) გახლავთ ძირითადი კონცეპცია ობიეკტზე ორიენტირებულ პროგრამირებაში, მისი გამოყენების იდეა მარტივია, მაგრამ ამავდროულად ძლიერი რადგან პროგრამისტს ეძლევა საშუალება შექმნას საბაზისო კლასი და მისგან აწარმოოს ობიეკტები (ქვე კლასები). 

მემკვიდრეობა ხდება საკვანძო სიტყვა extends-ის მეშვეობით, როდესაც ერთი კლასი (ქვე კლასი ) extends (საბასიზო კლასს) ის მისგან ღებულობს მთლიან შიგთავს რომელიც საბაზისო კლას გააჩნია, ყველა მეთოდს და ცვლადს რომელიც მასშია დეფინირებული და დამატებით გეძლევათ საშუალება ქვე კლასში მოახდინოთ დამატება ახალი მეთოდების და ცვლადების რომელიც ობიეკტის სრულყოფაში დაგეხმარებათ. მარტივად რომ წარმოიდგინოთ მემკვიდრეობა უყურეთ მას როგორც დაუსრულებელ გეგმას, რომლისგანაც ახდენთ უამრავი გეგმის დასრულებას, მაგალითად: ავტომობილი. მას გააჩნია ძრავი, საბურავები, საჭე, მუხრუჭები, აჩქარება და შენელება, მაგრამ ავტომობილი არის უამრავი სახეობის, Ford, BMW, Kia და ა.შ. ყველა მარკის ავტომობილს აქვს განსხვავებული მონაცემები მაგრამ საბაზისო ერთობა, (ყველა ავტომობილია), გამომდინარე აქედან Ford არის ავტომობილი, BWM არის ავტომობილი, Kia არის ავტომობილი. საერთო საბაზისო მონაცემებით მაგრამ განსხვავებული სტრუკტურით. სხვანაირად ამ სახის მემკვიდრეობას IS-A ურთიერთობას ეძახიან, inheritance = IS-A Relashionship (kia is a vehicle, programmer is a employee, phone is a mobilephone და ა.შ) დეფინირების მაგალითი.



მემკვიდრეობას გააჩნია სახეობები. ესენია:

1. ერთ საფეხურიანი მემკვიდრეობა. როდესაც ერთი კლასი მემკვიდრეა მეორე კლასის. 


2. მრავალ საფეხურიანი მემკვიდრეობა. როდესაც ერთი კლასი მემკვიდრეა მეორე კლასის და ყავს მემკვიდრე მესამე კლასი. (მეოთხე, მეხუთე, მეექვსე, რაოდენობას არ აქვს მნიშვნელობა.) როდესაც მრავალ საფეხურიანი მემკვიდრეობა ხდება ბოლოში მდგომი ქვე კლასი იღებს ყველა ფუნქციას რომელიც მის წინამორბედ კლასებს გააჩნია, ანუ მისი მთავარი კლასი მაინც პირველი საბაზისო კლასია, მიუხედავად იმისა რო მემკვიდრეობით იღებს მონაცემებს ზემდგომი კლასიდან. 
3. იერარქიული მემკვიდრეობა, როდესაც რამოდენიმე კლას ყავს ერთი ძირითადი კლასი. 
4. მრავალ განშტოებიანი მემკვიდრეობა, არის მემკვიდრეობა რომელიც გვაძლევს საშუალებას ერთი კლასი იყოს მემკვიდრე ერთდორულად რამოდენიმე კლასის. როგორც ესეთი ეს პრაკტიკა მიუღებელია პირდაპირი მემკვიდრეობის დროს (ჯავა მსგავს მემკვიდრეობას არ ცნობს) და კომპილატორი ერორ მესიჯს გვიჩვენებს როდესაც მას ვიყენებთ, მაგრამ ინტერფეისების მეშვეობით სრულიად ლეგალურია და მასზე მოგვიანებით ინტერფეისებზე საუბრის დროს ვისაუბრებთ. 

5. ჰიბრიდული მემკვიდრეობა ეს არის მემკვიდრეობა რომელიც გახლავთ ნაზავი ერთ საფეხურიანი და მრავალ განშტოებიანი მემკვიდრეობის. როგორც მისი წინამორბედი ისიც ცუდ პრაკტიკად ითვლება მემკვიდრეობისთვის, ჯავა მას ცნობს გასხნავევბით მრავალ განშტოებანი მემკვიდრეობისა მაგრამ ჰიბრიდულს მივყავართ ერთ პრობლემამდე რომელსაც „ბრილიანტის პრობლემას“ ეძახიან პროგრამისტები. არსი შემდეგში მდგომარეოაბს, როდესაც ერთ კლას ყავს ორი მემკვიდრე კლასი და ამ ორი მემკვიდრე კლასის იმპლემენტირებას ახდენს მეოთხე კლასი მას მხედველობა არ აქვს ძირითად საბაზისო კლასზე, ან თუ აქვს დიდი ალბათობით კოდი იქნება შეცდომებით. კომპილატორი ვერ ხვდება რომელი ბრძანების კომპილირება მოახდინოს და მივდივართ ერორამდე.


მემკვიდრეობის გამოყენების წესები:


1. არ არის ნება დართული მრავალ განშტოებიანი მემკვიდრეობა. (Class can not extend more the one class)

2. კონსტრუირება ახალი კლასის ხდება უკვე არსებული კლასის ბაზაზე. 

3. მემკვიდრეობით გადაიცემა ყველა მეთოდი დ ცვლადი რომელიც საბაზისო კლას გააჩნია. გარდა კონსტუკტორისა.

4. ძირითად კლას ქვია საბაზისო კლასი, სუპერ კლასი, მშობელი კლასი. 

5. მემკვიდრეობა გვაძლევს უფლებას მოვახდინოთ ცვალდების აგება იერარქიულად. 

6. საკვანძო სიტყვა super-ის მეშვეობით ხდება საბაზისო კლასის კონსტუკტორზე, ცვლადებზე და მეთოდებზე წვდომა. ის წააგავს this საკვანძო სიტყვას, და ემსახურება საბაზისო კლასის წევრების განსხვავებას ქვე კლასის წევრებისგან. Super(), super.field, super.method(). მას ვერ გამოიყენებთ სტატიკურ წევრებთან. 

7. მონაცემთა ტრანზიტულობა, თუ ძაღლი მემკვიდრეა ცხოველის და პიტბული მემკვიდრეა ძაღლის მაშინ პიტბული მემკვიდრეა ცხოველის. 

8. მემკვიდრეობით გადაიცემა public და protected წევრები.

9. მემკვიდრეობით გადაიცემა default წევრი კლასისა თუ კლასები ერთ პაკეტში იმყოფებიან. 

10. კლასის private წევრების მემკვიდრეობით გადაცემა არ ხდება, ისინი მიუწვდომელია. გასაუბრებაზე უყვართ ამ კითხვის დასმა რადგან კითხვა ორაზროვანია. როგორც ესეთი ჯავა ოფიციალურად არ ცნობს private წევრების მემკვიდრეობით გადაცემას და პასუხიც შესაბამისი უნდა იყოს, არა! 

11. საბაზისო კლასიდან მემკვიდრეობით მიღებული მეთოდები შეიძლება იქნენ ჩანაცვლებულნი. (overridden). 

12. სტატიკურად მიღებული მეთოდები შეიძლება დაიჩრდილნონ.

13. სტატიკური და ინსტანციური ბლოკის მემკვიდრეობით გადაცემა არ ხდება. 

14. სტანდარტულად ყველა მეთოდი კლასში არის ვირტუალური. 

15. თუ სურვილი გაქვთ რო მეთოდი არ იყოს ვიარტუალური უბრალოდ მონიშნეთ ის როგორც final 

16. მემკვიდრეობის დროს ქვე კლასმა აუცილებლად უნდა მაოხდინოს ძირითადი კლასის კონსტუკტორის გამოძახება, თუ პროგრამისტი არ გამოიძახებს კონსტუკტორს ქვე კლასში კომპილატორი იზამს ამას ჩვენ მაგივრად, თუ საბაზისო კლას არ აქვს default კონსტუკტორი(კონსტუკტორი პარამეტრების გარეშე) მაშინ ქვე კლასში უნდა გამოვიძახოთ ნებისმიერი სხვა კონსტუკტორი საბაზისო კლასიდან, წინააღმდეგ შემთხვევაში კომპილირებას ვერ მოვახდენთ. 



                                        HAS-A Relashionship
Has-a ურთიერთობები ერთ-ერთი ფუნდამენტია Oop-ში, მისი საბაზისო სტრუკტურა შემუშავებულია UML-ის (Unified Modeling Language) მიერ. ჯავაში ყველაზე ხშირად გამოიყენება სამი ძირითადი კონცეპცია მოდელირების ზემოთ ხსენებული ენიდან, ესენია: ასოციაცია, აგრეგაცია და კომპოზიცია. 

ობიეკტზე ორიენტირებულ პროგრამირებაში, თუ ერთი ობიეკტი ფუნქციონალურად ემსახურება მეორე ობიეკტს მაშინ ჩვენ გვაქ ასოციაცია ობიეკტებს შორის, ასოციაციას გააჩნია ფორმები, ესენია აგრეგაცია და კომპოზიცია, როგორც ესეთი UML-ში გაცილებით მეტი ფორმა არსებობს ობიეკტებს შორის ურთიერთობის და თუ ინტერესი გაგიჩდათ შეგიძლიათ მოიძიოთ მასალა, ჩვენ კი განვიხილავთ იმას რაც ყველაზე გამოყენებადია ჯავა პროგრამირებაში. 

მაშ ასე:

Associaiton- გახვალვთ ფორმა ურთიერთობის ობიეკტებს შორის, რომლის დროსაც ობიეკტები იყენებენ ერთმანეთის შიგთავს მაგრამ არ არიან მყარ ურთიერთობაში, ანუ თუ მოხდა ერთი ობეკტის განადგურება მეორე მაინც აგრძელებს სიცოცხლეს. უკეთ წარმოდგენისთვის: თანამშრომელი და გასაღები. პროგრამულად რომ შევქმნათ ეგ ურთიერთობა, თანამშრომელს აქვს გასაღები რო სამსახურში შევიდეს და გასაღებს აქვს თანამშრომელი, თუ რომელიმე დაიაკრგა მეორე სიცოცხლეს განაგრძობს, თანამშრომელი სხვა სამსახურში და გასაღები სხვა თანამშრომლის ხელში. ნახეთ მაგალითი:
შევქმენით სამი კლასი. 

კლასი Key:
კლასი Owner:
როგორც შეამჩნევდით ერთი კლასი მეორე კლასში გამოყენებული გვაქ როგორც ტიპი. ამ სახის გამოყენებას bidirectional association ქვია, ცნობისთვის ასოციაციას აქვს ურთიერთობის ფორმები, ესენია, ერთი-ერთან, ერთი-ბევრთან, ბევრი-ერთთან და ბევრი ბევრთან. პრინციპი ყველას ერთია ამიტომ სათითადო არ განვიხილავთ, ერთი თუ იცი ყველა იცი. 

ძირითადი კლასი;

როგორც ხედავთ ორივე კლასზე წვდომა გვაქ ერთი ცვლადიდან, გასაღების თუ მესაკუთვრის იქნება ცვლადი არ აქვს მნიშვნელობა, მთავარი არსის ნახვაა. ორივე ობიეკტი მუშაობს შეთანხმებულად, ორივეს გააჩნია ერთმანეთზე ინფორმაცია, მაგრამ ერთის გაუქმების შემდგომ მეორე არ წყვეტს არსებობას. ობიეკტის გაუქმება მაგალითისთვის არის მოყვანილი სკრინზე, მთლიანად რო გაუქმდეს კავშირები უნდა გაუუქმოთ სხვა კლასთან, იმიტომ რო ვირტუალური მანქანა საკმაოდ ჭკვიანია და ხედავს რო ობიეკტი ისევ გამოყენებაშია. კომპილირების შემდგომ;
აგრეგაცია(Aggregation) ეს არის ფორმა ასოციაციის როდესაც ერთი ობიეკტი დამოკიდებულია მეორეზე, მაგალითისთვის, დაუბრუნდეთ იგივე პროგრამას რომელიც ასოციაციაში გავაკეთეთ, თანამშრომელს აქვს გასაღები და გასაღებს აქვს თანამშრომელი, ორივე დამოუკიდებელია, მაგრამ თუ თანამშრომელს დავუმატებთ მისამართს გამოგვივა აგრეგაცია, რატომ? თანამშრომელს ჭირდება მისამართის ქონა, მაგრამ მისამართს არ ჭირდება თანამშრომელი, ანუ ობიეკტებს შორის ურთიერთობა არის ცალმხრივად დამოკიდებული. ერთს ჭირდება მეორე აუცილებლად, მეორე კი პირველის გარეშე იცოცხლებს. ვნახოთ მაგალითი;


ასე გამოიყურება ჩვენი სამი კლასი, როდესაც მისამართის ობიეკტი გაუქმდება პერსონის ობიეკტს დააკლდება ცვლადი, შესაბამისად არ მოხდება კომპილირება, მაგრამ თუ გავაუქმეთ პერსონის ობიეკტი, მისამართის ობიეკტი ჩვეულებრივად განაგრძობს მუშაობას. აგრეგაცია არის ცალმხრივი ურთიერთობა. კომპილირების შემდგომ.
კომპოზიცია(Composition) არის ფორმა ასოციაციის, რომელიც ითველა ყველაზე მყარ ასოციაციად. მისი მოქმედების დროს ობიეკტები მთლიანად არიან დამოკდიებულნი ერთმანეთზე. თუ მოხდა ერთი ობიეკტის გაუქმება, მეორე ობიეკტი უქმდება მასთან ერთად. არ აქვს მნიშვნელობა ურთიერთობა ორ მხრივი იქნება თუ ცალმხრივი, ნებისმიერ სიტუაციაში როდესაც ვკლავთ ერთს კვდება მეორეც. რაოდენ გასაკვირიც არ უნდა იყოს ეს ფორმა ურთიერთობის ჯავაში არის ყველაზე გამოყენებადი, ასოციაციის გამოყენება უნებურად გიწევთ, როდესაც ორი ობიეკტისგან იღებთ ინფორმაციას ეგ უკვე ასოციაციაა, აგრეგაციას იშვიათად იყენებენ, მაგრამ კომპოზიციას იყენებენ განუწყვეტლივ, მონაცემთა ბაზებთან მუშაობის დროს, სერვერთან მუშაობის დროს.  და ა.შ.  მარტივად ახდენთ უკვე აგებულ სისტემაში ცვლილებების შეტანას. არ გიწევთ არაფრის გადაწერა, ახლიდან შექმნა, უბრალოდ ამატებთ კლას და იყენებთ მის ცვლადს ყველგან სადაც გჭირდებათ ან როგორც გჭირდებათ. წარმოიდგინეთ ბავშვი (ფირმა) გთხოვთ ბანანს(კოდში ცვლილებების შეტანას), თუ გადავწყვიტავთ ამ ცვლილებების მემკვიდრეობით შეტანას გამოვა რო ბავშვს ვაძლევთ ბანანს მაიმუნებთან და მთლიან ჯუნგლებთან ერთად, მგონი მსგავსი სცენარით არავინ დარჩება კმაყოფილი, თქვენ , პროგრამისტსაც არ გჭირდებათ ყველაფერი მისცეთ მომხმარებელს, თუ ითხოვს ბანანს მიეცით ბანანი, სწორედ ამის საშუალებას გვაძლევს ასოციაცია თავისი ქვე ფორმებით. ვნახოთ მაგალითი კომპოზიციის:


დეპარტამენტის კლასი.

კომპანიის კლასი, ფოტოზე წაიკითხეთ კომენტარი. 
ძირითადი კლასი. 
კომპანიიდან გვაქ წვდომა დეპარტამენტებზე, არ არის აუცილებელი დეპარტამენტის ობიეკტი შევქმნათ. მაინც მიბმული არიან ერთმანეთზე

კომპილირების შემდგომ.
მგონი არც ისე რთულია, მარტივად დაიამხსოვრებთ, და უზარმაზარი გასაქანის მქონდე ოპერაციებია, თქვენ ფანტაზიაზეა ძირითადად დამოკდიებული როგორ და სად გამოიყენებთ. მეთოდებთან, ცვალდებთან, კონსტუკტორებთან თუ სადმე სხვაგან. მთავარია გვახსოვდეს წესები, რომლის მიხედვითაც განვასხვავებთ ერთმანეთისგან ოპერაციებს. 



მემკვიდრეობის მაგალითები:

სანამ ყველას საფეხურს დეტალურად გავივლიდეთ, ნახეთ პრიმიტიული მაგალითი იმისა თუ რას წარმოადგენს მემკვიდრეობა. 
ეს გახლავთ ძირითადი კლასი სადაც გვაქ მოცემული სტანდარტული ინფრომაცია, ის რაც ყველას გააჩნია. რის შემდგომაც გვაქ გეთერები და სეთერები, კონსტრუკტორის გარეშე. 

შემდეგ გვაქ ავტობუსის კლასი რომელიც მემკვიდრეა საბაზისო კლასის, ავტობუსის კლასში გვაქ მოდელი და წარმოების წელი. 
მთავარ კლასში კი ხედავთ თუ როგორ გააჩნია წვდომა ავტობუს ყველა ველზე მისი ზემდგომი კლასის. შეამჩნევდით რო კონსტრუკტორი არსად არ გვაქ გამოძახებული, მისი გამოზახება კომპილატორმა მოახდინა ჩვენს მაგივრად როცა შევქმენით ავტობუსის ობიეკტი. იგივე სიტუაციაში საბაზისო კლასში რო გვქონოდა კონსტუკტორი პარამეტრებით, ჯავა არ მოგვცემდა პროგრამის გაშვების უფლებას. ნახეთ მაგალითი:

საბაზისო კლასი, კონსტრუკტორით და პარამეტრებით. 

ქვე კლასის კონსტრუკტორი უკმაყოფილია , რადგან ვერ ახერხებს ავტომატურ რეჟიმში სტანდარტული კონსტრუკტორის გამოძახებას, ერთადერთი კონსტუკტორი რომელსაც ხედავს პარამეტრებიანი კონსტრუკტორია, მაგრამ სამწუხაროდ დახმარების გარეშე მისი გამოძახება ვირტუალურ მანქანას არ შეუძლია. ნახეთ მაგალითი შესწორებების შეტანის შემდგომ. 
ძირითად კლას დავამატეთ გეთერები და დამხმარე მეთოდი. 
ქვე კლასის სტანდარტულ კონსტრუკტორში მოვახდინეთ ძირითადი კლასის კონსტრუკტორის გამოძახება, დააკვირდით გამოძახების მაგალითს, იღებს პარამეტრებს და საკვანძო სიტყვა სუპერის მეშვეობით ახდენს ინფორმაციის გადმოტანას ქვე კლასში, 

ძირითადი კლასი და შემდგომ კომპილაცია.

Super საკვანძო სიტყვის მაგალითი:

საბაზისო კლასი.

ქვე კლასი:

ქვე კლასში გვაქ სამივე მაგალითი, თუ როგორ ხდება გამოძახება კონსტრუკტორის, მეთოდის და ცვლადის, ორი მეთოდი გვაქ , ერთგან ძირითადი კლასის ცვლადებზე წვდომას ვახდენთ, მეორეგან ქვე კლასის ცვლადებზე. მესამე მეთოდში ვიძახებთ ძირითადი კლასის მეთოდს. ხედავთ რომ ქვე კლასის მეთოდს და ძირითადი კლასის მეთოდს ერთი და იგივე სახელი აქვთ, მსგავს ოპერაციას Override ქვია და ეგ იქნება ჩვენი შემდეგი მაგალითი. მთავარი წესი რომელიც სუპერ საკვანძო სიტყვას გააჩნია: ის ყოველთვის დააყენეთ ყველაფერზე წინ, პირველი ველი ნებისმიერი ოპერაციის უნდა იყოს სუპერ ველი, რა თქმა უნდა თუ აპირებთ გამოყენებას. 
და კომპილირების შემდგომ:


Override:

მეთოდი რომლის ინსტანცირებაც ხდება ქვე კლასში პროგრამისტებისთვის ნაცნობია როგორც მეთოდი რომლის გადაწერაც ხდება, ის იდენტურია ძირითადი კლასის მეთოდისა, გააჩნია მსგავსი სახელი, პარამეტრების ოდენობა და ტიპი. გადაწერის ძირითადი დანიშნულება გახლავთ შეიტანოს ზემდგომი კლასის მეთოდში ის ცვლილებები რომელიც აუცილებელია მოცემულ მომენტში პროგრამის გასაშვებად, (თუ სურვილი გვაქ რო მეთოდი არ იქნეს გადაწერილი ის უბრალოდ უნდა მოვნიშნოთ საკვანძო სიტყვით Final)როდესაც ვახდენთ მეთოდის გადაწერას აუცილებელია გამოვიყენოთ ანოტაცია, @annotation, (@ovveriden) რათა განვასხვავოთ გადაწერილი მეთოდები ჩვეულებრივი მეთოდებისგან. (ანოტაციებზე ვისაუბრებთ როდისმე), ანოტაციის მეშვეობით კომპილატორს ვაჩვენებთ რომელია გადაწერილი მეთოდი. 

დღევანდელი ხელსაწყოები იმდენად ჭკვიანია რო კომპილატორი აქეთ გეუბნება რომელი მეთოდია გადაწერილი, მაგრამ ანოტაციის გამოყენება მაინც აუცილებელია, სხვა უამრავი მიზეზის გამო, ერთი მარტივი მიზეზი გახლავთ შეცდომა დასათაურებაში. თუ გადაწერილი მეთოდი შემთხვევით შეცდომით დაასათაურეთ კომპილატორი გეტყვით და განახებთ შეცდომას, მას კი ამ შეცდომას ანოტაცია ანახებს.

თუ ზემდგომი კლასის რეფერენცია იჭერს ქვემდგომი კლასის ობეიკტს მაშინ გადაწერას სხვა წესები აქვს, მსგავს ოპერაციას ჯავაში დინამიური და სტატიკური შეკვრა ქვია რაც ნიშნავს იმას რომ ერთი ოპერაცია სრულდება კომპილირების დროს და მეორე ოპერაცია სრულდება პროგრამის გაშვების პროცესში. მეთოდის გადაწერა შესაძლებელია მხოლოდ IS-A ურთიერთობის დროს. 

გადაწერა შესაძლებელია მეთოდების თუ ის არ არის მონიშნული როგორც final ან private, ერთი და იგივე პაკეტში, მაგრამ კლასები თუ სხვა და სხვა პაკეტშია მაშინ გადაწერა შესაძლებელია მხოლოდ public და protected მხედველობის მქონე მეთოდების. 

სტატიკური მეთოდის გადაწერა: როგორც ესეთი სტატიკური მეთოდის გადაწერა შეუძლებელია, მაგრამ შესაძლებელია მისი დაჩრდილვა, როდესაც ქვე კლასი იყენებს სტატიკურ მეთოდს იგივე სახელი, ტიპით და პარამეტრებით, მაშინ არ ხდება გადაწერა, უბრალოდ ქვე კლასის მეთოდი ჩრდილავს ძირითადი კლასის მეთოდს, ან პირიქით, გააჩნია როგორი სახის ინსტანციით ვმუშაობთ, დინამიურით თუ სტატიკურით. როგორც ესეთი სტატიკური მეთოდის დაჩრდილვა არის უაზრო პრაკტიკა პროგრამირებაში, რომ დაფიქრდეთ რატომ უნდა დაჩრდილო მეთოდი რომელიც კლასის დონის მეთოდია ან საერთოდ რატომ უნდა მოახდინო ინსტანცირება სტატიკური წევრის ობიეკტის რეფერენციული ცვლადის დახმარებით, არანაირი საღი აზრი ამაში არ დევს, მაგრამ მაგალითებს მაინც ვნახავთ რომ გავერკვეთ სად არის უაზრობა დამალული. 

1. მაგალითი:

პრიმიტიული პროგრამა რომელიც გვანახებს სტანდარტულ გადაწერას. როგორც სტატიკური ისე ინსტანციური მეთოდის. 

ძირითადი კლასი ყველა სახეობის მეთოდით.
ქვე კლასი, სადაც ინსტანცირებული მეთოდები მონიშნულია ანოტაციით. 

ძირითადი კლასი. 
და კომპილირების შემდგომ ხედავთ რომ ქვე კლასმა მთლიანად დაჩრდილა ზემდგომი კლასის მეთოდები როგორც სტატიკურმა ისე ინსტანციურმა. 

იგივე მაგალითზე განვიხილოთ, დაჩრდილვა ხდება ორმხრივად ეს დამოკიდებულია იმაზე თუ რომელი ობიეკტის რეფერენციას ვიყენებთ. თუ ვიყენებთ ქვე კლასის რეფერენციას მაშინ გადაწერილი მეთოდების გამოძახება ხდება ქვე კლასიდან, მაგრამ თუ ვიყენებთ მეთოდის დაჩრდილვას (ანუ სატატიკური მეთოდის გამოზახებას) მაშინ დამოკიდებულება ხდება იმაზე თუ რომელი კლასის რეფერენციით ვმუშაობთ, ნახეთ მაგალითი. 
ქვე კლას დავამატეთ ერთი მეთოდი, რის შემდგომაც შევქმენით ობიეკტები საწყის კლასში. 
ფოტოზე ხედავთ რომ ზემდგომი კლასის რეფერენცია ვერ ხედავს მეთოდს ქვე მდგომ კლასში, მარტივი მიზეზის გამო, არ აქვს Scope ქვე მდგომ კლასზე, მიუხედავად იმისა რო ობიეკტს ინახავს ქვე მდგომი კლასისა, რაც არ უნდა მოხდეს ყოველთვის ნახავს იმ მეთოდებს რომელიც დეკლალირებულია ზემდგომ კლასშიც, როგორ ფიქრობთ რომელ მეთოდებს გამოიძახებს ზემდგომი კლასის რეფერენცია? ნახეთ მაგალითი.

კომპილირების შემდგომ:
ზემდგომი კლასის რეფერენციამ გამოიძახა ინსტანციური მეთოდები ქვემდგომი კლასისა მაგრამ სტატიკური მეთოდი ზემდგომი კლასისა. რატომ? იმიტომ რო ქვე კლასმა მოახდინა გადაწერა და ზემდგომა კლaსმა მოახდინა დაჩრდილვა. რეფერენცია ასე თუ ისე ზემდგომს ეკუთვნის, სტატიკური მეთოდი კლასის დონის მეთოდია შესაბამისად კლასის რეფერენციამ მოახდინა საკუთარი კლასის მეთოდის გამოძახება. 

მნიშვნელოვანი ასპეკტი მეთოდების გამოძახების დროს არის მათი მხედველობის არეალის გათვალისწინება, დაუშვათ თუ ძირითად კლასში გვაქ public მეთოდი და მის გადაწერას ვახდენთ ქვე კლასში protected მხედველობით, მაშინ ჯავა ამის უფლებას არ მოგვცემს, იმიტომ რო უფრო მაღალი დონის მხედველობიდან დაბალის დონის ხმედველობაზე კონვერტირება არ არის ლეგალური ოპერაცია, თუმცა პირიქით სრულიად ლეგალურია, თუ protected მხედველობა გააჩნია ზემდგომს და public მხედველობას ვანიჭებთ ქვემდგომს ჯავა ხელს არ შეგვიშლის პროგრამის გაშვებაში, მიზეზი აქაც ნათელია, მხედველობის არეალი იზრდება რაც მოთხოვნადი და ლეგალურია. ნახეთ მაგალითი. 
კომპილირებამდე ჩანს რო შესწორებებია შესატანი, ნახეთ ერორ მესიჯი:
თუმცა პირიქით რომ მოვიქცეთ. 
არანაირი ხელის შემშლელი ფაკტორი არ შეგხვდებათ.

                                                                Static & Dynamic Binding

Static Binding- არის პროცესი რომელიც ხდება კომპილირების დროს(at compile time), მას სხვანაირად ნაადრევ კავშირს ეძახიან, ყველა, სტატიკური, ფინალური და პრივატული მეთოდი კავშირში შედის ვირტუალ მანქანასთან კომპილირების დროს, ანუ ვირტუალურმა მანქანამ წინასწარ იცის ესა თუ ის ოპერაცია რა შედეგით დასრულდება, ადვილად წარმოდგენისთვის სტატიკურ კავშირს დავარქვათ ინფორმაციის ნაადრევი მიღება, ეგ არის მისი მოვალეობა და არაფერი სხვა, მაგალითიც არა ერთი გაქვთ ამ ოპერაციის ნანახი, 
ფოტოზე ხედავთ სტატიკური ურთიერთობის მაგალითს, ასეთ სიტუაციაში ვირტუალურ მანქანას არ უწევს ორ აზროვნებაში გარკვევა. ზუსტად იცის რომელ მეთოდს იძახებს. 
დინამიური კავშირი : არის დაგვიანებული ურთიერთობა, ასეთ სიატუაციაში ვირტუალურმა მანქანამ ბოლო მომენტამდე არ იცის რომელი ბრძანება გაუშვას, ის ერკვევა ბრძანებაში გაშვების პროცესში (at run time). მეთოდის გადაწერა ნათელი მაგალითია დინამიური კავშირის, ვირტუალური მანქანა მეთოდის გადაწერის დროს ბოლო მომენტში ერკვევა რომელი ბრძანების გაშვება უწევს, იმიტომ რო ერთი და იგივე დასახელების, პარამეტრების ოდენობის მეთოდებთან უწევს მუშაობა. 
ფოტოზე ხედავთ სტანდარტულ მაგალითს დინამიური კავშირის. კომპილირების შემდგომ:
დინამიურ და სტატიკურ კავშირზე საუბრის დროს ერთ-ერთი აზრი რაც მოგდის ხოლმე თავში ეს გახლავთ კასტინგი. კასტინგი არა ტიპებს არამედ ობიეკტებს შორის, ერთი ობიეკტის მეორე ობიეკტად გადაქცევა და პირიქით. გახსოვთ ალბათ რო ჯავაში ყველაფერ იწყება ძირითადი კლასიდან რომელსაც ობიეკტი ქვია. ობიეკტის მემკვიდრეა ყველა და ყველაფერი რაც იქნება ჯავა ბიბლიოთეკის გამოყენებით. შესაბამისად ობიეკტი არის სუპერკლასი ყველა კლასის და ზემდგომი ობიეკტი ყველა ობიეკტის.

UpCasting:

კომპილირება: 

განვიხილოთ რა მოხდა ფოტოზე. გვაქ კლასი სადაც გვაქ მცირე ინფორმაცია, შემდგომ კლასიდან ვქმნით ობიეკტს. და ამ ობიეკტის ცვლადს ვანიჭებთ ზემდგომ ობიეკტს.(ცნობისთვის, ობიეკტზე მაგალითი ყოველთვის დადებით შედეგამდე მიგიყვანთ და არ არის კარგი პრაკტიკა ეგეთი სახით მაგალითის ჩვენება, მაგრამ ნებისმიერ სხვა კლასზე რო გაიმეოროთ იგივე ოპერაცია იგივე შედეგს მიიღებთ, ამიტომ მეპატიება სიზარმაცე. ) გამომდინარე აქედან ზემდგომი ობიეკტი გადაიქცა(ვირტუალურად, კომპილატორისთვის) ქვე მდგომ ობიეკტად. Object obj = upcast; ამ ოპერაციის დროს. ჯავა მსგავსი ოპერაციის წარმოებას საკუთარ თავზე იღებს, რატომ? იმიტო რო მსგავსი ოპერაციის წარმოების დროს მინიმალური შანსია იმისთვის რო რამე გაუთვალისწინებელი მოხდეს, ანუ საფრთხე ფაკტიურად არ არსებობს. ამიტომაც ზედმეტი ფიქრი არ გვჭირდება. მოცემულ ოპერაციას ვამოწმებთ instanceof საკვანძო სიტყვის მეშვეობით, რომელიც ამოწმებს მემკვიდრეობას. და პასუხიც დადებითი გვაქ. შემდეგ ველზე ეგ კონვერტირება მაქ განვრცობილი, ვერ ვხედავთ მაგრამ ოპერაცია Object obj1 = (Object)new UpCastingAdnDownCasting(); ამ პრინციპით ხდება კადრს მიღმა.  ეს არის სრული ვერსია იმისა რასაც ჯავა ჩვენთვის აკეთებს. შემდგომ ამასაც ვამოწმებთ და პასუხი ისევ დადებითია. მესამე ვარიანტი გამომრჩა. Object obj1 = new UpCastingAdnDownCasting(); ასე რო მოვქცეულიყავით, ოპერაცია მაინც ლეგალური იქნებოდა. ნუ რა თქმა უნდა როგორც ყველა წესიერ , პატიოსან და კეთილსინდისიერ ზემდგომ ობიეკტს ისე სუპერ ობიეკტსაც არ აქვს წვდომა ქვემდგომი ობიეკტების მეთოდებზე. თუ მსგავსი დასახელების, პარამეტრების და ოპერაციის მეთოდის მატარებელი არ არის თვითონ. შესაბამისად ჩვენი სუპერ ობიეკტი ვერაფერს ვერ ხედავს იმ ობიეკტში რომელსაც რეალურად ემსახურება და აქ იწყება DownCasting. მაგალითებს ამ კონკრეტულ კლასში განახებთ და მერე ცალკე განვავრცობ. 
ფოტოზე წაიკითხეთ კომენტარი. კომპილირების შემდგომ:


როგორც ხედავთ იდეალურად ართმევს თავს. მაგრამ downCasting არც ისე მარტივია როგორც ეს ერთი შეხედვით ჩანს, მისი წარმოების დროს უამრავი ფაკტორის გათვალისწინება გვიწევს, 1. ის უნდა გამოიყენოთ მაშინ როცა დარწმუნებული ხართ რო დინამიური ოპერაციის დროს შეასრულებს მასზე დაკისრებულ ამოცანას, (At Run Time), და არ გაჩერდება პროგრამა. მაგალითებზე ადვილია შესწორებების შეტანა მაგრამ როცა კოდი დიდია უამრავ დროს წაიღებს ჩასწორება, 2. სწორად უნდა მოახდინოთ კონვერტირება, სწორად კონვერტირებაში მოიაზრება სწორად ობიეკტის შექმნა, უბრალოდ ვერ შექმნით ობიეკტს და მერე ამ ობიეკტს მეორე ობიეკტს ვერ მიაკრავთ. თან ცუდი რაც არის როცა ამას გააკეთებთ ჯავა არანაირ გაამფთხილებელ ნიშანს არ გაჩვენებთ რო ოპერაციის წარმოება საფრთხეს შეიცავს, 3. გაითვალისწინეთ ხშირ შემთხვევაში ვერ მოახერხებთ კასტინგის ზემოდან ქვემოთ წარმოებას, ჯავა ამის უფელაბს უბრალოდ არ მოგცემთ შეუთავსებელი ტიპების გამო. არ არის ფაკტი რო ობიეკტი რომელსაც შექმნით ზუსტად იმ ტიპის იქნება რომელის ღირებულებასაც მას მიანიჭებთ. ამაზე ჯერ კიდევ დსაწყისში ვისაუბრეთ კასტინგის დროს. მსგავს პრობლემები რო აირიდოთ თავიდან ჯობია საერთოდ არ გააკეთოთ. უამრავი საფრთხის შემცველია. ლოგიკურად ჩდება კითხვა თუ ამდენი საფრთხის მატარებელია ზემოდან ქვემოთ წვდომა მაშინ რაღატო ვიყენებთ საერთოდ? 1. იმიტომ რო მივაღწიოთ პოლიმორფიზმს 2. იმიტომ რო პროგრამა გავხადოთ კომპლექსური და რთული (მარტივ ენაზე ინფორმაცია შევფუთოთ ისე რო ჩვენც ვერ გავიგოთ, არა თუ ვინმემ გარედან. ). ß ეს ხუმრობით. 
გამოყენების წესი, downCasting-ს უსაფრთხოდ რო მიაღწიოთ, გადახედეთ თქვენ მიერ შექმნილი კლასების იერარქიას, დაუშვათ აშენებთ შენობებს, გაქვთ ძირითადი კლასი ნაგებობა, სადაც სტანდარტული მონაცემები გაქვთ ნაგებობისთვის შენახული, და ამ ნაგებობიდან იწყებთ მშენებლობას, მის მაგალითზე ააგეთ ბანკის სათაო ოფისი, ბანკმა სათაო ოფისის აგების მერე ააშენა პატარა ოფისები რაიონებში, გამომდინარე აქედან რაიონული ოფისები მემკვიდრეა ნაგებობის იმიტომ რო მის მიერ შექმნილი, მოდელით ხელმძღვანელობს. ძირითადი იდეა რომელიც კასტინგს ეხება ამ მემკვიდრეობის მიღმა გახლავთ: რაიონული ოფისი ბანკის, ბანკია? დიახ. მაშინ შესაძლებელია კასტინგი. სათაო ოფისი ბანკის ნაგებობაა? დიახ, მაშინ შესაძლებელია კასინგი, ნაგებობა რაიონული ბანკია? არა! ნაგებობა სავაჭრო ცენტრიც არის. მაშინ ნუღარ მოახდენ კასტინგს. კოდურ ენაზე ეგ შემდეგნაირად გამოიყურება. Building plan = new Building(); ნაგებობის ობიეკტი. ამის შემდგომ რო ავდგეთ და Bank main = (Bank) plan; მოვახდინოთ downCasting ჯავა ამის უფლებას მოგვცემს, ჯავას ერთადერთი რაც ადარდებს ეგ ფრჩხილებში ობიეკტის ნახვაა, მაგრამ პროგრამას რო გაუშვებ ClaccCastException Error მივიღებთ შედეგად და ბონუსად უამრავ დროსაც დაკარგავთ თუ პროგრამა დიდია. იგივე მაგალითზე Building plan = new Bank() და შემდგომ Bank main = (Bank) plan; სრულიად ლეგალური და უსაფრთხო ოპერაცია გახლავთ, რადგან სწორად მოვახდინეთ downCasting. ყველაფერ ამასთან ერთად გასათვალისწინებელია ტიპებიც, თუ ნაგებობას რამოდენიმე გეგმა აქვს, ბანკისთვის, იურიდიული ფირმისთვის. მაშინ არ არის ფაკტი რომ კონვერტირება მოხდება ნაგებობის. რადგან ზუსტად უნდა ვიცოდეთ რომელი ტიპის მატარებელია. ბანკის(Integer) თუ იურიდიული ფირმის(String), 

downCasting:
შეუძლებელია შევქმნათ ობიეკტი და ის უბრალოდ ვაქციოთ სხვა ობიეკტად. 
კომპილირების შემდგომ. შეამჩნევდით, ჯავამ არანაირი გამაფრთხილებელი ნიშანი არ გვაჩვენა. მისთვის ოპერაცია ლეგალურია. 


ფოტოზე ბოლო ორი მეთოდი მაგალითისთვის მაქ ნაჩვენები, downCasting-ის მიზანია რო ყველა ობიეკტი სტანდარტულ საწყისებს დაუბრუნდნენ, 

ანუ იხელმძღვანელონ იმ ოპერაციებით რომელიც მხოლოდ საბაზისო კლასშია. ამიტომ მსგავსი სახით ზემოდან ქვემოთ მეთოდის გამოძახება ცუდ პრაკტიკად ითვლება. მაგრამ შესაძლებელია . კომპილირების შემდგომ

კასტინგის დროს შეუთავსებლობა:

ერთ-ერთი გავრცელებული შეცდომა გახლავთ დამწყებ პროგრამისტებში. ერთი ობიეკტი ერთი ტიპის მატარებელია და მას სხვა ობიეკტად ვერ ვაქცევთ რომელიც სხვა ტიპის მატარებელია. ჯავა ამის უფელაბს Compile time არ გვაძლევს. თუმცა აქედანაც არსებობს გამოსავალი. 


და ეკრანზე გამოვა 10. 

შემდეგ თავში აბსტრაქციაზე ვისაუბრებთ. 

Objects are like people. They’re living, breathing things that have knowledge inside them about how to do things and have memory inside them so they can remember things. And rather than interacting with them at a very low level, you interact with them at a very high level of abstraction, like we’re doing right here.Here’s an example: If I’m your laundry object, you can give me your dirty clothes and send me a message that says, “Can you get my clothes laundered, please.” I happen to know where the best laundry place in San Francisco is. And I speak English, and I have dollars in my pockets. So I go out and hail a taxicab and tell the driver to take me to this place in San Francisco. I go get your clothes laundered, I jump back in the cab, I get back here. I give you your clean clothes and say, “Here are your clean clothes.”You have no idea how I did that. You have no knowledge of the laundry place. Maybe you speak French, and you can’t even hail a taxi. You can’t pay for one, you don’t have dollars in your pocket. Yet, I knew how to do all of that. And you didn’t have to know any of it. All that complexity was hidden inside of me, and we were able to interact at a very high level of abstraction. That’s what objects are. They encapsulate complexity, and the interfaces to that complexity are high level
                                                                                                                      Steve Jobs

წარმატებები:

No comments:

Post a Comment