Zrozumienie koncepcji klas abstrakcyjnych jako niekompletnych szablonów oraz metod abstrakcyjnych jako wymuszenia implementacji w klasach pochodnych. Student dowie się, dlaczego nie można tworzyć instancji klas abstrakcyjnych i jaka jest różnica między metodą wirtualną (opcjonalną) a abstrakcyjną (obowiązkową).
W miarę rozwoju systemu dla komisu "Auto-Premium" dostrzegasz pewną nielogiczność: na placu nigdy nie pojawia się po prostu bliżej nieokreślony "Pojazd". Zawsze jest to albo konkretny "Samochod", albo konkretny "Motocykl". Sam obiekt typu "Pojazd" jest zbyt ogólny, by mógł istnieć jako realny byt, ale jest niezbędny jako wspólny fundament dla wszystkich innych typów maszyn. Decydujesz się więc na przekształcenie klasy bazowej w klasę abstrakcyjną (abstract class).
Dzięki temu wprowadzasz "bezpiecznik" – nikt omyłkowo nie stworzy obiektu samej bazy. Jednocześnie, jako zarządca komisu, musisz zadbać o finanse. Wprowadzasz obowiązek zaimplementowania metody "ObliczPodatekDrogowy()". Logika tego wyliczenia jest skrajnie różna: dla samochodów zależy od emisji spalin, a dla motocykli od pojemności silnika. Robiąc metodę abstrakcyjną (abstract method), wymuszasz na każdym programiście dopisującym nowy typ pojazdu (np. Ciężarówka), aby samodzielnie zdefiniował tę logikę. Jeśli tego nie zrobi, program się nie skompiluje. To potężne narzędzie do utrzymania porządku i narzucania reguł w dużych projektach IT.
using System;
using System.Collections.Generic;
namespace LaboratoriumOOP
{
// KLASA ABSTRAKCYJNA: Nie pozwala na tworzenie własnych instancji.
// Jest jedynie wzorcem/kontraktem dla innych klas.
public abstract class Pojazd
{
public string Marka { get; set; }
public double Cena { get; set; }
protected Pojazd(string marka, double cena)
{
Marka = marka;
Cena = cena;
}
// METODA ABSTRAKCYJNA: Brak ciała (implementacji).
// Każda klasa pochodna MUSI ją zaimplementować (override).
public abstract double ObliczPodatek();
// METODA WIRTUALNA: Posiada ciało, podklasy MOGĄ ją zmienić.
public virtual void Uruchom()
{
Console.WriteLine($"Systemy pojazdu {Marka} zostały uruchomione.");
}
}
public class Samochod : Pojazd
{
public Samochod(string marka, double cena) : base(marka, cena) { }
// Obowiązkowa implementacja kontraktu
public override double ObliczPodatek()
{
return Cena * 0.12; // Podatek 12% od ceny
}
public override void Uruchom()
{
base.Uruchom();
Console.WriteLine(" -> Włączono wycieraczki i światła drogowe.");
}
}
public class Motocykl : Pojazd
{
public Motocykl(string marka, double cena) : base(marka, cena) { }
// Obowiązkowa implementacja kontraktu
public override double ObliczPodatek()
{
return 250.0; // Stała stawka podatku dla motocykli
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--- ZADANIE 07: Abstrakcja i klasy bazowe ---\n");
// BŁĄD KOMPILACJI - nie można utworzyć obiektu typu abstrakcyjnego:
// Pojazd p = new Pojazd("Coś", 100);
List katalog = new List
{
new Samochod("Audi", 50000),
new Motocykl("Kawasaki", 15000),
new Samochod("Fiat", 10000)
};
foreach (var item in katalog)
{
Console.WriteLine($"Pojazd: {item.Marka}, Cena: {item.Cena} PLN");
Console.WriteLine($"Należny podatek: {item.ObliczPodatek()} PLN");
item.Uruchom();
Console.WriteLine("------------------------------------------");
}
Console.WriteLine("\nWNIOSEK: Abstrakcja pozwala wymuszać spójne zachowanie ");
Console.WriteLine("we wszystkich klasach pochodnych.");
Console.ReadKey();
}
}
}