Nauka tworzenia hierarchii klas przy użyciu dziedziczenia oraz zrozumienie roli modyfikatora dostępu protected. Student dowie się, jak wywoływać konstruktor bazowy, tworzyć klasy statyczne oraz jak korzystać z klas zagnieżdżonych i przestrzeni nazw.
Firma "Auto-Premium" dynamicznie się rozwija i wprowadza do oferty nie tylko samochody, ale również motocykle. Zauważasz, że oba te typy pojazdów mają wiele wspólnych cech, takich jak marka czy rok produkcji, ale różnią się też unikalnymi parametrami – samochody mają liczbę drzwi, a motocykle mogą posiadać wózek boczny. To idealny moment na wprowadzenie techniki dziedziczenia, aby nie powielać kodu i zachować porządek w systemie.
Projektujesz ogólną klasę bazową "Pojazd", która staje się fundamentem dla bardziej wyspecjalizowanych klas "Samochod" i "Motocykl". Wykorzystujesz modyfikator "protected", aby Twoje "dzieci" (klasy pochodne) miały swobodny dostęp do kluczowych pól rodzica, jednocześnie chroniąc te dane przed dostępem z zewnątrz (np. bezpośrednio z poziomu metody Main). Aby mieć pełny wgląd w skalę biznesu, wprowadzasz statyczny licznik, który automatycznie zlicza każdy nowy pojazd trafiający do bazy. Dzięki strukturze przestrzeni nazw (namespaces), Twój kod staje się profesjonalnie zorganizowany i gotowy na dalszą rozbudowę.
using System;
using System.Collections.Generic;
// Używamy własnej przestrzeni nazw
using LaboratoriumOOP.Modele;
namespace LaboratoriumOOP.Modele
{
// KLASA BAZOWA: Fundament hierarchii
public class Pojazd
{
// protected: widoczne tylko w tej klasie i klasach pochodnych
protected string Marka;
protected int Rok;
// static: pole współdzielone przez wszystkie instancje (licznik globalny)
private static int _licznikPojazdow = 0;
public Pojazd(string marka, int rok)
{
Marka = marka;
Rok = rok;
_licznikPojazdow++;
Console.WriteLine($"[INFO] Dodano nowy pojazd do bazy: {marka}.");
}
public static void WyswietlStanKomisu()
{
Console.WriteLine($"\n--- STAN KOMISU: {_licznikPojazdow} pojazdów ---");
}
public virtual void WyswietlInfo()
{
Console.Write($"Pojazd: {Marka} ({Rok})");
}
}
// DZIEDZICZENIE: Samochod "jest" (IS-A) Pojazdem
public class Samochod : Pojazd
{
public int LiczbaDrzwi { get; set; }
// base: wywołanie konstruktora klasy bazowej
public Samochod(string marka, int rok, int drzwi) : base(marka, rok)
{
LiczbaDrzwi = drzwi;
}
public override void WyswietlInfo()
{
base.WyswietlInfo();
Console.WriteLine($" [Samochód, Drzwi: {LiczbaDrzwi}]");
}
}
// SEALED: zapobiega dalszemu dziedziczeniu po tej klasie
public sealed class Motocykl : Pojazd
{
public bool CzyMaWozek { get; set; }
public Motocykl(string marka, int rok, bool wozek) : base(marka, rok)
{
CzyMaWozek = wozek;
}
public override void WyswietlInfo()
{
base.WyswietlInfo();
string wozekInfo = CzyMaWozek ? "Tak" : "Nie";
Console.WriteLine($" [Motocykl, Wózek boczny: {wozekInfo}]");
}
}
}
namespace LaboratoriumOOP
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("--- ZADANIE 05: Dziedziczenie i statyczne elementy ---\n");
// UPCASTING: Możemy przechowywać różne pojazdy w jednej liście typu Pojazd
List flota = new List();
flota.Add(new Samochod("Volvo", 2020, 5));
flota.Add(new Motocykl("Yamaha", 2022, false));
flota.Add(new Samochod("Tesla", 2024, 4));
// Próba dostępu:
// Console.WriteLine(flota[0].Marka); // BŁĄD KOMPILACJI - Marka jest protected!
Console.WriteLine("\nZawartość floty:");
foreach (var p in flota)
{
p.WyswietlInfo(); // Polimorficzne wywołanie metody
}
// Dostęp do metody statycznej przez nazwę klasy, nie przez obiekt
Pojazd.WyswietlStanKomisu();
Console.WriteLine("\nZakończono. Naciśnij klawisz...");
Console.ReadKey();
}
}
}