Werte aus Klassenobjekt an Klassenobjekt übergeben.



  • Also angenommen ich habe eine Klasse gebastelt, die quasi die Klasse einer Tierwelt darstellt:

    class CSäugetiere
    {
        public int Geschwindigkeit = 0;
        public int AnzahlBeine = 0;
    }
    

    Dann kann ich davon ja auch Klassen ableiten, um Arten einer Tierwelt der Klasse zu definieren:

    class CDelphin : CSäugetiere
    {
        public CDelphin()
        {
            Geschwindigkeit = 50;
            AnzahlBeine = 0;
        }
    }
    
    class CTiger : CSäugetiere
    {
        public CTiger()
        {
            Geschwindigkeit = 100;
            AnzahlBeine = 4;
        }
    }
    

    Außerdem besitze ich noch eine Klasse, die durch meine Mainfunktion abgearbeitet wird:

    class Wettlauf
    {
        public void Wasser()
        {
            CDelphin dlp = new CDelphin();
            CTiger tgr = new CTiger();
    
            tgr.Geschwindigkeit = tgr.Geschwindigkeit - 95;
    
            if (tgr.Geschwindigkeit > dlp.Geschwindigkeit)
            {
                Console.WriteLine("Sensationell!!!");
            }
        }
    }
    

    Angenommen ich habe nun eine Mainfunktion, welche verschiedene Unterfunktionen aufrufen kann:

    class Hauptklasse
    {
        static void Main (string[]args)
        {
            CWettlauf wlf = new CWettlauf();
            wlf.Wasser();
        }
    }
    

    Wo initialisere ich dann am Besten die Objekte TIger und dElphin, damit ich die Werte auch in der Funktion Wasser habe, ich glaube nicht, dass ich es richtig gemacht habe.



  • du übergibst dem wlf.Wasser() einfach zwei oder mehrere instanzen vom CSäugetiere. Wettlauf kann dann die Werte dort abfragen ohne das es interessiert welche art Tiere es sind. Das ist der Sinn solch einer Basisklasse.

    Anm.d.R.:

    1. CKlassenname ist sehr unüblich, ich kenn das nur aus der MFC, sowas sollte man vermeiden.
    2. Mach aus CSäugetiere eine abstrackte Klasse oder ein Interface, damit man kein direktes Säugetier erstellen kann
    3. Nimm lieber Englische bezeichner (Säugetiere ist deutsch und hat ein Umlaut - doppelt schlecht)
    4. Abkürzungen sind Böse (tgr - wenn man das irgendwo sieht weiß keiner was das sein soll, wlf kann auch wolf bedeuten)
    5. tgr.Geschwindigkeit = tgr.Geschwindigkeit - 95; kann man kürzen zu tgr.Geschwindigkeit -= 95;
    6. Vermeide Magic Numbers (die 95 ist willkürlich im Code gesetzt ohne erkennbaren Zusammenhang)
    7. Definiere Geschwindigkeit sowie AnzahlBeine als Properties, nicht als Öffentliche Felder.
    8. Mach den Setter von Punkt 7 Privat, sodass er nur von der Klasse selber (gegeben über den Konstruktor) gesetzt werden kann.
    9. Weise der Geschwindigkeit in der CTieger klasse keinen neuen Wert zu, egal wo, dadurch veränderst du es dauerhaft
    10. Ein Console Out sollte nur in der Main Klasse geschehen

    public abstract class Mammal
    {
        protected Mammal(int speed, int legs)
        {
            Speed = speed;
            Legs = legs;
        }
    
        public int Speed { get; private set; }
        public int Legs { get; private set; }
    }
    
    public class Dolphin : Mammal
    {
        public Dolphin()
          : base(50, 0)
        {
        }
    }
    
    public class Tiger : Mammal
    {
        public Tiger()
          : base(100, 4)
        {
        }
    }
    
    public class Footrace
    {
        private static int LEGS_IN_WATER = 95;
    
        public Mammal InWater(Mammal firstAttendee, Mammal secondAttendee)
        {
            var firstSpeed = AdjustSpeedByLegs(firstAttendee);
            var secondSpeed = AdjustSpeedByLegs(secondAttendee);
    
            return firstSpeed > secondSpeed ? firstAttendee : secondAttendee;
        }
    
        private int AdjustSpeedByLegs(Mammal attendee)
        {
            if (attendee.Legs > 0)
                return attendee.Speed - LEGS_IN_WATER;
            return attendee.Speed;
        }
    }
    
    class Program
    {
        static void Main (string[]args)
        {
            var race = new Footrace();
    
            var tiger = new Tiger();
            var dolphin = new Dolphin();
    
            Console.WriteLine("The winner in the water is the " + race.InWater(tiger, dolphin).GetType());
        }
    }
    


  • Jo, danke erstmal für deine Hilfe. Dass die Veränderungen so verheerend sind macht mein Problem jetzt richtig kompliziert, da ich mit den Tieren nur ein Auszug meines Programmes (nahezu 1000 Zeilen) geliefert habe, aber mit deinen Korrekturen bin ich teilweise vor nur noch mehr Probleme gestellt worden.
    Ich hoffe du kannst mir nochmal helfen, weil jetzt funktioniert das Programm überhaupt nicht mehr.

    Also was ich eigentlich will:
    Eine feste Art wird bestimmt z.B. Tiger (var tiger = new Tiger();).
    Dieser hat Anfangswerte (haben wir gesetzt) sollen später verändert werden durch den Ablauf des Programmes.
    Dazu soll eine zufällige Art bestimmt werden (aus über 20 Arten!!!), die unter bestimmten Bedingungen hier und da mit dem Tiger verglichen wird.

    -------------------------------------------------------------------------
    Aber wie bestimme ich dann die Random Klasse?
    Hatte erst den Ansatz, in dem ich eine zufällige int bestimmt habe und mit einer if-Abfrage dem int dann ein Objekt zugewiesen habe. Also

    if (i==1)
    {
        var dolphin = new Dolphin();
    }
    

    Ist das zu kompliziert bei sovielen Arten?
    -------------------------------------------------------------------------
    In deinem Code ist es nun so, dass der Wert des Tigers verändert werden soll durch eine Zahl, die für die andere Klasse aber keine Relevanz haben darf.

    Deshalb habe ich den Tiger in der Klasse extra erwähnt:

    Random ConditionTiger = new Random();
        DailyConditionTiger = ConditionTiger.Next(10, 100);
        Console.ReadKey();
        Console.WriteLine("\tTagesform des Tigers: {0}", DailyConditionTiger);
    

    Der wert soll dann auf den Wert addiert werden im Footrace, deshalb die frage, welcher ist den der wert für den Tiger? Ist das dann var firstSpeed = AdjustSpeedByLegs(firstAttendee);
    , weil Tiger auch als erstes in der Main initilisiert wurde?
    --------------------------------------------------------------------------
    Zu Punkt 9: Mein Ziel ist es im Anschluss, dass der Tiger eben dauerhaft den zugewiesenen Wert bekommt (so dass bei einer erneuten Abfrage der Main nach Footrace ein schneller oder langsamerer Tiger dabei ist), weil er durch training dann z.B. schneller wird, also muss ich das doch dann zuweisen?

    Das letzte Problem ist, was ich nun mache, wenn es Einfluss haben soll auf eine andere Funktion, welcher das schnellere Tier war. Angenommen der Tiger gewinnt, dann gibt es eine Klasse Food, in der dieser Wert dafür entscheidend ist, welches Tier zuerst ist.
    Es soll also besipielsweise ausgegebn werden.

    Console.WriteLine("Da {0} zuerst bei der Beute war wird er auch zuerst Essen wodurch er 1 cm größer wird, im Gegensatz zu {1}, WinnerFootrace, LooserFootrace");
    

    Das war über meine Art ganz leicht, da ich im Rennen einfach ermittlet habe, wer schneller ist (leider aber eben ohne Grundwert, weshalb ich deine Hilfe ja auch benötigte 😉 ) und den Gewinner habe ich dann gesetzt.
    In der Food Klasse, habe ich dann mit Variablen gearbeitet FeederOne und Feeder Two, aber kann ich die dann nach deiner Methode auch so einfach durch Gewinner und verlierer zuweisen?



  • Hi,

    Ich teile deine aussagen mal in Teilprobleme auf, dadurch ist es leichter analysierbar ^^

    Jo, danke erstmal für deine Hilfe. Dass die Veränderungen so verheerend sind macht mein Problem jetzt richtig kompliziert

    Verheerend ^^ Hajo es sind viel mehr Vorschläge, aber schön das du darauf ein gehst.

    , da ich mit den Tieren nur ein Auszug meines Programmes (nahezu 1000 Zeilen) geliefert habe, aber mit deinen Korrekturen bin ich teilweise vor nur noch mehr Probleme gestellt worden.
    Ich hoffe du kannst mir nochmal helfen, weil jetzt funktioniert das Programm überhaupt nicht mehr.

    Schaun wir mal 😃 (bin auch in ICQ online 😉 bei kurzen schnellen rückfragen)

    Also was ich eigentlich will:
    Eine feste Art wird bestimmt z.B. Tiger (var tiger = new Tiger();).
    Dieser hat Anfangswerte (haben wir gesetzt) sollen später verändert werden durch den Ablauf des Programmes.

    Problem 1. Es sollen Werte in den Tieren veränderbar sein.
    Die Beine bestimmt nicht ^^ aber nehmen wir die Kondition oder die Geschwindigkeit.
    Ich würde vor schlagen das die Tiere eine Methode anbieten der du diverse Sachen mitgeben kannst, zb futter.

    tiger.Eat(gazelle);
    

    Wie es intern in der "Eat" Methode ausgewertet wird, sei es in Energie, Kondition oder Fett, bestimmt allein das Tier.

    Angenommen das Gewinnertier bekommt ein Apfel, dann gibst du den Gewinner den Apfel und lässt ihn selber entscheiden wie es damit um geht. Dadurch kann ein Delphin anders reagieren als eine Heuschrecke.

    benutzer_1234 schrieb:

    Dazu soll eine zufällige Art bestimmt werden (aus über 20 Arten!!!), die unter bestimmten Bedingungen hier und da mit dem Tiger verglichen wird.

    -------------------------------------------------------------------------
    Aber wie bestimme ich dann die Random Klasse?
    Hatte erst den Ansatz, in dem ich eine zufällige int bestimmt habe und mit einer if-Abfrage dem int dann ein Objekt zugewiesen habe. Also

    if (i==1)
    {
        var dolphin = new Dolphin();
    }
    

    Ist das zu kompliziert bei sovielen Arten?

    Problem 2. Es sollen "zufällig" verschiedene Arten von Tieren erstellt werden.
    Das würde ich über eine Factory Klasse lösen.
    Eine Klasse die intern alle Tierarten kennt, und dann davon eins "auswürfelt".

    Hier mal Klassen die ich mir vorstellen kann
    Du hast einen "Pool" an verfügbaren Tieren, da kannst du dann leicht die verfügbaren Tiere verwalten.

    public static class AnimalPool
    {
        public static List<Type> GetAnimals()
        {
            return new List<Type>
            {
                typeof(Tiger),
                typeof(Dolphin),
                typeof(Gazelle),
                typeof(Elephant)
            };
        }
    }
    

    Und dann die eigentliche Factory die ein Konkretes Tier erzeugt (kein Wunder das Entwickler sich manchmal wie Gott fühlen ^^)

    public static class AnimalFactory
    {
        private static Random _random;
    
        static AnimalFactory()
        {
            _random = new Random(DateTime.Now.Second);
        }
    
        public static Mammal CreateAnimal()
        {
            var availableAnimals = AnimalPool.GetAnimals();
            var value = _random.Next(0, availableAnimals.Count - 1);
            return (Mammal)Activator.CreateInstance(availableAnimals[value]);
        }
    }
    

    Dadurch kannst du nun jederzeit ein Tier von dern AnimalFactory holen

    var animal = AnimalFactory.CreateAnimal();
    

    In deinem Code ist es nun so, dass der Wert des Tigers verändert werden soll durch eine Zahl, die für die andere Klasse aber keine Relevanz haben darf.

    Du meinst die 95? Ich wusste nicht genau was die bedeuten soll, daher habe ich es nur so konstruiert das es die Geschwindigkeit beeinflusst je nachdem ob es Beine hat oder nicht.

    Deshalb habe ich den Tiger in der Klasse extra erwähnt:

    Random ConditionTiger = new Random();
        DailyConditionTiger = ConditionTiger.Next(10, 100);
        Console.ReadKey();
        Console.WriteLine("\tTagesform des Tigers: {0}", DailyConditionTiger);
    

    Jedes "Mammal" oder "Animal", je nachdem was deine Basis ist sollte eher ein "Condition" Property anbieten. Dieses wird dann wie oben erwähnt innerhalb der Klasse verwaltet, ein Tieger der gerade Fras hat eine andere Kondition als ein Hungernder.
    d.h.

    var condition = animal.Condition;
    

    Der wert soll dann auf den Wert addiert werden im Footrace, deshalb die frage, welcher ist den der wert für den Tiger? Ist das dann var firstSpeed = AdjustSpeedByLegs(firstAttendee);
    , weil Tiger auch als erstes in der Main initilisiert wurde?

    Mein "AdjustSpeedByLegs" arbeitet Tier unabhängig, er hat danach beurteilt ob das Tier Beine hat oder nicht. Sobald dein Tier ein "Condition" property anbietet hast du deine relevanten Daten da.

    --------------------------------------------------------------------------
    Zu Punkt 9: Mein Ziel ist es im Anschluss, dass der Tiger eben dauerhaft den zugewiesenen Wert bekommt (so dass bei einer erneuten Abfrage der Main nach Footrace ein schneller oder langsamerer Tiger dabei ist), weil er durch training dann z.B. schneller wird, also muss ich das doch dann zuweisen?

    Nein, den Tieger weist du nichts zu, viel mehr sagst du den Tier das es Trainieren soll, ob und wie es sich dann auf die Kondition oder Geschwindigkeit auswirkt liegt im ermessen des Tieres.

    animal.Practice(practiceKind);
    

    practiceKind kann dann Running, Swimming oder sonstwas sein, und das Tier entscheidet wie es damit um geht.

    Das letzte Problem ist, was ich nun mache, wenn es Einfluss haben soll auf eine andere Funktion, welcher das schnellere Tier war. Angenommen der Tiger gewinnt, dann gibt es eine Klasse Food, in der dieser Wert dafür entscheidend ist, welches Tier zuerst ist.
    Es soll also besipielsweise ausgegebn werden.

    Console.WriteLine("Da {0} zuerst bei der Beute war wird er auch zuerst Essen wodurch er 1 cm größer wird, im Gegensatz zu {1}, WinnerFootrace, LooserFootrace");
    

    Das war über meine Art ganz leicht, da ich im Rennen einfach ermittlet habe, wer schneller ist (leider aber eben ohne Grundwert, weshalb ich deine Hilfe ja auch benötigte 😉 ) und den Gewinner habe ich dann gesetzt.
    In der Food Klasse, habe ich dann mit Variablen gearbeitet FeederOne und Feeder Two, aber kann ich die dann nach deiner Methode auch so einfach durch Gewinner und verlierer zuweisen?

    Nehmen wir mein Beispiel:

    var tiger = new Tiger();
    var dolphin = new Dolphin();
    var price = new Apple();
    
    var winner = race.InWater(tiger, dolphin);
    Console.WriteLine("Der {0} hat gewonnen, dadurch darf er nun {1} verspeisen", winner, price);
    winner.Eat(price);
    

    Ob der Tieger nun 1 cm gewachsen ist wegen den Apfel, oder ob er ihn komplett verschmähte, liegt im ermessen des Tieres selber und an die Art des Gewinns. Du kannst dann im Tier Events anbieten die benachrichtigen wenn sich bestimmte Werte geändert haben. Eventuell wächst der Tieger erst wenn er 19 Äpfel gegessen hat oder 1 Schwein. Das muss individuell behandelt werden.


  • Administrator

    David W schrieb:

    10. Ein Console Out sollte nur in der Main Klasse geschehen

    Wie bitte? Ein Console Out kann überall hinkommen, nur sollte man es korrekt aufgliedern. Es hat sicher nichts in " Wettlauf " oder " Wasser " zu suchen. Man kann aber für die Ausgabe ebenfalls Klassen erstellen, welche bestimmte Ausgaben vereinfachen. Es muss daher definitiv nicht nur in der Main Klasse geschehen. Sauber trennen soll man es.

    @benutzer_1234,
    David W hat zwar das folgende indirekt schon gesagt, bzw. im Code gezeigt, aber von allen Punkten möchte ich das nochmals besser unterstreichen. Felder nie öffentlich machen, sondern immer privat. Eine Initialisierung der Felder macht immer die Klasse, welche die Felder definiert. Wenn du Initialwerte von einer abgeleiteten Klasse übergeben möchtest, dann immer über die Konstruktoren. So wie es David W gezeigt hat:

    public abstract class Mammal
    {
        protected Mammal(int speed, int legs)
        {
            Speed = speed;
            Legs = legs;
        }
    
        public int Speed { get; private set; }
        public int Legs { get; private set; }
    }
    
    public class Dolphin : Mammal
    {
        public Dolphin()
          : base(50, 0)
    //      ^^^^^^^^^^^ !!! ;)
        {
        }
    }
    

    So wird die Verantwortung an Ort und Stelle gehalten. Sonst hast du mit der Zeit keine Übersicht mehr darüber, wer wo und wann auf die Felder zugreift.

    Grüssli



  • Dravere schrieb:

    David W schrieb:

    10. Ein Console Out sollte nur in der Main Klasse geschehen

    Wie bitte? Ein Console Out kann überall hinkommen, nur sollte man es korrekt aufgliedern. Es hat sicher nichts in " Wettlauf " oder " Wasser " zu suchen. Man kann aber für die Ausgabe ebenfalls Klassen erstellen, welche bestimmte Ausgaben vereinfachen. Es muss daher definitiv nicht nur in der Main Klasse geschehen. Sauber trennen soll man es.

    Natürlich, ich bezog mich in diesem Fall nur auf seinen konkreten Code, bei dem vorliegenden Klassen macht eine Ausgabe nur in der Main Methode Sinn.


  • Administrator

    David W schrieb:

    Dravere schrieb:

    David W schrieb:

    10. Ein Console Out sollte nur in der Main Klasse geschehen

    Wie bitte? Ein Console Out kann überall hinkommen, nur sollte man es korrekt aufgliedern. Es hat sicher nichts in " Wettlauf " oder " Wasser " zu suchen. Man kann aber für die Ausgabe ebenfalls Klassen erstellen, welche bestimmte Ausgaben vereinfachen. Es muss daher definitiv nicht nur in der Main Klasse geschehen. Sauber trennen soll man es.

    Natürlich, ich bezog mich in diesem Fall nur auf seinen konkreten Code, bei dem vorliegenden Klassen macht eine Ausgabe nur in der Main Methode Sinn.

    Ah, ok. Ich war echt gespannt, mit welcher Argumentation du da kommen würdest. Aber in dem Fall war es nur ein Missverständnis 🙂

    Grüssli



  • Wow, da bin ich mal ne Woche win Paar Tage im Urlaub und dann stehe ich vor Romanen an Hilfestellung. Scheinbar hat es sich schonmal gelohnt, dass ich mich nochmal mit den Grundlagen befasst habe. Bei den Klassen sieht man ja immernoch Verbesserungsbedarf, aber ich dachte mal, dass ich die Kenntnisse versuche selber anzuwenden, was ja nicht so schlecht war.

    Eingegangen bin ich auf deine Vorschläge, lieber David W, weil du offensichtlich der Fachmann bist und weshalb sollte ich mein Programm nicht auch dementsprechend aktualisieren. Alleine die Gestaltung der Tierunterklassen ist viel übersichtlicher und vom Programmcode kürzer, was beim Scrollen hilft;)

    Außerdem konnte ich die Fehler nunmehr arg reduzieren.

    Ich muss nun mal alles versuchen anzupassen und zu tüfteln und hoffe, dass ich dadurch nun viel weiter komme. Ich melde mich, wenn es noch irgendow speziell im Verständnis hakt;)


Anmelden zum Antworten