среда, 10. фебруар 2016.

Apstraktne klase u C# programskom jeziku



Svaka klasa koja sadrži ključnu reč abstract i koja ima najmanje jednu apstraktnu metodu se naziva apstraktna klasa. Apstraktna metoda je metoda koja sadrži ključnu reč abstract i koja nema ni telo ni implementaciju. Apstraktna klasa ne može da se instancira dok svaka njena apstraktna metoda mora da bude nadjačana u svakoj ne apstraktnoj klasi koja nasleđuje apstraktnu klasu. To jednostavno znači da apstraktnu klasu i njene apstraktne metode koristite kad niste sigurni kakva će biti implementacija neke metode ali vam je ta metoda neophodna. Apstraktna klasa je u svakom slučaju nepotpuna klasa. 


( Apstraknta klasa je klasa koja ne može imati objekte )

Na primer, pretpostavite da u vašem projektu morate imati klasu koja predstavlja konekciju sa bazom podataka, međutim vi ne znate kakve će sve baze koristiti kompanija za koju radite projekat.


public abstract class Connection
{
public abstract string ConnectionString();

}

Tada pravite apstraktnu klasu sa apstraktnom metodom koja predstavlja konekciju sa bazom podataka i ostavljate kompaniji da prilikom korišćenja vaše apstraktne klase u drugoj klasi nadjačaju metodu za konekciju i definišu njeno ponašanje.

class Program : Connection
{
public override string ConnectionString()
       {
return "ConnectionString for the database!";

}          
}

Na ovaj način svako ko na primer hoće da vidi tabelu zaposlenih mora implementirati konekciju sa bazom podataka u kojoj se podaci zaposlenih nalaze. Možda kompanija ima posebnu bazu podataka i tabelu zaposlenih u Beogradu i jednu drugu u Novom Sadu i podaci su fizički odvojeni, što nije praksa ali se dešava kad velika kompanija kupi malu. Onda vaša apstraktna klasa je idealno rešenje za sve vaše konekcije sa bazama podataka.

Koje su još stvari bitne za apstraktnu klasu? 


Najbitnija stvar kod apstraktnih klasa je da se one koriste kada generalizacijom ne možete da obezbedite potpunu funkcionalnost drugih klasa jer se njihova funkcionalnost realizuje na drugačije načine. Apstraktne klase se koriste i za bezbednosne svrhe da onemoguće inicijalizaciju klase. Za razliku od statičkih klasa koji ne mogu da se nasleđuju, apstraktna klasa mora da se nasledi. Znači za statičku klasu se podrazumeva da je sealed i bez ključne reči sealed dok apstraktna klasa ne može da sadrži ključnu reč sealed jer je abstract kontradiktorno od sealed. Apstraktne metode su automatski virtualne ali ako koristite ključnu reč virtual dobiće te grešku. Programeri C# nikad ne zovu apstraktnu metodu virtualnom metodom, kao što to rade C++ programeri; već je zovu samo apstraktna metoda. U C# programskom jeziku ključnu reč virtual ne možete koristiti ni kod statičnih metoda, nadjačanih metoda i privatnih metoda. Kad nasledite apstraktnu klasu vi morate obezbediti funkcionalnost za svaku apstraktnu metodu u apstraktnoj klasi. Pogledajte sledeći primer apstraktne klase.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractClass
{
    public abstract class Employee
    {
        public int ID_Employee { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Occupation { get; set; }

        public string FullName() => FirstName + " " + LastName;

        public abstract decimal Salary();

    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractClass
{
    class EmployeeFullTime : Employee
    {
        public decimal MonthlyPaid { get; set; }
        public decimal SalaryIncrease { get; set; }
        public string Status { get; } = "Full Time Employed";

        public override decimal Salary() => MonthlyPaid + SalaryIncrease;
                     
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractClass
{
    class EmployeeContract : Employee
    {
        public short WorkDays { get; set; }
        public decimal HourlyPaid { get; set; }
        public string Status { get; } = "Contract Employed";

        public override decimal Salary() => HourlyPaid * (WorkDays * 8);
              
    }
}

using System;
using static System.Console;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AbstractClass
{
    class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Salary Report" + Environment.NewLine);

            EmployeeFullTime employee1 = new EmployeeFullTime();
            employee1.ID_Employee = 1001;
            employee1.FirstName = "Manuel";
            employee1.LastName = "Radovanovic";
            employee1.Occupation = "Programmer";
            employee1.MonthlyPaid = 4375.85M;
            employee1.SalaryIncrease = employee1.MonthlyPaid / 5;

            Program program = new Program();
            program.Print(employee1.ID_Employee, employee1.FullName(), employee1.Occupation, employee1.Status, employee1.Salary());

            WriteLine(Environment.NewLine + new String('-', 20) + Environment.NewLine);

            EmployeeContract employee2 = new EmployeeContract();
            employee2.ID_Employee = 5457;
            employee2.FirstName = "Erica";
            employee2.LastName = "Bort";
            employee2.Occupation = "Designer";
            employee2.WorkDays = 20;
            employee2.HourlyPaid = 15.64M;

            program.Print(employee2.ID_Employee, employee2.FullName(), employee2.Occupation, employee2.Status, employee2.Salary());

            ReadKey();

        }

        private void Print(int ID, string fullName, string occupation, string status, decimal salaryEmployee)
        {
            WriteLine("ID Employee: " + ID);
            WriteLine("Employee: " + fullName);
            WriteLine("Occupation: " + occupation);
            WriteLine("Status: " + status);
            string salary = String.Format("{0:C}", salaryEmployee);
            WriteLine("Salary: " + salary);

        }
    }
}

Kao što možete videti u navedenom programu, apstraktna klasa ima samo jednu apstraktnu metodu. To je metoda koja izračunava platu zaposlenog. Međutim obračun plate za zaposlenu osobu i za osobu koja radi na ugovor imaju različita izračunavanja. Zato je rešenje apstraktne metode idealno jer prepušta klasama koje nasleđuju apstraktnu klasu da implementiraju različita izračunavanja plata. U navedenom programu vam može biti i malo čudno pisanje metoda FullName() i Salary(), ali to je novi način pisanja metoda u C# 6.0 programskom jeziku. Takođe obratite pažnju da vi možete imati auto propertije samo za čitanje i da im možete eksplicitno dodeliti vrednost. Sve je to prednost korišćenja C# verzije 6.0. Kad pokrenete navedeni program, rezultati će biti isti:

Salary Report

ID Employee: 1001
Employee: Manuel Radovanovic
Occupation: Programmer
Status: Full Time Employed
Salary: $5,251.02
--------------------
ID Employee: 5457
Employee: Erica Bort
Occupation: Designer
Status: Contract Employed
Salary: $2,502.40


Kako izgleda prethodni program možete pogledati i na video-u:



( C# 6.0 Tutorial - Fundamentals - 38. Abstract Class )