01
Fundament: klasa jako szablon i obiekt jako byt
Cel zadania

Zrozumienie podstawowej różnicy pomiędzy klasą (jako definicją typu) a obiektem (jako konkretnym wystąpieniem tej klasy w pamięci). Student nauczy się tworzyć proste klasy, deklarować pola i metody oraz operować na referencjach do obiektów, dostrzegając jednocześnie ryzyka wynikające z braku kontroli dostępu do danych (braku hermetyzacji).

Scenariusz problemowy

Wyobraź sobie, że prowadzisz nowoczesny komis samochodowy "Auto-Premium". Do sprawnego zarządzania ofertą potrzebujesz cyfrowego odzwierciedlenia pojazdów znajdujących się na placu. Tworzysz więc klasę "Samochod", która działa jak szablon (plan budowy) dla każdego nowo sprowadzonego auta. Na początku, ze względu na prostotę, wszystkie cechy pojazdu (marka, model, rok produkcji) decydujesz się upublicznić.

Szybko jednak zauważasz problem: ponieważ każdy ma swobodny dostęp do danych, do systemu trafiają absurdalne informacje. Jeden z pracowników omyłkowym wpisem ustala rok produkcji pojazdu na -500, a inny pozostawia pole marki puste. System akceptuje te dane bez mrugnięcia okiem, co prowadzi do błędów w raportach. Dodatkowo, podczas próby kopiowania danych między pojazdami, zauważasz dziwne zjawisko: zmiana parametrów jednego auta magicznie wpływa na drugie. To doskonały moment, aby zrozumieć, jak działają referencje i dlaczego bezpośredni dostęp do pól klasy jest niebezpieczną praktyką.

Opis wykonania
  • Zdefiniuj przestrzeń nazw LaboratoriumOOP, w której znajdą się Twoje klasy.
  • Stwórz klasę Samochod, która będzie posiadać publiczne pola: marka (string), model (string) oraz rokProdukcji (int).
  • Dodaj do klasy metodę WyswietlInformacje(), która wypisuje dane pojazdu w czytelnym formacie.
  • W metodzie Main utwórz pierwszy obiekt klasy Samochod (np. auto1) używając operatora new.
  • Przypisz wartości do pól obiektu auto1 i wywołaj jego metodę informacyjną.
  • Zademonstruj błąd walidacji: utwórz obiekt auto2 i przypisz mu nielogiczny rok produkcji (np. -500).
  • Zwróć uwagę, że kompilator nie zgłasza błędu, mimo że dane są merytorycznie błędne.
  • Zademonstruj działanie referencji: stwórz zmienną auto3 i przypisz do niej auto1 (auto3 = auto1).
  • Zmień markę w obiekcie auto3 i sprawdź, co stało się z danymi w auto1.
  • Wyciągnij wnioski na temat alokacji obiektów na stercie i współdzielenia referencji.
  • Podsumuj działanie Garbage Collectora, który automatycznie sprząta obiekty, do których nie ma już żadnych odniesień.
Kod źródłowy
Program.cs
using System;

namespace LaboratoriumOOP
{
    // KLASA: To szablon (blueprint), który mówi kompilatorowi, 
    // jakie cechy (pola) i zachowania (metody) będzie miał każdy obiekt tego typu.
    public class Samochod
    {
        // POLA PUBLICZNE: To cechy obiektu dostępne "z zewnątrz".
        // UWAGA: W profesjonalnym kodzie unika się pól publicznych na rzecz właściwości.
        // Tutaj używamy ich, aby pokazać problem braku kontroli nad danymi.
        public string marka;
        public string model;
        public int rokProdukcji;

        // METODA: Definiuje czynność, którą obiekt potrafi wykonać.
        // PascalCase: Nazwy metod w C# zaczynamy wielką literą.
        public void WyswietlInformacje()
        {
            Console.WriteLine($"Pojazd: {marka} {model}, Rok produkcji: {rokProdukcji}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("--- ZADANIE 01: Klasy, obiekty i referencje ---\n");

            // OBIEKT (Instancja): Konkretny byt stworzony na podstawie szablonu klasy.
            // Operator 'new' alokuje pamięć na STERCIE (Heap) i zwraca REFERENCJĘ (adres).
            Samochod auto1 = new Samochod();
            auto1.marka = "Toyota";
            auto1.model = "Corolla";
            auto1.rokProdukcji = 2022;

            Console.WriteLine("1. Informacje o prawidłowym obiekcie:");
            auto1.WyswietlInformacje();

            // PROBLEM BRAKU HERMETYZACJI:
            // Możemy wpisać dowolne dane, ponieważ pola są publiczne i nie mają walidacji.
            Samochod auto2 = new Samochod();
            auto2.marka = ""; // Pusta marka
            auto2.rokProdukcji = -500; // Absurdalny rok produkcji
            
            Console.WriteLine("\n2. Demonstracja błędnych danych (brak walidacji w polach publicznych):");
            auto2.WyswietlInformacje();

            // REFERENCJE VS WARTOŚCI:
            // Zmienne typów obiektowych przechowują adres w pamięci, a nie samą wartość.
            Console.WriteLine("\n3. Demonstracja współdzielenia referencji:");
            Samochod auto3 = auto1; // auto3 teraz wskazuje na ten sam obszar pamięci co auto1
            auto3.marka = "Lexus"; // ZMIENIAMY auto3...
            
            Console.WriteLine("Po zmianie marki w auto3:");
            auto1.WyswietlInformacje(); // Zauważ, że auto1 również się zmieniło!

            // Garbage Collector (GC): 
            // Kiedy ustawimy referencję na null (np. auto2 = null), 
            // a nie będzie innych odwołań do tego obiektu, GC automatycznie zwolni pamięć.
            
            Console.WriteLine("\nWnioski: Pola publiczne nie chronią integralności danych. ");
            Console.WriteLine("Typy referencyjne przekazują adres, co wymaga ostrożności.");
            
            Console.WriteLine("\nNaciśnij dowolny klawisz, aby zakończyć...");
            Console.ReadKey();
        }
    }
}
                    
Wynik w konsoli
--- ZADANIE 01: Klasy, obiekty i referencje --- 1. Informacje o prawidłowym obiekcie: Pojazd: Toyota Corolla, Rok produkcji: 2022 2. Demonstracja błędnych danych (brak walidacji w polach publicznych): Pojazd: , Rok produkcji: -500 3. Demonstracja współdzielenia referencji: Po zmianie marki w auto3: Pojazd: Lexus Corolla, Rok produkcji: 2022 Wnioski: Pola publiczne nie chronią integralności danych. Typy referencyjne przekazują adres, co wymaga ostrożności. Naciśnij dowolny klawisz, aby zakończyć...