🔥 Zapisy zamknięte, ale możesz pobrać Roadmapę .NET i dołączyć do listy oczekujących — Pobierz i dołącz do Listy VIP →

Klasy i obiekty w C# — podstawy OOP

Klasy i obiekty

1 Klasy

Definicja Klasy:

  • Klasa w języku C# to szablon lub plan, na podstawie którego tworzone są obiekty. Reprezentuje abstrakcję pewnego rodzaju jednostki w systemie.
  • Klasy są fundamentem programowania obiektowego, pozwalają na strukturyzację i organizację kodu.
  • Klasa definiuje cechy (pola), zachowanie (metody) oraz funkcjonalności obiektu.

Struktura Klasy:

  • Pola (Prywatne Dane): Pola przechowują dane charakteryzujące obiekt klasy. Są to zmienne, które należą do konkretnej instancji klasy.
  • Właściwości: Właściwości pozwalają na kontrolowany dostęp do pól klasy i umożliwiają walidację danych przed zapisem lub odczytem.
  • Metody (Funkcje): Metody to funkcje, które mogą operować na polach klasy i wykonywać różne operacje. Metody definiują zachowania obiektu.
  • Konstruktory: Konstruktor to specjalna metoda wywoływana podczas tworzenia nowej instancji klasy. Służy do inicjalizacji obiektu.
  • Indeksery: Indeksery pozwalają na dostęp do elementów obiektu za pomocą indeksu, podobnie jak w przypadku tablic. Wartość indeksu może być dowolnym typem, a nie tylko typem liczbowym.
  • Zdarzenia: Zdarzenia umożliwiają subskrypcję i obsługę zdarzeń wywoływanych w klasie.
  • Statyczność: Członkowie statyczni (metody, pola) należą do klasy, a nie do konkretnej instancji. Są dostępne bez konieczności tworzenia obiektu danej klasy.

przykład

public class Narzedzie
{
    public static int LiczbaNarzedzi;
}

Definicja Klasy przykład

public class Samochod
{
    // Członkowie klasy (pola, właściwości, metody)
}

Pola (Fields) i Właściwości (Properties)

public class Samochod
{
    public string Marka;        // Pole
    
    private int _rokProdukcji;  // Pole prywatne

    public int RokProdukcji     // Właściwość
    {
        get { return _rokProdukcji; }
        set { _rokProdukcji = value > 1900 ? value : 1900; }
    }
}

Metody

public class Samochod
{
    public void UruchomSilnik()
    {
        // Logika uruchamiania silnika
    }

    public int ObliczWiekSamochodu()
    {
        return DateTime.Now.Year - RokProdukcji;
    }
}

Konstruktory

public class Samochod
{
    public Samochod(string marka, int rokProdukcji)
    {
        Marka = marka;
        RokProdukcji = rokProdukcji;
    }
}

Indeksery

using System;

public class Biblioteka
{
    private string[] ksiazki = new string[10];

    // Indekser
    public string this[int indeks]
    {
        get
        {
            if (indeks >= 0 && indeks < ksiazki.Length)
            {
                return ksiazki[indeks];
            }
            else
            {
                return "Indeks poza zakresem";
            }
        }
        set
        {
            if (indeks >= 0 && indeks < ksiazki.Length)
            {
                ksiazki[indeks] = value;
            }
            else
            {
                Console.WriteLine("Indeks poza zakresem");
            }
        }
    }
}

class Program
{
    static void Main()
    {
        Biblioteka mojaBiblioteka = new Biblioteka();

        // Ustawienie wartości za pomocą indeksera
        mojaBiblioteka[0] = "Asp.Net Core";
        mojaBiblioteka[1] = "Csharp";
        mojaBiblioteka[2] = "Xml";

        // Pobranie wartości za pomocą indeksera
        Console.WriteLine(mojaBiblioteka[1]); // Wyświetli: Asp.Net Core
        Console.WriteLine(mojaBiblioteka[5]); // Wyświetli: Indeks poza zakresem
    }
}

Zdarzenia

using System;

// Klasa reprezentująca nadawcę zdarzenia
public class Nadawca
{
    // Definicja delegata zdarzenia
    public delegate void MojDelegat(string wiadomosc);

    // Zdarzenie oparte na delegacie
    public event MojDelegat MojEvent;

    // Metoda, która wywołuje zdarzenie
    public void WywolajZdarzenie(string wiadomosc)
    {
        Console.WriteLine("Nadawca: Wysyłam wiadomość - " + wiadomosc);

        // Sprawdzamy, czy zdarzenie ma zarejestrowane jakieś obszary nasłuchujące
        if (MojEvent != null)
        {
            // Wywołujemy zdarzenie, przekazując wiadomość
            MojEvent(wiadomosc);
        }
    }
}

// Klasa reprezentująca odbiorcę zdarzenia
public class Odbiorca
{
    // Metoda obsługująca zdarzenie
    public void ObslugaZdarzenia(string wiadomosc)
    {
        Console.WriteLine("Odbiorca: Otrzymałem wiadomość - " + wiadomosc);
    }
}

class Program
{
    static void Main()
    {
        // Tworzymy obiekty nadawcy i odbiorcy
        Nadawca mojNadawca = new Nadawca();
        Odbiorca mojOdbiorca = new Odbiorca();

        // Rejestrujemy metodę ObslugaZdarzenia jako obszar nasłuchujący zdarzenia w nadawcy
        mojNadawca.MojEvent += mojOdbiorca.ObslugaZdarzenia;

        // Wywołujemy zdarzenie
        mojNadawca.WywolajZdarzenie("Nowa wiadomość!");
 
    }
}

Oczekiwany wynik:

Nadawca: Wysyłam wiadomość - Nowa wiadomość!
Odbiorca: Otrzymałem wiadomość - Nowa wiadomość!

2 Obiekty

Definicja

  • Obiekt to konkretna instancja klasy.
  • Możemy utworzyć wiele obiektów na podstawie jednej klasy.
  • Każdy obiekt ma swoje unikalne atrybuty (wartości pól) i może wywoływać metody klasy.
  • Tworzenie obiektu polega na alokowaniu pamięci i inicjalizowaniu jego pól i właściwości zgodnie z definicją klasy.
  • Obiekty są niezależne i mogą mieć różne stany.

Tworzenie Obiektu:

  • new – obiekt jest tworzony za pomocą operatora new wraz z wywołaniem konstruktora klasy.
    Przykład: Samochod mojSamochod = new Samochod("Toyota", "Camry", 2022);
  • Referencje: Obiekty są przekazywane przez referencje. Oznacza to, że przypisanie jednego obiektu do innego nie tworzy nowego obiektu, ale kopiuje referencję do tego samego obiektu w pamięci.

Dostęp do Członków Klasy:

  • Pola i metody klasy mogą być dostępne z poziomu obiektu, a dostęp do nich odbywa się za pomocą operatora ..
  • Przykład: mojSamochod.PokazInformacje();
Osoba osoba1 = new Osoba("Jan", "Kowalski");
Osoba osoba2 = new Osoba("Anna", "Nowak");

osoba1.PrzedstawSie(); // "Jestem Jan Kowalski."
osoba2.PrzedstawSie(); // "Jestem Anna Nowak."

3 Filary Programowania obiektowego

Encapsulation (Enkapsulacja):

Enkapsulacja to zasada programowania obiektowego, która polega na ukrywaniu wewnętrznych detali implementacyjnych klasy i ujawnianiu tylko potrzebnych interfejsów.

Dostęp do pól i metod jest kontrolowany przez mechanizmy takie jak modyfikatory dostępu ( public, private, protected, internal, protected internal) które określają, które elementy klasy są widoczne dla innych części kodu. Co pomaga w zabezpieczaniu i izolowaniu wewnętrznych szczegółów implementacji.

Enkapsulacja pomaga w utrzymaniu spójności danych i umożliwia łatwiejsze utrzymanie kodu, ponieważ zmiany w implementacji mogą być ukrywane przed innymi częściami programu.

public class Samochod
{
    // private - dostęp tylko w obrębie klasy
    private int _rokProdukcji;

    // public - dostęp z dowolnego miejsca
    public int RokProdukcji
    {
        get { return _rokProdukcji; }
        set { _rokProdukcji = value > 1900 ? value : 1900; }
    }
}

Dziedziczenie

Dziedziczenie to mechanizm, który pozwala na tworzenie nowych klas na podstawie istniejących klas. Dziedziczenie umożliwia jednej klasie (klasie pochodnej) korzystanie z cech i zachowań innej klasy (klasy bazowej). Dziedziczenie pozwala na ponowne wykorzystanie kodu i tworzenie hierarchii klas, co ułatwia organizację kodu i wprowadzanie zmian w jednym miejscu.

public class Zwierze
{
    public void Oddychaj()
    {
        Console.WriteLine("Zwierze oddycha.");
    }
}

public class Ptak : Zwierze
{
    public void Lataj()
    {
        Console.WriteLine("Ptak lata.");
    }
}

Ptak dziedziczy metodę Oddychaj od klasy Zwierze.

Polimorfizm

Polimorfizm to koncepcja, która pozwala na traktowanie różnych obiektów w jednolity sposób. Możesz używać obiektów klas pochodnych jako obiektów klas bazowych.
Polimorfizm umożliwia jednemu interfejsowi obsługiwać różne typy obiektów lub jednej metodzie obsługiwać różne formy danych. W C#, polimorfizm może być osiągnięty poprzez przeciążanie metod, przesłanianie metod, interfejsy i klasy abstrakcyjne.

Metody wirtualne i abstrakcyjne umożliwiają nadpisywanie funkcji w klasach pochodnych.

public class Kształt
{
    public virtual void Narysuj()
    {
        Console.WriteLine("Rysuję kształt.");
    }
}

public class Kwadrat : Kształt
{
    public override void Narysuj()
    {
        Console.WriteLine("Rysuję kwadrat.");
    }
}

public class Kolo : Kształt
{
    public override void Narysuj()
    {
        Console.WriteLine("Rysuję koło.");
    }
}

Korzystając z polimorfizmu, możemy używać wspólnego interfejsu (Kształt) do obsługi różnych konkretnych implementacji (Kwadrat, Kolo).

Abstrakcja

Abstrakcja polega na ukrywaniu zbędnych detali implementacyjnych i skupianiu się na istotnych aspektach danego obiektu. Jest to proces tworzenia modelu, który koncentruje się na najważniejszych cechach i zachowaniach, ignorując mniej istotne szczegóły.

Klasy Abstrakcyjne:

Klasy abstrakcyjne są klasami, które nie mogą być instancjonowane bezpośrednio, ale mogą zawierać metody abstrakcyjne, czyli metody, które nie posiadają implementacji w klasie abstrakcyjnej. Klasy te służą jako szablony do dziedziczenia.

public abstract class Figura
{
    public abstract double PolePowierzchni(); // Metoda abstrakcyjna
}

Interfejsy:

Interfejsy to zbiorcze zestawy metod, które są implementowane przez różne klasy. W odróżnieniu od klas abstrakcyjnych, interfejsy nie zawierają żadnej implementacji i umożliwiają implementację wielu interfejsów w jednej klasie.

public interface IDzwieki
{
    void WydajDzwiek();
}

Właściwości Abstrakcyjne:

Właściwości abstrakcyjne pozwalają na definiowanie abstrakcyjnych pól w klasach abstrakcyjnych. Implementacja tych pól zostanie dostarczona przez klasę dziedziczącą.

public abstract class Pojazd
{
    public abstract string Marka { get; set; }
}

Abstrakcja pozwala na tworzenie bardziej ogólnych i elastycznych struktur w kodzie, co z kolei ułatwia rozbudowę i modyfikację systemu. Jest to kluczowa koncepcja w programowaniu obiektowym, która pomaga w modelowaniu rzeczywistych problemów i skupianiu się na istotnych aspektach systemu.

Filary programowania obiektowego stanowią podstawę dla wielu zaawansowanych koncepcji i technik w programowaniu. Wspierają one tworzenie kodu, który jest bardziej elastyczny, łatwiejszy do zrozumienia, utrzymania i rozbudowy. Programowanie obiektowe jest kluczowym paradygmatem programowania, który jest szeroko stosowany we współczesnym oprogramowaniu.

Chcesz zobaczyć te same idee w praktyce? Zobacz 4 filary programowania obiektowego w C# i Interfejsy w C# — czysty kod bez powtórzeń.

Jeśli wolisz zacząć od prostszego, bardziej przystępnego wprowadzenia z analogią do klocków LEGO zamiast suchej teorii, sprawdź Obiekty w C# to jak Klocki LEGO — dobry punkt startowy przed tym artykułem.

👨‍💻
Mariusz Jurczenko
Senior .NET Developer · 10+ lat doświadczenia komercyjnego

Programista .NET z doświadczeniem komercyjnym w firmach takich jak NFZ, Kamsoft, Diagnostyka, Hermes Reply Polska czy Etisoft Smart Solutions. Twórca kursów, z których skorzystało już ponad 11 000 osób w Strefie Kursów i ponad 1 000 kursantów na dev-hobby.pl.

Specjalizacja: Clean Code, Clean Architecture i uczenie programowania tak, żeby dało się je naprawdę zrozumieć — nie wykuć.

🚀 Co dalej?

Zobacz to w praktyce na wideo i pobierz darmową roadmapę, żeby ułożyć naukę w spójną ścieżkę do pierwszej pracy.

9 comments

  1. Klarowne przedstawienie filarów programowania obiektowego, a także wartościowa lista dodatkowych tematów do zrozumienia.
    Dodatkowe tematy, takie jak Klasy i Metody Statyczne, Metody Generyczne, czy Metody Rozszerzeń, są dobrze ujęte.

  2. Wyjaśnienie pól i właściwości jest zrozumiałe. Dobrze pokazane różnice między publicznymi polami a prywatnymi polami z właściwościami.
    Właściwość RokProdukcji zastosowująca walidację to dobry sposób na kontrolę danych.

Dodaj komentarz

czytanie to początek

Zamień wiedzę w umiejętności

Pobierz darmową Roadmapę .NET i ułóż takie tematy jak ten w spójną ścieżkę do pierwszej pracy.

Pobieram roadmapę →