Polymorfi Objektorienterad och komponentbaserad programmering
Polymorfi, mångtydighet Polymorfi innebär att en viss konstruktion kan exekveras på olika sätt Överlagring av metoder ger ett polymorft beteende En metod med passande parameterlista binds tidigt, statiskt, till anropet Bindningen sker vid kompileringen av källkoden Polymorfi kan även uppnås med sen, dynamisk bindning av metodanrop till metoder Metodanropet binds till rätt objekt oberoende vilken typ som referensen till objektet är Bindningen sker under runtime, när anropet exekveras
Några begrepp Tidig eller statisk bindning Vilken metod som ska bindas till ett anrop avgörs vid kompileringen Sen eller dynamisk bindning Vilken metod som ska bindas till ett anrop avgörs vid exekveringen av metodanropet Virtuell metod En metod som anropas med dynamisk bindning Abstrakt metod En virtuell metod utan metodkropp Abstrakt klass En klass som inte går att instansera. Har en eller flera abstrakta metoder
Tidig, statisk bindning class KlassA public void enmetod() Console.WriteLine("KlassA, enmetod"); class KlassB : KlassA public new void enmetod() Console.WriteLine("KlassB, enmetod"); class Program public static void Main() KlassA objektet = new KlassB(); objektet.enmetod(); //Anropet binds till en metod vid kompileringen KlassA, enmetod
Sen, dynamisk bindning class KlassA public virtual void enmetod() Console.WriteLine("KlassA, enmetod"); class KlassB : KlassA public override void enmetod() Console.WriteLine("KlassB, enmetod"); class Program public static void Main() KlassA objektet = new KlassB(); objektet.enmetod(); //Anropet binds till en metod när satsen exekveras KlassB, enmetod
Ett exempel till, del 1 using System; public class Person protected string namn; public Person() Console.WriteLine("Defaultkonstruktor: Person"); public Person(string namnet) namn = namnet; Console.WriteLine( Konstruktor: Person"); public virtual void Write() Console.WriteLine("Person: " + namn); public class Student : Person public Student() Console.WriteLine("Defaultkonstruktor: Student"); public Student(string namnet) namn = namnet; Console.WriteLine( Konstruktor: Student"); public override void Write()Console.WriteLine("Student: " + namn); public class Orienterare : Student public Orienterare(string namnet) namn = namnet; Console.WriteLine( Konstruktor: Orienterare"); public override void Write()Console.WriteLine("Orienterare: " + namn); public class Fotbollsspelare : Student public Fotbollsspelare(string namnet) namn = namnet; Console.WriteLine( Konstruktor: Fotbollsspelare"); public override void Write() Console.WriteLine("Fotbollsspelare: " + namn);
Ett exempel till, del 2 public class Test public static void Main() Person[] lista = new Person[4]; lista[0] = new Person("Ada"); lista[1] = new Student("Beda"); lista[2] = new Orienterare("Cesar"); lista[3] = new Fotbollsspelare("Dan"); foreach (Person enindivid in lista) enindivid.write(); Vad händer om metoden Write inte är virtual? Vilket resultat får vi då? Konstruktor: Person Defaultkonstruktor: Person Konstruktor: Student Defaultkonstruktor: Person Defaultkonstruktor: Student Konstruktor: Orienterare Defaultkonstruktor: Person Defaultkonstruktor: Student Konstruktor: Fotbollsspelare Person: Ada Student: Beda Orienterare: Cesar Fotbollsspelare: Dan
Restaurang Oasen, del 1 using System; using System.Collections; public class Hungrig public void Konsumerar(Förtäring[] meny, int nummer) if (meny[nummer]!= null) Console.WriteLine(meny[nummer].Smakar()); meny[nummer] = null; //Äter upp sin mat public abstract class Förtäring //En abstrakt klass går inte att skapa objekt av! public abstract string Smakar(); //Om det finns en abstrakt metod i klassen //så måste även klassen deklareras som abstrakt public class Mat : Förtäring public override string Smakar()return "Dagens rätt är hyfsad.";
Restaurang Oasen, del 2 public class StektSill : Mat public override string Smakar()return "Strömmingen var knaprig och salt."; public class Palt : Mat public override string Smakar()return "Palt smakar alltid Gott!"; public class FaluKorv : Mat public override string Smakar()return "Korven är fantastisk!"; public class Fika : Förtäring public override string Smakar()return "En kopp fika är aldrig fel."; public class Bulle : Fika public override string Smakar()return "Nybakta Bullar är inte dumt."; public class Kaka : Fika public override String Smakar()return "Kakorna var sliskiga";
Restaurang Oasen, del 3 public class Restaurang public static void Main() Hungrig kallekula = new Hungrig(); Förtäring[] meny = new Förtäring[7]; meny[0] = new Mat(); meny[1] = new StektSill(); meny[2] = new Palt(); meny[3] = new FaluKorv(); meny[4] = new Fika(); meny[5] = new Bulle(); meny[6] = new Kaka(); Dagens rätt är hyfsad. En kopp fika är aldrig fel. Nybakta Bullar är inte dumt. Strömmingen var knaprig och salt. Tack för maten! Random slumptal = new Random(); int antal = slumptal.next(1, 8); //Antal maträtter som ska konsumeras for (int i=0; i<antal; i++) kallekula.konsumerar(meny, slumptal.next(7)); //Äter slumpvis en maträtt Console.WriteLine("Tack för maten!");
Gränssnitt och sen bindning using System; using System.Collections; public class Hungrig public void Konsumerar(IFörtäring[] meny, int nummer) if (meny[nummer]!= null) Console.WriteLine(meny[nummer].Smakar()); meny[nummer] = null; //Äter upp sin mat public interface IFörtäring //OBS! Metoderna i ett gränssnitt är inte virtuella i C#!! string Smakar(); public abstract class Förtäring : IFörtäring //Därför måste gränssnittet implementeras //av en klass med abstrakta eller public abstract string Smakar(); //virtuella metoder public class Mat : Förtäring public override string Smakar()return "Dagens rätt är hyfsad.";
Mer om interface Statisk bindning interface IGränsnitt void enmetod(); Dynamisk bindning interface IGränsnitt void enmetod(); class KlassA : IGränsnitt public void enmetod()console.write("a\n"); class KlassA : IGränsnitt public virtual void enmetod()console.write("a\n"); class KlassB : KlassA public new void enmetod()console.write("b\n"); class KlassB : KlassA public override void enmetod()console.write("b\n"); class Program public static void Main() IGränsnitt objektet = new KlassB(); objektet.enmetod(); A class Program public static void Main() IGränsnitt objektet = new KlassB(); objektet.enmetod(); B
Klassen Object Alla klasser ärver indirekt eller direkt av klassen Object Några metoder i klassen Object, avsedda för omdefiniering är; public virtual string ToString() Returnerar en sträng med klassens namn Kan överlagras så att den returnerar information om objektet ifråga public virtual int GetHashCode() Ska returnera en kod som är lika för lika objekt Används av hashtabeller public virtual bool Equals(object obj) Jämför referenser, returnerar true om de båda referenserna refererar till samma objekt Ska överlagras så att den returnerar true om två lika objekt jämförs
Omdefiniering av metoderna, del 1 class Person string namn; int ålder; public Person(string namn, int ålder) this.namn = namn; this.ålder = ålder; public override string ToString()return namn + ", " + ålder + " år"; public override bool Equals(object obj) //OBS object if (obj == null) return false; Person enperson = obj as Person; if (enperson == null) return false; return (namn == enperson.namn && ålder == enperson.ålder); //Kanske inte en och //samma person men lika! public override int GetHashCode()return namn.gethashcode() ^ ålder.gethashcode();
Omdefiniering av metoderna, del 2 public class Test public static void Main() Person kalle1 = new Person("Kalle", 43); Person kalle2 = new Person("Kalle", 43); if (kalle1.equals(kalle2)) Console.WriteLine("Lika"); else Console.WriteLine("Ej lika"); Console.WriteLine(kalle1.GetHashCode()); Console.WriteLine(kalle2.GetHashCode()); Lika 593500676 593500676
Gränssnittet IComparable, del 1 class Person : IComparable string namn; int ålder; public Person(string namn, int ålder) this.namn = namn; this.ålder = ålder; public override string ToString()return namn + ", " + ålder + " år"; public int CompareTo(object obj) Person enperson = obj as Person; if (ålder < enperson.ålder) return -1; else if (ålder == enperson.ålder) return 0; else return 1;
Gränssnittet IComparable, del 2 public class Test public static void Main() Person[] gruppen = new Person[5]; gruppen[0] = new Person("Berit", 42); gruppen[1] = new Person("Zeke", 23); gruppen[2] = new Person("Albin", 71); gruppen[3] = new Person("Stina", 62); gruppen[4] = new Person("Tore", 31); List<Person> laget = new List<Person>(gruppen); Array.Sort(gruppen); //Möjligt på grund av att laget.sort(); //Person implementerar //gränssnittet IComparable Console.WriteLine("\Det sorterade fältet"); foreach (Person individ in gruppen) Console.WriteLine(individ); Console.WriteLine("\nDen sorterade listan"); foreach (Person medlem in laget) Console.WriteLine(medlem); Det sorterade fältet Zeke, 23 år Tore, 31 år Berit, 42 år Stina, 62 år Albin, 71 år Den sorterade listan Zeke, 23 år Tore, 31 år Berit, 42 år Stina, 62 år Albin, 71 år
Gränsnittet IDisposable, del 1 using System; class Person : IDisposable private string namn; private int ålder; private bool disposed = false; public Person(string namn, int ålder) this.namn = namn; this.ålder = ålder; public override string ToString() return namn + ", " + ålder + " år."; ~Person() Console.WriteLine(namn + "s destruktor: anropar Dispose."); Dispose(false); //Låter Dispose frigöra objektets resurser
Gränsnittet IDisposable, del 2 public void Dispose() //Implementerar gränsnittets metod Dispose Dispose(true); //Frigör resurser GC.SuppressFinalize(this); //Förhindrar att objektets finalizer, dvs destruktor, körs private void Dispose(bool disposing) //OBS! private if (disposed) return; Console.WriteLine(namn + " - dispose: I stället för det här meddelandet"); Console.WriteLine(namn + " - dispose: så borde alla resurser frigöras nu."); if (disposing) disposed = true;
Gränsnittet IDisposable, del 3 public class Test public static void Main() Person kalle = new Person("Kalle", 53); Person stina = new Person("Stina", 37); kalle.dispose(); //Objektets resurser frigörs, men objektet består! Console.WriteLine(kalle); kalle.dispose(); //Objektets resurser är redan frigjorda så inget händer. Console.WriteLine(stina); Kalle - dispose: I stället för det här meddelandet Kalle - dispose: så borde alla resurser frigöras nu. Kalle, 53 år. Stina, 37 år. Stinas destruktor: anropar Dispose. Stina - dispose: I stället för det här meddelandet Stina - dispose: så borde alla resurser frigöras nu.