Metode - zgledi

Metode - zgledi

Avtor: Matija Lokar

Zgled – člani športnega kluba

Denimo, da bi radi napisali program, ki vodi evidenco o članih športnega kluba. Podatki o članu obsegajo ime, priimek, letnico vpisa v klub in vpisno številke (seveda je to poenostavljen primer). Torej objekt, ki predstavlja člana kluba, vsebuje štiri podatke:

public class Clan {
    public string ime;
    public string priimek;
    public int leto_vpisa;
    public string vpisna_st;
}

Klub - uporaba

public class TestKlub {
  public static void Main(string[] args) {

    Clan a = new Clan();
    a.ime = "Janez";
    a.priimek = "Starina";
    a.leto_vpisa = 2000;
    a.vpisna_st = "2304";

    Clan b = new Clan();
    b.ime = "Mojca";
    b.priimek = "Mavko";
    b.leto_vpisa = 2001;
    b.vpisna_st = "4377";

    Clan c = b;
    c.ime = "Andreja";
(2.png)
    Console.WriteLine("Clan a:\n" + a.ime + " " + a.priimek +
                      " " + a.leto_vpisa + " (" + a.vpisna_st + ")\n");

    Console.WriteLine("Clan b:\n" + b.ime + " " + b.priimek +
                      " " + b.leto_vpisa + " (" + b.vpisna_st + ")\n");

    Console.WriteLine("Clan c:\n" + c.ime + " " + c.priimek +
                      " " + c.leto_vpisa + " (" + c.vpisna_st + ")\n");
    Console.ReadLine();
  }
}

Zgled – športni klub, nadaljevanje

Spremenimo sedaj naš razred Clan tako, da bomo uporabili konstruktor

public class Clan {
    public string ime;
    public string priimek;
    public int leto_vpisa;
    public string vpisna_st;

    public Clan(string i, string p, int l, string v) {
        this.ime = i;
        this.priimek = p;
        this.leto_vpisa = l;
        this.vpisna_st = v;
    }
}

Šprtni klub - test

  • Bo naš testni program OK?
  • Poženimo
  • Napake!

    • Kako, rekli smo, da spreminjanje razreda ne vpliva na uporabniške programe
    • Spremenili smo način uporabe
    • V testnem programu: Clan()

      • Tega sedaj ni

        • C# ga naredi sam le, če nismo napisali nobenega konstruktorja

Popravljeni zgled

public class Clan {
    public string ime;
    public string priimek;
    public int leto_vpisa;
    public string vpisna_st;

    public Clan() {
    this.ime = "Ne vem";
    this.priimek = "Ne vem";
    this.leto_vpisa = 0;
    this.vpisna_st = "Ne vem";
    }

    public Clan(string i, string p, int l, string v) {
    this.ime = i;
    this.priimek = p;
    this.leto_vpisa = l;
    this.vpisna_st = v;
    }
}

Poskus testa

  • Ni težav!
  • Zakaj ves ta napor, če pa je na koncu le isto ...
  • Preglednost!

    • In priprava za naprej

Primerjava: brez / s konstruktiorjem

public class TestKlub {
  public static void Main(string[] args) {
     Clan a = new Clan();
    a.ime = "Janez";
    a.priimek = "Starina";
    a.leto_vpisa = 2000;
    a.vpisna_st = "2304";

    Clan b = new Clan();
    b.ime = "Mojca";
    b.priimek = "Mavko";
    b.leto_vpisa = 2001;
    b.vpisna_st = "4377";

    Clan c = b;
    c.ime = "Andreja";
...
public class TestClan{
    public static void Main(string[] args) {
        Clan a = new Clan("Janez",
                "Starina", 2000, "2304");
    Clan b = new Clan("Mojca",
                "Mavko", 2001, "4377");
            Clan c = b;
    c.ime = "Andreja";
...

Objektne metode

  • V definicijo razreda običajno spadajo tudi metode
  • Klic objektnih metod:

    • imeObjekta.imeMetode(parametri)
    • System.Console.WriteLine("To naj se izpiše");
    • besedilo.Equals(primerjava)
  • Metoda v razredu Clan public string Inicialke() {
        return this.ime[0] + "." + this.priimek[0] + ".";
     }

Uporaba metode

using MojiRazredi; // knjižnica z razredom Clan
public class TestClan{
    public static void Main(string[] args) {
       Clan a = new Clan("Janez", "Starina", 2000, "2304");
       String inicialnkeClanaA = a.Inicialke();
       Console.Write("Clan a:\n" + a.ime + " " + a.priimek +
               " " + a.leto_vpisa + " (" + a.vpisna_st + ") ");
       Console.WriteLine("ima inicialke: " + inicialnkeClanaA);
    }
}

  • inicialnkeClanaA = a. = klic metode

Sprememba metode

public class Clan {
    public string ime;
    public string priimek;
    public int leto_vpisa;
    public string vpisna_st;

    public Clan() {
   ime = "Ne vem";
   priimek = "Ne vem";
   leto_vpisa = 0;
   vpisna_st = "Ne vem";
    }
    public Clan(string i, string p, int l, string v) : this() {
      ime = i;
   priimek = p;
   leto_vpisa = l;
   vpisna_st = v;
    }
    public string Inicialke() {
   return this.ime[0] + " " + this.priimek[0];
    }
}

Spremembe v TestClan
niso potrebne!

Metoda, ki vrača objekt iz Razreda

  • Vemo, da z

    • a = b;
  • kjer sta a in b obe spremenljivki tipa Clan, v a ne shranimo kopije objekta b, ampak sedaj a in b označujeta isti objekt.
  • Metoda, ki naredi kopijo objekta.

    • a = b.Kopija();
  • V a je nov objekt, ki pa ima iste podatke kot b.

Kopija

public Clan Kopija() {
    Clan nov = new Clan();
    nov.ime = this.ime;
    nov.priimek = this.priimek;
    nov.leto_vpisa = this.leto_vpisa;
    nov.vpisna_stevilka =
         this.vpisna_stevilka;
    return nov;
}

Še metoda za izpis

public void Izpis() {
  Console.WriteLine("Clan:\n" + this.ime + " " +
     this.priimek + " " + this.leto_vpisa +
     " (" + this.vpisna_st + ")\n");
}

ali pa še

public string Opis() {
  return this.ime + " " + this.priimek + " " +
         this.leto_vpisa +
         " (" + this.vpisna_st + ");
}

Uporaba

public class TestKlub {
  public static void Main(string[] args) {

    Clan a = new Clan("Janez", "Starina", 2000, "2304");
    Clan b = new Clan("Mojca", "Mavko", 2001, "4377");
    Clan c = b;
    c.ime = "Andreja";
    Clan d = b.Kopija();
    d.ime = "Tadeja";

    Console.WriteLine("Clan a"); a.Izpis();
    Console.WriteLine("Clan b:\n" + b.Opis());
    Console.WriteLine("Clan c:\n" + c.Opis());
    Console.WriteLine("Clan d"); d.Izpis();
    Console.ReadLine();
  }
}

Razred Datum

  • Denimo, da v naših programih pogosto delamo z datumi.
  • Zato bomo sestavili ustrezni razred
  • Načrt razreda:

    • Podatki

      • dan (število)
      • mesec (izbira: število ali pa niz)
      • Leto (število)
    • Metode

      • Konstruktorji
      • Izpiši
      • Povečaj za 1 dan
      • Je datum smiselen
      • Je leto prestopno
      • Nov datum za toliko in toliko dni pred/za danim datumom
      • Dan v tednu
      • ...

Datum – podatki in konstruktor

public class Datum {
   public int dan;
   public string mesec;
   public int leto;

   public Datum() {
      dan = 1;
      mesec = "januar"
      leto = 2000;
   } // privzeti datum je torej 1.1.2000

Dodatni konstruktorji

public Datum(int leto) : this() {
  this.leto = leto; // this je nujen
} // datum je torej 1.1.leto

public Datum(int d, string m, int l) : this(l)
{ // leto smo že nastavili
  this.mesec = m; // this ni nujen
  this.dan = d;
} // datum je torej d.m.l (na primer 12.3.2006 ali
  // 12. marec 2006)

Prestopno

  • Zanima nas, ali je leto prestopno

public bool JePrestopno() {
   int leto = this.leto;
   if (leto % 4 != 0) return false;
   if (leto % 400 == 0) return true;
   if (leto % 100 == 0) return false;
   return true;
}

Dodaj en dan

public void PovecajZaEnDan() {
   dan = dan + 1;
   if (dan < 29) return;
   if (dan == 29 && mesec != "februar") return;
   if (dan == 29 && mesec == "februar" && this.JePrestopno()) return;
// lahko nehamo, mesec in leto sta ok
   string[] meseciPo30 = {"april","junij","september", "november"};

(19.png)

Uporaba razreda

  • Ugotovi, če je letošnje leto prestopno!

using MojiRazredi;

public class JeLetosPrestopnoLeto {
   Datum danes = new Datum(22, 1, 2008);
   if (danes.jePrestopno()) {
     Console.WriteLine("Je prestopno leto");
   } else {
     Console.WriteLine("Ni prestopno leto");
   }
}

Posplošeno Fibonaccijevo zaporedje

  • Fibonaccijevo zaporedje:

    • 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
  • Fibonaccijeva števila definiramo z začetnima pogojema (prvo in drugo število sta enaka 1) ter z rekurzivno formulo (n-to Fibonaccijevo število je vsota prejšnjih dveh) . S temi podatki lahko izračunamo vsa ostala števila.
  • Če začetna pogoja spremenimo (rekurzivno pravilo pa ostane isto), dobimo posplošena Fibonaccijeva števila. Če si npr. za prvo število izberemo 3 in za drugo -1 dobimo zaporedje števil 3, -1, 2, 1, 3, 4, 7, 11...

Posplošeno Fibonaccijevo zaporedje

  • Razred PosploseniFibonacci, ki bo vseboval metodo public int VrniNto(int n) , ki bo izračunal n-to posplošeno Fibonaccijevo število. Razred naj vsebuje dva konstruktorja:
  • publicPosploseniFibonacci() - ta naj za začetni pogoj postavi pogoj za običajna Fibonaccijeva števila.
  • public PosploseniFibonacci(int prvo, int drugo) - temu podamo vrednosti prvega in drugega posplošenega Fibonaccijevega števila.
  • Če torej ustvarimo objekta PosploseniFibonacci fibo = new PosploseniFibonacci() in PosploseniFibonacci splosni = new PosploseniFibonacci(3, -1) nam klica metod fibo.VrniNto(4) in splosni.VrniNto(4) vrneta 3 oz. 1.

Podatki in konstruktorji

  • Hraniti bo potrebno začetna člena

public class PosploseniFibonacci {
  public int prvo;
  public int drugo;

  public PosploseniFibonacci() {
    this.prvo = 1;
    this.drugo = 1;
  }

  public PosploseniFibonacci(int p, int d) {
    this.prvo = p;
    this.drugo = d;
  }

Metoda

public int VrniNto(int n) {
   if (n == 1) return this.prvo;
   if (n == 2) return this.drugo;
   return this.VrniNto(n – 2) +
          this.VrniNto(n – 1);
}

Povečajmo učinkovitost

  • Zelo pogosto potrebujemo prvih 20 členov Fibonnacijevega zaporedja, ostala pa bolj redko
  • Kaj storiti, da izboljšamo odzivnost?
  • Naj objekt hrani še tabelo prvih 20 členov, Če potem uporabimo VrniNto(i) in je i <= 20, le pogledamo v tabelo.
  • Kje narediti tabelo – v konstruktorju!

Podatki in konstruktorji

  • Hraniti bo potrebno tabelo prvih 20 členov

public class PosploseniFibonacci {
  public int[] tabela = new int[20]
  public PosploseniFibonacci() {
    tabela[0] = tabela[1] = 1;
    for (int i = 2; i < 20; i++) {
      tabela[i] = tabela[i – 2] + tabela[i];
    }
  }
  public PosploseniFibonacci(int p, int d) {
    tabela[0] = p;
    tabela[1] = d;
    for (int i = 2; i < 20; i++) {
      tabela[i] = tabela[i – 2] + tabela[i];
    }
  }
}

Vrni Nto

public int VrniNto(int n) {
   if (n < 20) return this.tabela[n – 1];
   return this.VrniNto(n – 2) +
          this.VrniNto(n – 1);
}

0%
0%