C# Academy · Oppitunti

Staattinen ja ilmentymäkohtainen suunnittelu

Päättäkää, milloin staattinen tila on tarkoituksenmukainen.

Oppitunti 4/413 vaihetta

Staattinen ja ilmentymäkohtainen suunnittelu on ilmainen C# Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu C# Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. C# Academy-kurssilla on yhteensä 4 oppituntia.

Suunnittelupäätös

static- ja instance-jäsenten valinta on suunnittelupäätös. Keskeinen kysymys on, riippuuko toiminta oliokohtaisesta tilasta vai ainoastaan syötteistä.

using System;

class Program
{
    // Depends only on inputs -> good static method
    static int Max(int a, int b) => a > b ? a : b;

    static void Main()
    {
        Console.WriteLine(Max(3, 8));
    }
}

Käyttäkää static-jäsentä tilattomaan logiikkaan

Jos metodi ei tarvitse instanssikenttiä vaan ainoastaan muuntaa syötteitä, määrittäkää se static-metodiksi. Matematiikka-apurit ja muotoilijat ovat hyviä esimerkkejä.

using System;

static class Convert2
{
    public static double MilesToKm(double miles) => miles * 1.60934;
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Convert2.MilesToKm(10).ToString("0.0") + " km");
    }
}

Käyttäkää instanssia tilan käsittelyyn

Jos toiminta riippuu oliokohtaisesti vaihtelevista tiedoista, käyttäkää instance-jäsentä. Jokainen olio säilyttää oman tilansa.

using System;

class Counter
{
    private int _count;
    public void Increment() => _count++;
    public int Value => _count;
}

class Program
{
    static void Main()
    {
        var a = new Counter();
        var b = new Counter();
        a.Increment();
        a.Increment();
        b.Increment();
        Console.WriteLine("a=" + a.Value + ", b=" + b.Value);
    }
}

Jaettu tila on globaalia tilaa

Staattinen kenttä on käytännössä globaali. Se voi aiheuttaa vaikeasti havaittavia virheitä, kun ohjelman monet osat lukevat kenttää ja kirjoittavat siihen. Suosikaa instanssitilaa, kun jokainen käyttäjä tarvitsee oman kopionsa.

using System;

class BadCart
{
    public static int Items;   // shared by EVERYONE -> usually wrong for a cart
}

class Program
{
    static void Main()
    {
        BadCart.Items++;
        BadCart.Items++;
        Console.WriteLine("All carts share: " + BadCart.Items);
    }
}

Testattavuus

Puhdasta staattista metodia on helppo testata: sama syöte tuottaa saman tuloksen. Muuttuva staattinen tila puolestaan vuotaa testien välillä ja tekee testeistä hauraita.

using System;

static class Calc
{
    public static int Add(int a, int b) => a + b;   // trivially testable
}

class Program
{
    static void Main()
    {
        Console.WriteLine(Calc.Add(2, 2) == 4 ? "pass" : "fail");
    }
}

Static tehdasapureina

Staattiset tehdasmetodit ovat selkeä tapa luoda määritettyjä instansseja kuvaavan nimen avulla.

using System;

class Color
{
    public int R, G, B;
    private Color(int r, int g, int b) { R = r; G = g; B = b; }

    public static Color Red() => new Color(255, 0, 0);
    public static Color White() => new Color(255, 255, 255);
}

class Program
{
    static void Main()
    {
        var c = Color.Red();
        Console.WriteLine(c.R + "," + c.G + "," + c.B);
    }
}

Älkää käyttäkö static-jäsentä vain new-sanan välttämiseksi

Älkää tehkö kaikesta staattista vain olioiden luomisen välttämiseksi. Jos tyyppi kuvaa tilallista asiaa, instanssit pitävät tilan erillään ja turvallisena.

using System;

class Player
{
    public string Name;
    public int Health = 100;
    public void TakeDamage(int d) => Health -= d;
}

class Program
{
    static void Main()
    {
        var p1 = new Player { Name = "A" };
        var p2 = new Player { Name = "B" };
        p1.TakeDamage(30);
        Console.WriteLine(p1.Name + ": " + p1.Health + ", " + p2.Name + ": " + p2.Health);
    }
}

Käyttäkää molempia tarkoituksenmukaisesti

Monissa luokissa käytetään staattisia jäseniä jaetuille vakioille tai laskureille sekä instanssijäseniä oliokohtaisille tiedoille. Tällainen yhdistelmä on täysin idiomattinen.

using System;

class Invoice
{
    private static int _seq = 1000;
    public readonly int Number;
    public decimal Amount;

    public Invoice(decimal amount)
    {
        Number = _seq++;
        Amount = amount;
    }
}

class Program
{
    static void Main()
    {
        var i1 = new Invoice(50m);
        var i2 = new Invoice(75m);
        Console.WriteLine(i1.Number + " / " + i2.Number);
    }
}

Samanaikaisuuden haaste

Useat säikeet voivat käyttää jaettua staattista tilaa samanaikaisesti, mikä voi aiheuttaa kilpailutilanteita. Yhteen säikeeseen rajattu instanssitila on oletusarvoisesti turvallisempaa.

using System;

class SafeCalc
{
    // No shared mutable state -> naturally thread-safe
    public static long Factorial(int n)
    {
        long result = 1;
        for (int i = 2; i <= n; i++) result *= i;
        return result;
    }
}

class Program
{
    static void Main()
    {
        Console.WriteLine(SafeCalc.Factorial(5));
    }
}

Yksinkertainen nyrkkisääntö

Static = tyyppiin kuuluvaa toimintaa, joka ei käytä oliokohtaista tilaa. Instance = toimintaa, joka lukee tietyn olion tietoja tai muuttaa niitä. Jos epäröitte, suosikaa instanssia kaikessa tilallisessa toiminnassa.

using System;

class Temperature
{
    public double Celsius;                                  // instance state
    public static double ToF(double c) => c * 9 / 5 + 32;   // stateless helper
}

class Program
{
    static void Main()
    {
        var t = new Temperature { Celsius = 30 };
        Console.WriteLine(Temperature.ToF(t.Celsius));
    }
}

Kokonaisuus

Hyvä suunnittelu erottaa tilattomat apurit (static) tilallisista malleista (instance) ja pitää jaetun muuttuvan tilan tarkoituksella mahdollisimman vähäisenä.

using System;

static class TaxRules
{
    public static decimal Apply(decimal amount, decimal rate) => amount + amount * rate;
}

class Sale
{
    public decimal Subtotal;
    public decimal Total(decimal rate) => TaxRules.Apply(Subtotal, rate);
}

class Program
{
    static void Main()
    {
        var s = new Sale { Subtotal = 100m };
        Console.WriteLine(s.Total(0.2m));
    }
}

Pikatesti

Testatkaa, miten hyvin ymmärrätte static- ja instance-suunnittelun erot.

Kertaus

Valitkaa static tilattomaan logiikkaan, joka riippuu vain syötteistä, kuten apureihin, tehtaisiin ja vakioihin. Valitkaa instance toimintaan, joka liittyy oliokohtaiseen tilaan. Staattinen muuttuva tila on käytännössä globaalia, sitä on vaikeampi testata ja se altistaa samanaikaisuusvirheille, joten pitäkää se vähäisenä ja harkittuna.

using System;

static class Util { public static int Sq(int n) => n * n; }

class Box { public int Size; public int Area() => Util.Sq(Size); }

class Program
{
    static void Main()
    {
        var box = new Box { Size = 4 };
        Console.WriteLine(box.Area());
    }
}
Aloita maksutta

Opi C# tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
93
Oppitunnit
346

Usein kysytyt kysymykset

Onko oppitunti ”Staattinen ja ilmentymäkohtainen suunnittelu” ilmainen?

Kyllä – oppitunnin ”Staattinen ja ilmentymäkohtainen suunnittelu” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko C# Academy-kurssin, päivitä CoddyKit PROhon. C# Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Staattinen ja ilmentymäkohtainen suunnittelu”?

Päättäkää, milloin staattinen tila on tarkoituksenmukainen. Harjoittelet C# Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni C# Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin C# Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Staattinen ja ilmentymäkohtainen suunnittelu”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä C# Academy-oppitunnilla?

Kyllä. Jokainen C# Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Staattiset metodit ja kentät
  2. Staattiset luokat apuohjelmille
  3. Vakiot ja readonly-kentät
  4. Staattinen ja ilmentymäkohtainen suunnittelu
← Takaisin: C# Academy