მოგესალმებით პატივცემულო ფორუმელებო
ამ თემის გახსნა იმიტომ გადავწყვიტე რომ ბევრი დამწყები პროგრამისტია რომლებსაც სწავლა წყურიათ და არ იციან სად ეძებონ ინფორმაცია.
მეც გამომიცდია ეს პერიოდი და ვიცი რა ძნელია.მოდით ყველამ გავუზიაროთ ერთმანეთს ჩვენი ცოდნა და გამოცდილება. მეც სიამოვნებით წავიკითხავდი ნებისმიერ სფეროში ჩემზე კომპეტენტური პირის სტატიას, ამიტომ თქვენც იაქტიურეთ
პირველი ლექცია:
ობიექტ ორიენტირებული პროგრამირება ანუ OOP.რატომ მაინც და მაინც OOP? პასუხი მარტივია, ნებისმიერი პროგრამისტი ვისაც ობიექტ ორიენტირებული პროგრამირების პრინციპები არ ესმის და მას იგნორირებას უკეთებს ის ჩემი აზრით ვერასდროს გახდება კარგი პროგრამისტი. OOP-ს ძალის დემონსტრირებისთვის გადავწყვიტე გამომეყენებინა ჩემი საყვარელი ენა C#, ამიტომ თუ ჩემი ნაჯღაბნის წაკითხვას გადაწყვიტავთ გაითვალისწინეთ რომ ამ ენის სინტაქსის ცოდნაა საჭირო რომ აზრი გამოიტანოთ. ხო და კიდევ, იმედია იმის აღნიშვნა არ დამჭირდება რომ ეს პოსტი არაა განკუთვნილი ისეთ გველეშაპებზე როგორებიცაა Hub(ჩვენი პატივცემული მოდერი
), Gode, md5, ezeki, herraldo, Abnormalia etc, არამედ იმათთვის ვინც ეხლა დაიწყო პროგრამირების სწავლა
მაინც რას ნიშნავს ობიექტ ორიენტირებული პროგრამირება. ეს ნიშნავს ამოცანა დაყო გარკვეულ ნაწილებად რომლებსაც კლასები(Class) წარმოადგენს და ამ ნაწილებს განუსაზღვრო თავიანთი კონკრეტული მოვალეობები. კლასი წარმოადგენს ობიექტს რომელიც შედგება მეთოდებით(Methods), მოვლენებით(Events) და (ეს არ ვიცი ქართულად როგორ ვთარგმნო
) ფროფერთებით(Properties). უფრო ნათელი წარმოდგენა რომ შეგექმნათ გახსენით Visual Studio, შექმენით ახალი Windows Application პროექტი და ფორმაზე დააგდეთ Timer კომპონენტი. გადადით Properties ფანჯარაზე და ნახავთ რომ ჩამოწერილია Enabled, GenerateMember, Interval და ასე შემდეგ. ესენი არის კლასის ფროფერთები რომლებიც მიმართავს მისივე ცვლადებს და არეგულირებს მის მოქმედებებს ჩვენი სურვილისამებრ. Timer კლას-ს გააჩნია ერთი მოვლენა Tick რომელიც გვატყობინებს რომ ჩვენს მიერ მითითებული Interval ფროფერთი ამოიწურა. აგრეთვე მეთოდები როგორიცა Start, Stop და ა.შ.
თუ თქვენ ჩემს მიერ ზემოთ დაწერილი ვერ გაიგეთ მაშინ შეწყვიტეთ კითხვა, ჯერ არ ყოფილხართ მზად OOP-სთან საზიარებლად
მოდით დავიწყოთ ყველაზე მარტივიდან, შევქმნათ ახალი კლასი. ამისთვის გადადით Solution Explorer-ში, დააჭირეთ მაუსის მარჯვენა ღილაკი თქვენს პროექტზე, მიიტანეთ კურსორი Add-ზე და სუბმენიუში აირჩიეთ Class. მოცემულ ფანჯარაში ფაილს დაარქვით Car.cs და დააჭირეთ Add-ს. ვიჟუალ სტუდიომ ავტომატურად დაგვიგენერირა შემდეგი კოდი:
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsApplication1
{
class Car
{
}
}
class Car <-- ეს არის ჩვენი ახლადშექმნილი კლასი. მასში უნდა მოვახდინოთ ჩვენი მეთოდების, მოვლენების და ფროფერთების აღწერა. დავიწყოთ ყველაზე მარტივიდან, წარმოვადგინოთ მანქანის მახასიათებლები ფროფერთებად რომლებიც ყველა მანქანას გააჩნია. მაგ. სიჩქარე, წონა, ძრავის კუბატურა, ფერი და კარებების რაოდენობა. ამისთვის ჩვენ უნდა გამოვაცხადოთ თითო მახასიათებლისთვის თითო ცვლადი რომლებიც მათ მნიშვნელობას შეინახავენ.
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
namespace WindowsApplication1
{
class Car
{
short _Speed;
short _Weight;
short _Doors;
double _Motor;
Color _Color;
}
}
როგორც ხედავთ გამოვაცხადე ცვლადები და ჩავამატე ახალი namespace-ი System.Drawing რომელშიც
Color სტრუქტურაა აღწერილი. სტრუქტურებზეც ვისაუბრებთ მოგვიანებით. ვინაიდან და რადგანაც ობიექტ ორიენტირებული პროგრამირების პრინციპი კრძალავს კლასში არსებული ცვლადებზე პირდაპირ წვდომას ამიტომ ჩვენ დაგვჭირდება აქსესორების(Accessors) გამოყენება რომ ზემოთ აღნიშნულ ცვლადებს მივანიჭოთ და პირიქით, წავიკითხოთ მათი მნიშვნელობა.
C#-ში აქსესორები წარმოდგენილია set და get-ით. როგორც უკვე მიხვდებოდით set გამოიყენება ცვლადისთვის მნიშვნელობის მისანიჭებლად ხოლო get მისი წაკითხვისთვის. ფროფერთების გამოცხადების შემდეგ აქსესორების საშუალებით ჩენი კოდი გამოიყურება ესე:
class Car
{
short _Speed;
short _Weight;
double _Motor;
short _Doors;
Color _Color;
public short Speed { get { return _Speed; } set { _Speed = value; } }
public short Weight { get { return _Weight; } set { _Weight = value; } }
public short Doors { get { return _Doors; } set { _Doors = value; } }
public double Motor { get { return _Motor; } set { _Motor = value; } }
public Color Color { get { return _Color; } set { _Color = value; } }
}
როგორც ხედავთ გამოვაცხადე ახალი ცვლადები რომლებიც აქსესორების საშუალებით პირდაპირ გადიან თავიანთთვის შესაბამის ცვლადებზე. უფრო ნათელი რომ გახდეს სურათი წარმოიდგინეთ ეს კოდი:
Car myCar = new Car();
myCar.Speed = 240;
short speed = myCar.Speed;
ამ კოდში, მეორე ხაზზე ჩვენ Speed ფროფერთის მივანიჭეთ მნიშვნელობა, რომლიც 240-ია. აქ ამოქმედდა set აქსესორი და გამოიძახა შემდეგი კოდი: _Speed = value;(value არის მნიშვნელობა რომელიც რომელიც ჩვენ მივანიჭეთ) ანუ რეალურად ჩვენ Speed ცვლადს კი არ მივანიჭეთ მნიშვნელობა არამედ _Speed-ს. Speed-ი უბრალოდ მაჩვენებელია _Speed ცვლადზე რომ პირდაპირი წვდომა არ გვქონდეს მასზე როგორც ამას OOP მოითხოვს. რაც შეეხება მესამე ხაზს, ალბათ მიხვდებოდით, აქ ამოქმედდა get აქსესორი და შესაბამისად შემდეგი კოდი: return _Speed; get აქსესორი-ს გამოძახებისას ვიყენებთ return ოპერატორს რომელიც გვიბრუნებს ცვლადის მნიშვნელობას.
Modifiersკლასში ყველა ცვლადს, ფროფერთის, მეთოდს თუ მოვლენას გააჩნია საკუთარი Modifier(ქართულად არ ვიცი როგორ ითარგმნება
). Modifier განსაზღვრავს თუ რამდენად ხილვადია ესა თუ ის ობიექტი. არსებობს შემდეგი ტიპის Modifier-ები:
private: ეს ნიშნავს რომ ამ Modifier-ით გამოცხადებული ნებისმიერი ობიექტი იქნება ხილვადი მხოლოდ კლასის შიგნით. მას გარედან ვერ მიმართავ. C#-ში ნებისმიერ გამოცხადებულ ობიექტს თუ არ მივუთითეთ Modifier მაშინ ის იგულისხმება როგორც Private. ლუსტრაციისთვის შევხედოთ ჩვენს კლასს. ის ცვლადები რომლებიც "_" სიმბოლოთი იწყება გამოცხადებულია Modifier-ის გარეშე, ანუ ისინი არიან private და მათ კლასის გარედან ვერ მივმართავთ. მაგალითად თქვენ რომ დაწეროთ შემდეგი კოდი:
Car myCar = new Car();
myCar._Speed = 240; <-- კომპილატორი აქ ამოგიგდებთ შეცდომას
რადგან _Speed ცვლადი რეალურად არსებობს, მაგრამ იგი private-ია და მისი მიმართვა შეიძლება მხოლოდ კლასის შიგნით(და ჩვენც ასე ვიქცევით, მას მივმართავთ აქსესორების საშუალებით). _Speed ცვლადს დასაწყისში რომ მივუწეროთ public ამ შემთხვევაში კომპილატორი შეცდომას აღარ მოგვცემს და ჩვენი კოდიც დაკომპილირდება, მაგრამ ამითი ჩვენ OOP-ს პრინციპს დავარღვევთ, რადგან ცვლადზე პირდაპირი წვდომას მოვიპოვებთ.
public: ამ Modifier-ით გამოცხადებული ნებისმიერი ობიექტი ხილვადი იქნება არა მხოლოდ კლასის შიგნით, არამედ გარედანაც. მაგალითისთვის ისევ ჩვენი კლასი ავიღოთ. ყველა გამოცხადებულ ფროფერთებს წინ აქვთ მიწერილი public, რაც იმას ნიშნავს რომ ჩვენ შეგვიძლია მათ მივმართოთ გარედან.
protected: ამაზე ცოტა მოგვიანებით ვისაუბრებთ, როცა მემკვიდრეობას შევეხებით.
Internal: თუ თქვენ კლასს აღწერთ ასემბლიში(Assembly. .NET-ის dll ფაილი), მაშინ თქვენს მიერ გამოცხადებული კლასი/ობიექტი იქნება ხილვადი მხოლოდ თქვენს ასემბლიში.
Protected Internal: იგივეა რაც protected ოღონდ ესეც ასემბლის შიგნით მოქმედებს.
Eventsმოვლენები როგორც უკვე ზევით ავღნიშნეთ გვატყობინებს კლასის ამა თუ იმ მოქმედებას. Timer კლასს აქვს ერთი მოვლენა, რომელიც გამოიძახება როდესაც ჩვენს მიერ მითითებული ინტერვალი ამოიწურება, მაგრამ როგორ ჩავამატოთ ჩვენს კლასს ჩვენთვის სასურველი მოვლენები? ძალიან მარტივია. მოდით ჩვენს კლასს დავამატოთ ორი public მეთოდი, Start() & Stop() და ერთი bool ფროფერთი რომელიც აღწერს მანქანა დაძრულია თუ არა ადგილიდან.
class Car
{
short _Speed;
short _Weight;
double _Motor;
short _Doors;
Color _Color;
bool _Started;
public short Speed { get { return _Speed; } set { _Speed = value; } }
public short Weight { get { return _Weight; } set { _Weight = value; } }
public short Doors { get { return _Doors; } set { _Doors = value; } }
public double Motor { get { return _Motor; } set { _Motor = value; } }
public Color Color { get { return _Color; } set { _Color = value; } }
public bool Started{ get {return _Started;} }
public void Start()
{
_Started = true;
}
public void Stop()
{
_Started = false;
} }
ალბათ შეამჩნევდით რომ Started ფროფერთიში მარტო get აქსესორი მაქვს გამოყენებული. ეს იმას ნიშნავს რომ გარედან ამ ცვლადს წაიკითხავენ, მაგრამ შეცვლით ვერ შეცვლიან რადგან set აქსესორი არ გამომიყენებია, შესაბამისად მისთვის მნიშვნელობის მინიჭება შესაძლებელია მხოლოდ კლასის შიგნით, როდესაც პირდაპირ მივმართავთ _Started ცვლადს.
ეხლა პრაქტიკულად ყველაფერი გაგვაჩნია გარდა დელეგატებისა(delegates) იმისთვის რომ ჩავამატოთ ორი მოვლენა: OnStarted და OnStopped, რომლებიც იქნებიან გამოძახებულები Start() და Stop() მეთოდების გამოძახებისას. რა არის დელეგატი? დელეგატი იგივე მაჩვენებელია(Pointer) ფუნქციაზე, უბრალოდ .NET-ში მას სახელი შეუცვალეს. დელეგატის საშუალებით ჩვენ ავღწერთ ფუნქციის პარამეტრებს და დასაბრუნებელ მნიშვნელობას. მაგ:
public delegate void Started(object sender, EventArgs e);
public delegate void Stopped(object sender, EventArgs e);
ძალიან კარგი
ეხლა ვიცით თუ რა პარამეტრები უნდა ქონდეს ჩვენს მოვლენას. ეხლა კი თვითონ მოვლენები გამოვაცხადოთ.
public event Started OnStarted;
public event Stopped OnStopped;
ეხლა ჩავამატოთ Start() და Stop() მეთოდებში მოვლენების გამოძახების კოდი.
public void Start()
{
_Started = true;
if(OnStarted != null) //ეს შემოწმება აუცილებელია, რადგან შეიძლება OnStarted მოვლენას Event Handler არ ქონდეს მინიჭებული
OnStarted(this, new EventArgs());
}
public void Stop()
{
_Started = false;
if(OnStopped != null)
OnStopped(this, new EventArgs());
}
this არის მაჩვენებელი მიმდინარე კლასის ინსტანსზე რომელსაც OnStarted-ის პირველ პარამეტრად გადავცემთ რომ შემდეგ Event Handler-ში გავარკვიოთ თუ საჭირო გახდა რომელმა კლასის ინსტანსმა გამოიძახა მიმდინარე მოვლენა. ეს ძირითადად მაშინ გვჭირდება როდესაც რამდენიმე ინსტანს-ს ერთი Event Handler-ი აქვთ.
ჩვენი კლასი მზადაა, ეხლა ისღა დაგვრჩენია შექმნისას მივანიჭოთ Event Handler-ები. ამისთვის ვწერთ შემდეგ კოდს:
Car myCar = new Car();
myCar.OnStarted += new Started(Car_OnStarted);
myCar.OnStopped += new Stopped(Car_OnStopped);
Car_OnStarted და Car_OnStopped არის ჩვეულებრივი პროცედურები რომლის პარამეტრები შეესაბამება Started და Stopped დელეგატებისას.
მორჩა, როცა თქვენ გამოიძახებთ კლასის Start()-ს და Stop() მეთოდებს, შესაბამისად მოვლენაზე მინიჭებული Event Handler-ებიც გამოიძახება ავტომატურად, ანუ ჩვენს შემთხვევაში Car_OnStarted და Car_OnStopped.
ჯერ ჯერობით სულ ეს იყოს, მეტის დაწერა ვერ მოვასწარი დროის უქონლობის გამო. მომავალში მემკვიდრეობაზე, კონსტრუქტორ/დესტრუქტორებზე და პოლიმორფიზმზე მოგითხრობთ. მანამდე კარგი იქნება თუ თქვენც დაყრით თქვენს ნაშრომებს
მოდერს ვთხოვ ეს თემა Hello World-ში არ გადაიტანოს, რადგან შეიძლება ვინმემ ისეთი სტატია დაპოსტოს რომელიც არ შეესაბამებოდეს იმ განყოფილებას. ჩემი თხოვნა იქნება მხოლოდ ნოვიჩოკებისთვის ნუ გამოვიყენებთ ამ თემას.
This post has been edited by Dato0011 on 9 Nov 2006, 15:26