Megosztás a következőn keresztül:


Objektumorientált programozás felfedezése osztályokkal és objektumokkal

Ebben az oktatóanyagban egy konzolalkalmazást fog létrehozni, és megismerheti a C# nyelv részét képező alapvető objektumorientált funkciókat.

Előfeltételek

Az alkalmazás létrehozása

Terminálablak használatával hozzon létre egy Osztályok nevű könyvtárat. Ott fogja létrehozni az alkalmazást. Váltson erre a könyvtárra, és írja be dotnet new console a konzolablakba. Ez a parancs létrehozza az alkalmazást. Nyissa meg a Program.cs fájlt. Ennek így kell kinéznie:

// See https://aka.ms/new-console-template for more information
Console.WriteLine("Hello, World!");

Ebben az oktatóanyagban olyan új típusokat fog létrehozni, amelyek egy bankszámlát jelölnek. A fejlesztők általában egy másik szövegfájlban definiálják az egyes osztályokat. Ez megkönnyíti a program méretének növekedésével való kezelését. Hozzon létre egy BankAccount.cs nevű új fájlt az Osztályok könyvtárban.

Ez a fájl tartalmazza a bankszámla definícióját. Az Objektumorientált programozás úgy rendszerezi a kódot, hogy osztályok formájában hoz létre típusokat. Ezek az osztályok egy adott entitást képviselő kódot tartalmaznak. Az BankAccount osztály egy bankszámlát jelöl. A kód metódusokon és tulajdonságokon keresztül implementál bizonyos műveleteket. Ebben az oktatóanyagban a bankszámla támogatja ezt a viselkedést:

  1. 10 jegyű számmal rendelkezik, amely egyedileg azonosítja a bankszámlát.
  2. Van egy sztringje, amely a tulajdonosok nevét vagy nevét tárolja.
  3. Az egyenleg lekérhető.
  4. Elfogadja a betéteket.
  5. Elfogadja a visszavonásokat.
  6. A kezdeti egyenlegnek pozitívnak kell lennie.
  7. A kivonások nem eredményezhetnek negatív egyenleget.

A bankszámla típusának meghatározása

Először is létrehozhatja az adott viselkedést meghatározó osztály alapjait. Hozzon létre egy új fájlt a File:New paranccsal. Nevezze el BankAccount.cs. Adja hozzá a következő kódot a BankAccount.cs fájlhoz:

namespace Classes;

public class BankAccount
{
    public string Number { get; }
    public string Owner { get; set; }
    public decimal Balance { get; }

    public void MakeDeposit(decimal amount, DateTime date, string note)
    {
    }

    public void MakeWithdrawal(decimal amount, DateTime date, string note)
    {
    }
}

Mielőtt továbblépnénk, tekintsük át, mit épített. A namespace deklaráció lehetővé teszi a kód logikai rendszerezését. Ez az oktatóanyag viszonylag kicsi, ezért az összes kódot egy névtérbe helyezi.

public class BankAccount A létrehozott osztályt vagy típust határozza meg. Az osztály deklarációját { követő és } azt követő összes elem meghatározza az osztály állapotát és viselkedését. Az osztálynak öt tagja BankAccount van. Az első három tulajdonság. A tulajdonságok adatelemek, és olyan kódokkal rendelkezhetnek, amelyek érvényesítik az ellenőrzést vagy más szabályokat. Az utolsó kettő metódus. A metódusok olyan kódblokkok, amelyek egyetlen függvényt hajtanak végre. Az egyes tagok nevének olvasása elegendő információt nyújt Önnek vagy egy másik fejlesztőnek ahhoz, hogy megértse az osztályt.

Új fiók megnyitása

Az első implementálási funkció a bankszámla megnyitása. Amikor egy ügyfél megnyit egy fiókot, meg kell adnia egy kezdeti egyenleget, és információkat kell megadnia a fiók tulajdonosáról vagy tulajdonosairól.

A típus új objektumának BankAccount létrehozása egy olyan konstruktor definiálását jelenti, amely hozzárendeli ezeket az értékeket. A konstruktor olyan tag, amelynek neve megegyezik az osztály nevével. Ez az osztálytípus objektumainak inicializálására szolgál. Adja hozzá a következő konstruktort a BankAccount típushoz. Helyezze a következő kódot a következő deklaráció MakeDepositfölé:

public BankAccount(string name, decimal initialBalance)
{
    this.Owner = name;
    this.Balance = initialBalance;
}

Az előző kód a minősítővel this azonosítja a létrehozandó objektum tulajdonságait. Ez a minősítő általában nem kötelező, és nincs megadva. A következőt is írhatta volna:

public BankAccount(string name, decimal initialBalance)
{
    Owner = name;
    Balance = initialBalance;
}

A this minősítő csak akkor szükséges, ha egy helyi változó vagy paraméter neve megegyezik az adott mező vagy tulajdonság nevével. A this minősítőt a cikk hátralévő részében kihagyjuk, hacsak nincs rá szükség.

A konstruktorok akkor lesznek meghívva, ha objektumot hoz létre a használatával new. Cserélje le a Program.cs sorát Console.WriteLine("Hello World!"); a következő kódra (cserélje le <name> a nevét):

using Classes;

var account = new BankAccount("<name>", 1000);
Console.WriteLine($"Account {account.Number} was created for {account.Owner} with {account.Balance} initial balance.");

Futtassuk le, amit eddig készített. Ha Visual Studiót használ, a Hibakeresés menüben hibakeresés nélkül válassza a Start lehetőséget. Ha parancssort használ, írja be dotnet run azt a könyvtárat, amelyben létrehozta a projektet.

Észrevette, hogy a fiók száma üres? Itt az ideje, hogy ezt kijavítsuk. A fiókszámot az objektum létrehozásakor kell hozzárendelni. De nem a hívó feladata létrehozni. Az BankAccount osztálykódnak tudnia kell, hogyan rendelhet hozzá új fiókszámokat. Egy egyszerű módszer egy 10 jegyű számmal kezdeni. Növekmény minden új fiók létrehozásakor. Végül tárolja az aktuális fiók számát egy objektum létrehozásakor.

Tagdeklaráció hozzáadása az BankAccount osztályhoz. Helyezze a következő kódsort a nyitó zárójel { után az BankAccount osztály elejére:

private static int s_accountNumberSeed = 1234567890;

Ez accountNumberSeed egy adattag. Ez privateazt jelenti, hogy csak az osztályon belüli BankAccount kóddal érhető el. Ez a módszer elkülöníti a nyilvános felelősségeket (például egy fiókszámot) a magánvégrehajtástól (a fiókszámok létrehozásának módjától). Ez azt is staticjelenti, hogy az összes BankAccount objektum megosztja. A nem statikus változók értéke egyedi az BankAccount objektum minden példányára vonatkozóan. Ez accountNumberSeed egy private static mező, és így a C# elnevezési konvenciók szerint rendelkezik az s_ előtaggal. A s denoting static és _ denoting private mező. Adja hozzá a következő két sort a konstruktorhoz a fiókszám hozzárendeléséhez. Helyezze őket a következő sor this.Balance = initialBalanceután:

Number = s_accountNumberSeed.ToString();
s_accountNumberSeed++;

Írja be dotnet run az eredményeket.

Betétek és kivonások létrehozása

A megfelelő működéshez a bankszámlaosztálynak el kell fogadnia a befizetéseket és a kifizetéseket. Alkalmazzuk a betéteket és a kifizetéseket úgy, hogy létrehozunk egy naplót a fiók minden tranzakciójának. Az egyes tranzakciók nyomon követése számos előnnyel jár az egyes tranzakciók egyenlegének egyszerű frissítésével szemben. Az előzmények az összes tranzakció naplózására és a napi egyenlegek kezelésére használhatók. Ha szükség van rá, az összes tranzakció előzményeiből származó egyenleg kiszámítása biztosítja, hogy egy rögzített tranzakció hibái megfelelően tükröződnek a következő számítás egyenlegében.

Először hozzunk létre egy új típust, amely egy tranzakciót jelöl. A tranzakció egy egyszerű típus, amely nem rendelkezik felelősségekkel. Szüksége van néhány tulajdonságra. Hozzon létre egy Transaction.cs nevű új fájlt. Adja hozzá a következő kódot:

namespace Classes;

public class Transaction
{
    public decimal Amount { get; }
    public DateTime Date { get; }
    public string Notes { get; }

    public Transaction(decimal amount, DateTime date, string note)
    {
        Amount = amount;
        Date = date;
        Notes = note;
    }
}

Most adjunk hozzá egy List<T> Transaction objektumot az BankAccount osztályhoz. Adja hozzá a következő deklarációt a konstruktor után a BankAccount.cs fájlban:

private List<Transaction> _allTransactions = new List<Transaction>();

Most számítsuk ki helyesen a Balance. Az aktuális egyenleg az összes tranzakció értékeinek összegzésével érhető el. A kód jelenleg csak a fiók kezdeti egyenlegét tudja lekérni, ezért frissítenie kell a tulajdonságot Balance . Cserélje le a BankAccount.cs sorát public decimal Balance { get; } a következő kódra:

public decimal Balance
{
    get
    {
        decimal balance = 0;
        foreach (var item in _allTransactions)
        {
            balance += item.Amount;
        }

        return balance;
    }
}

Ez a példa a tulajdonságok egy fontos aspektusát mutatja be. Most már kiszámítja az egyenleget, amikor egy másik programozó kéri az értéket. A számítás az összes tranzakciót számba adja, és az aktuális egyenlegként adja meg az összeget.

Ezután implementálja a módszereket és MakeWithdrawal a MakeDeposit módszereket. Ezek a módszerek kényszerítik az utolsó két szabályt: a kezdeti egyenlegnek pozitívnak kell lennie, és a visszavonás nem hozhat létre negatív egyenleget.

Ezek a szabályok a kivételek fogalmát vezetik be. Egy metódus nem tudja sikeresen befejezni a munkáját, ha kivételt küld. A kivétel típusa és a hozzá társított üzenet írja le a hibát. Ebben az esetben a MakeDeposit metódus kivételt jelez, ha a betét összege nem nagyobb 0-nál. A MakeWithdrawal módszer kivételt eredményez, ha a visszavonási összeg nem nagyobb 0-nál, vagy ha a visszavonás alkalmazása negatív egyenleget eredményez. Adja hozzá a következő kódot a _allTransactions lista deklarációja után:

public void MakeDeposit(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive");
    }
    var deposit = new Transaction(amount, date, note);
    _allTransactions.Add(deposit);
}

public void MakeWithdrawal(decimal amount, DateTime date, string note)
{
    if (amount <= 0)
    {
        throw new ArgumentOutOfRangeException(nameof(amount), "Amount of withdrawal must be positive");
    }
    if (Balance - amount < 0)
    {
        throw new InvalidOperationException("Not sufficient funds for this withdrawal");
    }
    var withdrawal = new Transaction(-amount, date, note);
    _allTransactions.Add(withdrawal);
}

Az throw utasítás kivételt jelez . Az aktuális blokk végrehajtása véget ér, és a hívásverem első egyező catch blokkjára irányuló átvitel vezérlése. Egy blokkot catch fog hozzáadni a kód teszteléséhez egy kicsit később.

A konstruktornak egyetlen módosítást kell kapnia, hogy egy kezdeti tranzakciót adjon hozzá ahelyett, hogy közvetlenül frissítenék az egyenleget. Mivel már megírta a metódust MakeDeposit , hívja a konstruktortól. A kész konstruktornak így kell kinéznie:

public BankAccount(string name, decimal initialBalance)
{
    Number = s_accountNumberSeed.ToString();
    s_accountNumberSeed++;

    Owner = name;
    MakeDeposit(initialBalance, DateTime.Now, "Initial balance");
}

DateTime.Now egy tulajdonság, amely az aktuális dátumot és időpontot adja vissza. Tesztelje ezt a kódot úgy, hogy hozzáad néhány befizetést és kifizetést a Main metódushoz, az új BankAccountkódot létrehozó kódot követve:

account.MakeWithdrawal(500, DateTime.Now, "Rent payment");
Console.WriteLine(account.Balance);
account.MakeDeposit(100, DateTime.Now, "Friend paid me back");
Console.WriteLine(account.Balance);

Következő lépésként tesztelje, hogy hibafeltételeket fog-e észlelni, ha negatív egyenlegű fiókot próbál létrehozni. Adja hozzá a következő kódot az imént hozzáadott kód után:

// Test that the initial balances must be positive.
BankAccount invalidAccount;
try
{
    invalidAccount = new BankAccount("invalid", -55);
}
catch (ArgumentOutOfRangeException e)
{
    Console.WriteLine("Exception caught creating account with negative balance");
    Console.WriteLine(e.ToString());
    return;
}

Az utasítással try-catch megjelölhet egy kódblokkot, amely kivételeket okozhat, és észlelheti a várt hibákat. Ugyanezzel a technikával tesztelheti azt a kódot, amely kivételt eredményez egy negatív egyenleg esetében. Adja hozzá a következő kódot a metódus deklarációja invalidAccount Main előtt:

// Test for a negative balance.
try
{
    account.MakeWithdrawal(750, DateTime.Now, "Attempt to overdraw");
}
catch (InvalidOperationException e)
{
    Console.WriteLine("Exception caught trying to overdraw");
    Console.WriteLine(e.ToString());
}

Mentse a fájlt, és írja be dotnet run a kipróbálásához.

Kihívás – az összes tranzakció naplózása

Az oktatóanyag befejezéséhez megírhatja azt a GetAccountHistory metódust, amely létrehoz egy string tranzakciós előzményeket. Adja hozzá ezt a metódust a BankAccount következő típushoz:

public string GetAccountHistory()
{
    var report = new System.Text.StringBuilder();

    decimal balance = 0;
    report.AppendLine("Date\t\tAmount\tBalance\tNote");
    foreach (var item in _allTransactions)
    {
        balance += item.Amount;
        report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}");
    }

    return report.ToString();
}

Az előzmények az StringBuilder osztály használatával formáznak egy sztringet, amely minden tranzakcióhoz egy sort tartalmaz. Az oktatóanyagokban korábban már láthatta a sztringformázási kódot. Az egyik új karakter a .\t Ez beszúr egy lapot a kimenet formázásához.

Adja hozzá ezt a sort a Program.cs teszteléséhez:

Console.WriteLine(account.GetAccountHistory());

Futtassa a programot az eredmények megtekintéséhez.

Következő lépések

Ha elakadt, az oktatóanyag forrását a GitHub-adattárban tekintheti meg.

Folytathatja az objektumorientált programozási oktatóanyagot.

Ezekről a fogalmakról az alábbi cikkekben tudhat meg többet: