03
Cykl życia obiektu: konstruktory i przeciążanie
Cel zadania

Zrozumienie mechanizmu inicjalizacji obiektów za pomocą różnych typów konstruktorów oraz nauka przeciążania metod i konstruktorów. Student pozna sposoby łańcuchowania wywołań konstruktorów przy użyciu słowa kluczowego this oraz dowie się, jak działa destruktor klasy.

Scenariusz problemowy

W komisie "Auto-Premium" proces wprowadzania danych staje się uciążliwy. Pracownicy narzekają, że za każdym razem po utworzeniu obiektu muszą ręcznie wpisywać każde pole z osobna. Chciałbyś, aby system pozwalał na tworzenie pojazdu od razu z podstawowymi danymi (np. tylko marką i modelem), zachowując jednocześnie możliwość utworzenia zupełnie pustego obiektu lub pełnego opisu.

Postanawiasz wyposażyć klasę "Samochod" w zestaw specjalnych metod – konstruktorów. Dzięki ich przeciążeniu, system zyska na elastyczności. Dodatkowo, wprowadzasz funkcję obniżania ceny pojazdu, która może działać na dwa sposoby: poprzez odjęcie konkretnej kwoty lub procentowe obniżenie wartości. Aby zachować przejrzystość kodu, wykorzystujesz łańcuchowanie konstruktorów, co pozwala uniknąć powielania logiki inicjalizacji. Na koniec dodajesz destruktor, który będzie informował system o tym, że dany obiekt kończy swoją drogę w pamięci operacyjnej i jest gotowy do usunięcia przez mechanizm sprzątający środowiska .NET.

Opis wykonania
  • Zdefiniuj konstruktor bezargumentowy, który ustawia domyślne wartości pól.
  • Dodaj sparametryzowany konstruktor przyjmujący markę i model.
  • Stwórz trzeci konstruktor przyjmujący wszystkie parametry (marka, model, rok, cena).
  • Zastosuj łańcuchowanie konstruktorów: niech krótsze konstruktory wywołują ten najdłuższy przy użyciu : this(...).
  • Wykorzystaj słowo kluczowe this do rozróżnienia parametrów konstruktora od pól klasy.
  • Dodaj pole Cena typu double z podstawową walidacją.
  • Zaimplementuj dwie wersje metody ObnizCene() – jedną przyjmującą kwotę (double), drugą przyjmującą procent (int).
  • Dodaj destruktor klasy (~Samochod), który wypisze w konsoli komunikat o usunięciu obiektu.
  • W metodzie Main utwórz 3 różne obiekty, wykorzystując każdy z dostępnych konstruktorów.
  • Zademonstruj wywołanie obu wersji metody ObnizCene i wypisz wyniki.
  • Wyjaśnij w komentarzach, że destruktor jest wywoływany przez Garbage Collector w nieokreślonym momencie (dlatego w teście użyjemy `GC.Collect()`).
Kod źródłowy
Program.cs
using System;

namespace LaboratoriumOOP
{
    public class Samochod
    {
        private string _marka;
        private string _model;
        private int _rokProdukcji;
        private double _cena;

        // 1. Konstruktor bezargumentowy (jawny)
        // Łańcuchowanie: wywołuje pełny konstruktor z domyślnymi wartościami
        public Samochod() : this("Nieznana", "Nieznany", 2000, 0.0)
        {
            Console.WriteLine("[LOG] Utworzono pusty obiekt (konstruktor bezargumentowy).");
        }

        // 2. Konstruktor z 2 parametrami
        public Samochod(string marka, string model) : this(marka, model, DateTime.Now.Year, 10000.0)
        {
            Console.WriteLine($"[LOG] Utworzono obiekt {marka} {model} (konstruktor 2-arg).");
        }

        // 3. Pełny konstruktor (główny)
        public Samochod(string marka, string model, int rokProdukcji, double cena)
        {
            // Słowo 'this' wskazuje na pole klasy, unikając konfliktu z parametrem
            this._marka = marka;
            this._model = model;
            this._rokProdukcji = rokProdukcji;
            this._cena = cena;
            Console.WriteLine($"[LOG] Pełna inicjalizacja: {marka} {model}.");
        }

        // DESTRUKTOR: Wywoływany przez Garbage Collector przed usunięciem z pamięci.
        ~Samochod()
        {
            // UWAGA: Destruktorów unika się, jeśli nie zwalniamy zasobów niezarządzanych.
            // Tutaj służy jedynie do celów edukacyjnych.
            Console.WriteLine($"[GC] Obiekt {_marka} {_model} został usunięty z pamięci.");
        }

        // PRZECIĄŻANIE METOD (Overloading)
        // Ta sama nazwa, ale inna lista parametrów.

        public void ObnizCene(double kwota)
        {
            _cena -= kwota;
            Console.WriteLine($"Cena obniżona o {kwota} PLN. Nowa cena: {_cena} PLN.");
        }

        public void ObnizCene(int procent)
        {
            double obnizka = _cena * (procent / 100.0);
            _cena -= obnizka;
            Console.WriteLine($"Cena obniżona o {procent}%. Nowa cena: {_cena} PLN.");
        }

        public void Wyswietl()
        {
            Console.WriteLine($"Pojazd: {_marka} {_model} ({_rokProdukcji}), Cena: {_cena} PLN");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("--- ZADANIE 03: Konstruktory i przeciążanie ---\n");

            // Tworzenie obiektów różnymi sposobami
            Samochod s1 = new Samochod();
            Samochod s2 = new Samochod("Ford", "Focus");
            Samochod s3 = new Samochod("BMW", "X5", 2021, 250000.0);

            Console.WriteLine("\nStan pojazdów:");
            s1.Wyswietl();
            s2.Wyswietl();
            s3.Wyswietl();

            Console.WriteLine("\nDemonstracja przeciążania metod:");
            s2.ObnizCene(1500.50); // Metoda z double
            s3.ObnizCene(10);      // Metoda z int (procenty)

            Console.WriteLine("\nKoniec programu. Obiekty zostaną usunięte...");
            
            // Sugestia dla Garbage Collectora, aby posprzątał (tylko do demonstracji destruktora)
            s1 = null; s2 = null; s3 = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine("\nNaciśnij klawisz...");
            Console.ReadKey();
        }
    }
}
                    
Wynik w konsoli
--- ZADANIE 03: Konstruktory i przeciążanie --- [LOG] Pełna inicjalizacja: Nieznana Nieznany. [LOG] Utworzono pusty obiekt (konstruktor bezargumentowy). [LOG] Pełna inicjalizacja: Ford Focus. [LOG] Utworzono obiekt Ford Focus (konstruktor 2-arg). [LOG] Pełna inicjalizacja: BMW X5. Stan pojazdów: Pojazd: Nieznana Nieznany (2000), Cena: 0 PLN Pojazd: Ford Focus (2026), Cena: 10000 PLN Pojazd: BMW X5 (2021), Cena: 250000 PLN Demonstracja przeciążania metod: Cena obniżona o 1500,5 PLN. Nowa cena: 8499,5 PLN. Cena obniżona o 10%. Nowa cena: 225000 PLN. Koniec programu. Obiekty zostaną usunięte... [GC] Obiekt BMW X5 został usunięty z pamięci. [GC] Obiekt Ford Focus został usunięty z pamięci. [GC] Obiekt Nieznana Nieznany został usunięty z pamięci. Naciśnij klawisz...