# OOP Umsetzung gesucht



## Gast2 (27. Jun 2008)

Moin,

da ich momentan nicht weis wie ich das Programmtechnisch umsetzen soll ... folgendes

ich habe eine Klasse Krieger ... Augenmerk liegt auf der Methode AttackValue()

```
public class Krieger
{
	public int AttackeValue() { return 0; }

	public void _1on1_(Krieger defender)
	{
		int value = Atlantis.rnd(0, AttackValue() + defender.AttackValue());
		
		// Angriff erfolgreich? -> Schaden berechnen
		if (value <= AttackValue()) defender.lebenspunkte -= DamageValue();
	}

	// weiterer Kram

}
```

dann gibt es noch verschiedene Klassen die von Krieger erben (macht Sinn)

```
public class Schwertkaempfer extends Krieger { }
public class ReiterMitSchwert extends Krieger { }
public class Speerkämpfer extends Krieger { }
```

diese Klassen haben die Methode AttackValue() erfolgreich überschrieben und liefern einen passenden Angriffswert ... das Problem liegt beim Speerkämpfer

greift der Speerkämpfer den Schwertkämpfer an, so habe ich einen Angriffswert ... greift der Speerkämpfer aber den Reiter an, so habe ich einen anderen Angriffswert

meine einzige Idee wie ich das Problem lösen kann, wäre der Methode den Angegriffenen (also Reiter oder Schwertkämpfer) mit zu liefern ... dann müsste ich in der Methode entsprechenden mit if (o instanceof Schwertkaempfer) arbeiten ... das würde ich gerne vermeiden, da es mehrere solcher Ausnahmen und noch weitere Krieger gibt ... somit wird es ein langes if mit instanceof

ich hätte gerne eine nette OOP-Lösung (wo einem meist alles auf die Füße fällt)

hand, mogel


----------



## Gelöschtes Mitglied 5909 (27. Jun 2008)

und was is jetzt dein Problem?

dass attackvalue 0 (bzw du keinen hast)  ist?

dann setzt ihn halt vorher (ctor / setter)


----------



## diggaa1984 (28. Jun 2008)

nein sein problem ist, das er viele versch. attackValues hat, je nach Gegnertyp. und er würde quasi nur eine methode wollen "getAttackValue" welche passend zum gegner den angriffswert liefert, so wie ich das verstanden hab.

nu is die frage wie er ohne grossartiges rumwürgen am code auch später noch einfach neue kämpferklassen erstellen kann, und möglichst leicht neue angriffswerte liefern kann, ohne "instanceof"-Prüfungen

so rein auf die schnelle fällt mir nur ein:

- kämpferklassen haben ID's, welche die klasse eindeutig identifizieren
- jede kämpferklasse hält ein Array mit den Angriffswerten pro Gegnerklasse
- dabei sind die einträge gemäß den ID's der kämpferklassen geordnet, sprich Arrayindex 0 = Kämpferklasse.id = 0
  damit du nicht suchen brauchst sondern direkt mit der ID den index bestimmst

- kannst dann das Array hardcoden im code
- deine getAttackValue würde nun den angriffswert auslesen, und benötigt dazu nur die ID der gegnerklasse


hat aber weniger was mit OOP zu tun, mehr ne lösung fürn logisches problem


----------



## Guest (28. Jun 2008)

Wenn es wirklich um das instanceof und die if-Abfragen geht könnte man das auch mit einer Map<Class,Integer> lösen. Als Key einfach die konkrete Krieger-Klasse des Gegners und als Value den Angriffswert als Integer. Alos z.B so:


```
Map<Class,Integer> kriegerMap = new HashMap<Class,Integer>();
kriegerMap.put(Schwertkaempfer.class, 23);
kriegerMap.put(Reiter.class, 42);

public int AttackeValue(Krieger krieger) {
     return ((Integer)kriegerMap.get(krieger.gerClass())).intValue();
}
```


----------



## Gast2 (28. Jun 2008)

Moin,

ich habe heute morgen nochmal "Design Patterns" durchwühlt, aber da auch nichts gefunden ... ich werde einfach den Angreifer in AttackValue() mit über geben und dann mit instanceof arbeiten ... dann habe ich zumindest alle Modifikationen bei einer Klasse zusammen

hand, mogel


----------



## Yzebär (28. Jun 2008)

Ich würde eine static-Methode definieren, der du Angreifer und Verteidiger übergibst. 

Ein instanceof kannst du in einer Kriegerklasse (zB Speerkämpfer) nur verwenden, wenn du verschiedene Klassen von Einheiten verwendest, auf die dann geprüft wird und sich diese Klassen auch nicht mehr ändern (d.h. keine neuen hinzukommen). Die konkreten Kriegerklassen dürfen sich nicht untereinander kennen, ansonsten hast du sehr viel Arbeit, wenn du neue Kriegerklassen hinzufügst. 

Bei meinem Vorschlag steht die Berechnung nur an einer einzigen Stelle und auch nur dort sind alle Kriegerklassen bekannt. Zudem sollten die Kriegerklassen sowieso keine Berechnungslogik enthalten, sondern nur Container für die Attribute der Klasse sein. Bei Aktionen, werden die Objekte in eine Methode reingereicht und können dort auch gleich entsprechend modifiziert werden (zB. bei einem Angriff wird der Attack-Wert dess Angreifers ermittelt und entsprechend dem Verteidiger HPs abgezogen).


----------



## Gast2 (28. Jun 2008)

Moin,



			
				Yzebär hat gesagt.:
			
		

> Ein instanceof kannst du in einer Kriegerklasse (zB Speerkämpfer) nur verwenden, wenn du verschiedene Klassen von Einheiten verwendest, auf die dann geprüft wird und sich diese Klassen auch nicht mehr ändern (d.h. keine neuen hinzukommen).


es werden noch einige hinzukommen ...


> Die konkreten Kriegerklassen dürfen sich nicht untereinander kennen, ansonsten hast du sehr viel Arbeit, wenn du neue Kriegerklassen hinzufügst.


... da ich das weis, wollte ich ja einen OOP-Ansatz haben um die einzelnen Klassen voneinander zu trennen

das was ich oben kurz dargestellt habe ist nur ein kleiner Teil der Problematik ... der Angriffswert alleine berechnet sich schon aus verschieden Dingen (Talentwert, Rasse, Terrain, ...) ... dazu kommen noch einige Boni & Mali wenn sich gewisse Klassen gegenüber stehen (z.B. eben Reiter & Speerkämpfer) ???:L 

dann habe ich das Problem noch an einigen anderen Stellen im Programm ... auch dort handhabe ich das Ganze im Moment mit IF-Abfragen



hand, mogel



<werbung>bei Bedarf kann links der Link angeklickt werden und unter Bibliothek/Kriege die Komplexität festgestellt werden</werbung>


----------



## diggaa1984 (28. Jun 2008)

also hm, um später mal eventuelle aenderung wegen balancing vornehmen zu können, und der masse wegen, wäre es fast besser das ganze irgendwie extern aus ner datei zu laden oder? und dort kannst alles eintragen was du brauchst. wie man das dann schoen verteilt an die klassen is wieder ne frage für sich 
den tipp mit der Map fand ich gar net mal so schlecht.


----------



## Marco13 (28. Jun 2008)

EDIT: den Beitrag von 17:02 hatte ich noch nicht gesehen .... hab da eine Weile rum-gebrainstormt .... :roll: 



Entscheidend ist imho die Frage, welches Kriterium darüber entscheidet, wie die AttackValue ist. Im einfachsten/schlechtesten Fall hat man eine Matrix:

```
Typ  A  B  C
  A  1 5 6
  B  3 1 7
  C  5 3 1
```
wo jedem Typ die AttackValue zugeordnet ist, die sie für jeden anderen Typ hat. Das ist aber schlecht, weil es schwer erweiterbar ist, und man lauter instanceof-Abfragen hat (und dort eine Map<Class, Integer> zu verwenden, verlagert das Problem sozusagen(!) nur von Compile- auf Laufzeit...) 

Wenn es irgendein Kriterium gibt, auf Basis dessen man entscheiden kann, ob die "normale" AttackValue verwendet wird, oder eine andere, kann man das entsprechend modellieren. Zum Beispiel(!) könnte die abstrakte Krieger-Klasse eine Methode "hatPferd" anbieten, und nur der KriegerMitPferd liefert dort "true" zurück. Die Berechnung der AttackValue wäre dann

```
Speerkämpfer
{
....
    if (gegner.hatPferd()) return standardAttackValue + 5;
    else standardAttackValue;
}
```

AAAABER: Das ist immernoch nicht schön erweiterbar, weil da ja noch andere Kriterien dazukommen können. Wenn man dann code hat wie

```
Speerkämpfer
{
....
    if (gegner.hatPferd()) return standardAttackValue + 5;
    if (gegner.hatSchild()) return standardAttackValue - 5;
    if (gegner.hatRüstung()) return standardAttackValue - 7;
    if (gegner.hatFrikadelleAmKnie()) return standardAttackValue + 134125;
    ....
}
```
ist das auch bogus. 

Wie man das schön abstrakt und allgemeingültig modellieren kann, weiß nur der, der das Programm schreibt. 

Möglich wäre z.B., dass jeder Krieger auch eine "defenseValue" hat, die irgendwie mit der AttackValue verrechet wird, z.B. durch ein Pferd erhöht oder verringert werden kann.

Eine andere, noch allgemeiner gültige Alternative (die aber halbgar und nur spontan rumgesponnen ist) wäre, für die "AttackValue" nicht nur einen int zu verwenden, sondern eine Klasse "Attack", die noch zusätzliche Informationen enthält, und zwischen den Kriegern passend verrechent wird.... GANZ, GANZ grob rumgesponnen... sowas wie

```
class Attack
{
    int value;
    int height;
}

class KriegerMitPferd
{
    void receiveAttack(Attack attack)
    {
        if (attack.getHeight() < 10) // trifft nur das Pferd
        {
             health -= (attack.getValue() - 5);
        }
        else
        {
             health -= (attack.getValue());
        }
    }
}


class KriegerMitSpeer
{
    void doAttack(Krieger gegner)
    {
         gegner.receiveAttack(new Attack(schaden, 20)) // Große höhe: Schadet KriegerMitPferd  viel
    }
}
class KriegerMitMesser
{
    void doAttack(Krieger gegner)
    {
         gegner.receiveAttack(new Attack(schaden, 1)) // Kleine höhe: Schadet KriegerMitPferd nur wenig
    }
}
```
(hierbei wäre die "height" eben das Kriterium, das entscheidet, wie viel oder wenig der Angriff einem Spieler schaden kann - denkbar wären für eine Attack auch attribute wie "geschwindigkeit", "reichweite", "typ" (Stich- oder Hiebwaffe) oder so.... DA kann man sich einmal einen Satz von Eigenschaften überlegen, der einen "Angriff" möglichst vollständig beschreibt, so, dass man danach für jede beliebige Gegner-Paarung einen vernünftigen attackValue ausrechnen kann. Vielleicht könnte das sogar so weit gehen, dass es auch eine Klasse "Defense" gibt.... aber wie gesagt, das ist jetzt nur rumgesponnen.... alles Dinge, die in die Modellierung mit einfließen könn*T*en.

(Irgendwie geisterte auch gerade das Wort "AttackValueModifier" in meinem Kopf rum......)

BTW: Schau dir in bezug auf deine bisherigen Klassen auch mal
http://de.wikipedia.org/wiki/Decorator
an. Bisher hast du
_Schwertkaempfer extends Krieger 
ReiterMitSchwert extends Krieger_
Man könnte jetzt erstmal sagen, dass sowas wie
_ReiterMitSchwert extends *SchwertKämpfer*_
erstmal sinnvoller aussehen würde, aber "gut" wäre es immernoch nicht....Wenn du dann noch sowas hast wie
_ReiterMitSchwertUndSchild extends Krieger
ReiterMitSpeerUndSchild extends Krieger
ReiterMitVergiftetemSpeerUndSchildUndRüstung extends Krieger
ReiterMitVergiftetemSchwertUndSchildUndRüstungUndFrikadelleAmKnie extends Krieger
wird das auch schnell sehr häßlich.... Mit dem Decorator-Pattern könnten dann z.B. eine Methode "createAttack" definieren, die dann die Attack durch die dekorierten Instanzen reicht:
Speerkämpfer: Erstellt Attack mit attackValue 5
ReiterMitSpeer: Erhöht die "Height" dieser Attack um 10
ReiterMitVergiftetemSpeer: Erhöht die attackValue um 5
....

(Rumspinn-Brainstorming ende .... :wink: )_


----------



## Yzebär (28. Jun 2008)

Da das Angriffsverhalten eines Schwertkämpfers davon abhängig ist, wen er angreift, ist das Decorator-Pattern m.E. nicht so ganz das Richtige. Daher würde ich, wie bereits vorher erwähnt, die gesamte Logik für Berechnungen von Kämpfen in eine Berechnungsengine auslagern, der man jeweils die Kontrahenten übergibt. 


```
public class Berechnungen
{
    public static void berechneKampf(Krieger angreifer, Krieger verteidiger)
    {
     ... // berechnet hier den wirksamen Attack-/Defend-Wert 
         // (abhängig davon welche Arten von Kämpfern gegeneinander antreten)
        verteider.setHP(...);
        angreifer.setHP(...);
    }
}

public class Speerkaempfer
{
    // member für Fähigkeiten und Equipment

   public int getAttackValue()
   {
    ... // errechnet hier anhand der Items (Rüstung, Waffen) und Fähigkeiten einen allgemeinen Wert
   }
}
```

Und so beinhaltet die Berechnungsengine Berechnungen für alle Arten von Interaktionen. Die Daten für diese Berechnungen liefern die Krieger-Objekte. Wenn neue Einheiten hinzukommen, muß nur immer wieder die Berechnungsengine erweitert werden. Alle anderen Klassen, die zum Beispiel die Spielumgebung verwalten, brauchen auch nur die Oberklasse aller Kriegerobjekte zu kennen, da für alle Interaktionen zwischen den Spielern die Berechnungsengine verwendet wird. Wenn du für die Berechnung eine Matrix verwendest, müssen der Engine auch nicht alle Kriegerimplementierungen bekannt sein.

Die Auslagerung der Interaktionen aus den Kriegerobjekten ist deswegen sinnvoll, weil bei Änderungen der Interaktionsmodalitäten, alle Implementierungen der Kriegerklassen geändert werden müssen, die Objekte einen Haufen Methoden haben, die sie möglicherweise nicht alle benutzen und die Klassen u.U. mehr voneinander wissen müssen als eigentlich nötig.


----------



## Illuvatar (29. Jun 2008)

(hab jetzt nicht ganz alles hier gelesen nur eine kleine Anmerkung)

OOP und was weiß ich was alles können die nicht um irgendwelche langen if-else-Konstrukte rumhelfen. Du kannst sie vielleicht sogar in Dateien auslagen und anders nennen, in extra Klassne auslagern oder sonstwas. Aber irgendwo muss es nun mal festgelegt werden: Wenn ein Space Marine einen Eldar-Avatar angreift, dann macht das 3 Schaden.


----------



## Marco13 (29. Jun 2008)

_Da das Angriffsverhalten eines Schwertkämpfers davon abhängig ist, wen er angreift, ist das Decorator-Pattern m.E. nicht so ganz das Richtige. _

Der unverbindliche (!) Vorschlag, sich mal das Decorator-Pattern anzusehen, bezog sich NUR und ausschließlich darauf, dass man eben nicht solche absurden Unterklassen wie
_
MenschMitSchwert extends Krieger
ElfMitSchwert extends Krieger
OgerMitSchwert extends Krieger
....
ReiterMitVergiftetemSchwertUndSchildUndRüstungUndFrikadelleAmKnie extends Krieger
_
erstellen sollte. Es macht ja keinen Sinn, praktisch für jede Eigenschaft, die "dazukommt", eine neue Unterklasse anzulegen.... :autsch:  Man KÖNNTE solche zusätzlichen Eigenschaften über das Decorator-Pattern abbilden: Es gibt einen Krieger, und der Kann ein Pferd haben, oder eben nicht. Eine Alternative zum Decorator-Pattern könnte so eine Art "Inventar"-Klasse sein, die jeder Krieger hat. Wie auch immer: Man weiß vorher nicht unbedingt, was da alles dazukommen kann, und es sollte möglichst einfach sein, neue Eigenschaften dazuzupacken. (Dass diese neuen Eigeschaften dann auch beim Berechnen der attackValue berücksichtigt werden müssen, ist ein anderes Thema).

Also: Das mit dem Decorator hatte nicht direkt (nur indirekt) mit dem Problem des Berechnens der attackValue zu tun.

Zur AttackValue: Die Lösung mit der Berechnungsengine IST ja genau "eine" Matrix. Egal, wie sie implementiert ist. (Irgendwie war ich da eine Abstraktionsebene höher)


> public static void berechneKampf(Krieger angreifer, Krieger verteidiger)
> {
> ... // berechnet hier den wirksamen Attack-/Defend-Wert
> //* (abhängig davon welche Arten von Kämpfern gegeneinander antreten)*



Diese Abhängigkeit muss ja irgendwie berechnet werden (und DAS war ja die ursprüngliche Frage). Da gibt es verschiedene Möglichkeiten.

```
if (k1 instanceof KriegerMitPferd && k2 instanceof Speerkämpfer) { return x; }

// oder

if (k1.getType()== Type.KriegerMitPferd && k2.getType() == Type.Speerkämpfer) { return x; }

// oder

return someMagicMatrix.get(k1.getClass(), k2.getClass());

// oder, oder, oder....
```

Und wenn ein neuer Typ dazukommt, muss man für jeden Fall und jede Kombination neuen Code einfügen (also eine Zeile und eine Spalte zu dieser Matrix hinzufügen). Das ganze aber nicht nur für jeden neuen Typ, sondern für jede neue Waffe (sofern das nicht das gleiche ist - siehe oben) oder jedes Add-On, jeden Zaubertrank oder was weiß ich....

Grundsätzlich spricht nichts dagegen, die Berechnungen für die Kämpfe in eine eigene Klasse auszulagern. Dein Vorschlag war jetzt praktisch, alle möglichen Ergebnisse, die auftreten können, einfach "aufzuzählen", und dann einfach nachzuschauen, welche AUSgabe zur aktuellen EINgabe passt. Besser wäre es IMHO, wenn man auf Basis der EINgabe die AUSgabe _allgemein_ berechnet. Natürlich muss dieser Berechnung dann auch genügend Information zugrunde liegen (d.h. mehr als der Typ der kämpfenden Einheiten). Deswegen die Idee mit der Attack- (und ggf. Defense-) Klasse. Wenn die Information, dass einer der Kämpfer einen Speer hat, und der andere ein Pferd, nicht nur im Typ codiert ist, sondern implizit in der Angriffsklasse, dann kann die Information in jeder beliebigen Konstellation verwendet werden. 

In diesem Beispiel: WARUM macht ein Speer bei einem Pferd mehr schaden? Weil man ihn als Lanze verwenden kann, d.h. weil die Reichweite hoch und die erreichbare Höhe groß ist. Wenn man jetzt als Waffe einen Bambusstock einbauen will, dann sollte man eben NICHT eine Klasse "KriegerMitBambusstock" einführen müssen, und in der Berechnungsengine 200 Zeilen anpassen, um überall neue Fälle mit "instanceof KriegerMitBambusstock" einzubauen und damit diesen neuen Typ abzudecken. Stattdessen läßt man die Krieger-Klasse, die einen Bambusstock als Waffe hat (oder "damit dekoriert" ist) einfach ein Attack-Objekt erstellen, das AUCH eine hohe Reichweite und eine große erreichbare Höhe besitzt (aber vielleicht weniger Schaden macht, als ein Speer). Wenn man damit dann einen Reiter angreift, wird die Tatsache, dass man einen Bambusstock als Lanze verwenden kann, "automatisch" mit abgedeckt.

Man fügt also im Idealfall nur eine Klasse hinzu, die die "Attack" für einen Bambusstock erstellt. Die anderen Klassen (und insbesondere die Berechnungen, für die Fälle, dass der Gegner ein Pferd hat oder nicht) ändern sich nicht.


----------



## diggaa1984 (29. Jun 2008)

man könnte das ganze eventuell einfacher halten, wenn man den Kämpferklassen ihre Waffen quasi verbindlich festlegt, sodass ein Speerkämpfer eben nur Speere haben darf, n Schwertkämpfer nur Schwerter und n Buschmann eben nur n Knüppel ^^.

Dann könnte man in einer Matrix (auch gerne extern ausgelagert zum Leichten anpassen und automatisiertem Laden) die Angriffswerte standardmäßig für die Paarungen abbilden. In der Berechnungsengine würden dann die ganzen anderen Sachen dazugerechnet werden, wie von Marco bereits umfassend vorgeschlagen. 

Eventuell müsste man nicht unbedingt für jeden neuen Kämpfertyp die Matrix erweitern, wenn man geschickte Oberklassen wählt. 
Zum Bsp ist es dem Speerkämpfer egal ob der Reiter n Knüppel oder n Schwert oder n Bogen in der Hand hätte. Der Vorteil vom Speer bleibt in dem Fall der selbe, und könnte unter Umständen mit dem selben Basis-Angriffswert (bzw Angriffsfaktor je nachdem wie man das darstellt) in die Berechnung starten.

Finde die Vorstellung mit Faktoren zu arbeiten fast besser, als mit festen Angriffswerten, wenn man bedenkt das später neue stärkere Waffen oder dergleichen eigebaut werden. Der Faktor würde sich erstma mit dem Schaden der Waffe multiplizieren danach könnte man dann die anderen Sachen mit rein rechnen (Defense, Zaubereinflüsse etc.), welche dann dieses vorläufige Ergebnis wieder beinflussen.
So hätte ein Speerkämpfer gegen Reiter Faktor 2.0 und gegen nen Schwertkämpfer zu Fuss vielleicht 0.5 oder so.


----------



## diggaa1984 (29. Jun 2008)

EDIT: doppelpost, hatte grad gehangen beim abschicken


----------



## Gelöschtes Mitglied 5909 (29. Jun 2008)

wie wäre es wenn du den kriegern als attribut eine Waffe gibts,
und die Waffe hat eine reichweite, macht x schaden und so weiter.
Dann musst du nicht für jede neuen Krieger eine Extra Klasse machen und kannst einem krieger auch mehrere Waffen geben.

Das gleiche kannst du dann mit Rüstung usw machen und dann den schaden ggf abziehn.


----------



## Yzebär (29. Jun 2008)

Marco13 hat gesagt.:
			
		

> Grundsätzlich spricht nichts dagegen, die Berechnungen für die Kämpfe in eine eigene Klasse auszulagern. Dein Vorschlag war jetzt praktisch, alle möglichen Ergebnisse, die auftreten können, einfach "aufzuzählen", und dann einfach nachzuschauen, welche AUSgabe zur aktuellen EINgabe passt.



Nein, so war das nicht gemeint. Die Berechnungsmethode kann natürlich ein if-else-Konstrukt enthalten, aber ich würde die bereits angesprochene Berechnung aufgrund einer Matrix vorziehen (deren Aufbau man zB aus einer Datei einliest). Ziel ist schließlich immer, Erweiterungen mit so wenig Änderungen wie möglich zu ermöglichen. Mit dieser Matrix verrechnet man dann die allgemeinen Angriffs-/Verteidigungspunkte (die sich aus dem aktuellen Equipment errechnen, Collections/Attribute von Waffen, Rüstungsteilen) der beiden übergebenen Einheiten. Bei sauberer Programmierung kennt die Berechnungsmethode nur Interfaces oder abstrakte Klassen und keine konkreten Typen. 

Um es nochmal deutlicher auszudrücken. Mein Vorschlag richtet sich nach dem Paradigma, Daten und Berechnungslogik strikt zu trennen. Die Klassen für Krieger oder Magier oder sonstiges sind Datencontainer. Interaktionen (Handeln, Kämpfen, Quatschen ...) zwischen diesen, ist Logik, die in diesen Containern nichts zu suchen hat.


----------



## Gast2 (29. Jun 2008)

Moin, so viele Antworten :shock:

aber alle lösen nicht das Hauptproblem "Wie erkläre ich jetzt Klasse A das es mir einen anderen Wert liefern muss, weil Klasse B mitspielt, ohne das ich Klasse A mitteile das Klasse b mitspielt" :roll: 

macht aber nix ... denn der Vorschlag mit dem Decorator brachte mich der Lösung etwas näher ... es werden jeweils Decorator-Klassen der einzelnen Items erstellt und es existiert nur noch ein Krieger (der eben dekoriert wird mit Schild, Waffe etc.) ... dadurch lässt sich alles ohne Probleme mit weiteren Items erweitern ... das Problem mit den Ausnahmen (Reiter & Speerkämpfer, Frikadelle & Steak, etc.) löse ich dann in der Methode wo sich die beiden Krieger die Köpfe einschlagen mittels if

damit habe ich nur zwei Stellen wo ich was ändern muss ... bei der Kriegeraufstellung (Decorator) und im Kampf (if)



danke Euch, mogel



PS: jetzt habe ich endlich Dekorator-Pattern kapiert (Umsetzung) und nicht nur das Prinzip verstanden (Theorie)


----------



## diggaa1984 (29. Jun 2008)

mogel hat gesagt.:
			
		

> aber alle lösen nicht das Hauptproblem "Wie erkläre ich jetzt Klasse A das es mir einen anderen Wert liefern muss, weil Klasse B mitspielt, ohne das ich Klasse A mitteile das Klasse b mitspielt" :roll:



das soll ja die berechnungsengine machen, die sich auf ne standardwertematrix bezieht und danach die ganzen zusatzfaktoren dazurechnet. die enginge würde dann die 2 kämpferklassen bekommen und könnte damit theoretisch alles errechnen. somit brauch keine klasse wissen, welche andern kämpferklassen überhaupt existieren.

Somit hältst das "gib mir andern Angriffswert"-zeugs aus den kämpferklassen raus, was ich auch sinnvoll finde.


----------



## Marco13 (29. Jun 2008)

Wie ich schon weiter oben geschrieben hatte: Was die verünftigste Modellierung ist, weiß nur derjenige, der weiß, was da am Ende rauskommen soll. 

@Yzebär: 
Vielleicht meinst du das gleiche, aber die Formulierung
_// berechnet hier den wirksamen Attack-/Defend-Wert
         // (abhängig davon welche Arten von Kämpfern gegeneinander antreten) 
_
klang, als müßte man immer die _Klassen_ erstellen - und nur die Interaktion dieser Klassen würde sich auf die Werte aus der Datei stützen. Insbesondere
_Wenn neue Einheiten hinzukommen, muß nur immer wieder die Berechnungsengine erweitert werden_
klingt ja nicht gerade leicht erweiterbar, sondern als müßte, wie angedeutet, für jede neue Waffe die Matrix für ALLE neuen Kombinationen erweitert werden :? 

Aber davon ausgehend, dass du prinzipiell das gleiche meintest: Natürlich könnten - um da die Brücke zu schlagen - auch bei meinem Vorschlag alle möglichen Waffen aus einer XML-Datei gelesen werden, wo dann drinsteht, was für Attack-Objekte sie erstellen - und NUR diese Informationen werden dann - ganz generisch - von der "Berechnungsengine" verwendet, die aber bei neuen Waffen NICHT erweitert werden muss, sondern schlicht und einfach andere Ergebnisse berechnet....

@mogel: Bevor du dich jetzt auf's Decorator-Pattern stürzt, solltest du *GENAU* überlegen, ob das für deinen Fall angebracht ist. Ich hatte es nur erwähnt, weil es "klassisch" zur Vermeidung der beschriebenen, überspezialisierten Unterklassen verwendet wird. Für deinen Fall könnte aber eine "Inventar"-Klasse *und/oder* oder eine abstrakte Waffen-Klasse (von der jeder Krieger zwei Stück tragen kann) u.U. noch *deutlich* besser geeignet sein!!!

_aber alle lösen nicht das Hauptproblem "Wie erkläre ich jetzt Klasse A das es mir einen anderen Wert liefern muss, weil Klasse B mitspielt, ohne das ich Klasse A mitteile das Klasse b mitspielt"  _

Doch, das lösen sie (oder ich habe schon bei der ursprünglichen Frage was komplet falsch verstanden). Es kommt nur auf die Formulierung und Modellierung an. Also zur Klärung: Unrsprünglich hattest du ja sowas in den Raum gestellt:

```
abstract class Krieger
{ 
    abstract int attackValue(Krieger other); 
}

class KriegerMitPferd
{
    public int attackValue(Krieger other) { .... }
}

class KriegerMitSpeer
{
    public int attackValue(Krieger other)
    {
        if (other instanceof KriegerMitPferd) return highAttackValue;
        else return lowAttackValue;
    }
}
```
Das ist stilitsisch nicht so toll, schlecht erweiterbar usw.... Wenn es jetzt eine Klasse "KriegerMitEinhorn" gibt, dann muss diese Klasse erstellt werden, und an ALLEN Stellen, wo bisher "instanceof KriegerMitPferd" abgefragt wurde, zusätzlich noch "instanceof KriegerMitEinhorn" eingefügt werden.


Die Alternative wäre jetzt (zur Vereinfachung, und als Versuch, die Vorschläge von Yzebär und mir zu vermischen):

```
abstract class Krieger
{ 
    abstract int attackDamage();
    abstract boolean hatLanze(); // NUR zur Vereinfachung und Verdeutlichung!!!
    abstract boolean hatPferd();
}

class KriegerMitPferd // NUR zur Vereinfachung und Verdeutlichung!!!
{
    public int attackValue(Krieger other) { .... }
    public boolean hatLanze() { return false; }
    public boolean hatPferd() { return true; }
}

class KriegerMitSpeer
{
    public int attackDamage() { return 10; }
    public boolean hatLanze() { return true; }
    public boolean hatPferd() { return false; }
}

    void kämpftKämpftKämpft(Krieger a, Krieger b)
    {
         int attackValue = a.attackDamage();
         if (a.hatLanze() && b.hatPferd()) attackValue += 5;  // NUR zur Vereinfachung und Verdeutlichung!!!
         ....
    }
```

Wenn man DORT eine Klasse "KriegerMitEinhorn" einfügen will, dann erstellt man diese Klasse, und gibt auch bei ihr in der Methode "hatPferd" den Wert "true" zurück. Es muss dann am bestehenden Code NICHTS geändert werden. Es wird einfach nur eine neue Klasse hinzugefügt - dasselbe für KriegerMitGreif, KriegerMitPony .... usw.


WICHTIG: Das letzte Beispiel sollte nur dam Zweck diesen, deutlich zu machen, wie man die Unterscheidung, die du auf Basis des Typs treffen wolltest, allgemeiner auf Basis von Eigenschaften treffen könnte. Die _konkrete_ Modellierung ist aber immernoch ungeschickt, wegen der vielen, speziellen Unterklassen, und den vielen "hat..."-Methoden. Die Alternativen wurden schon angedeutet....

```
class Krieger 
{
    Waffe getWaffe();
    boolean besitzt(Item inventarItem);
}

Krieger kriegerMitSpeer = new Krieger("DateiMitInformationÜberSpeer.txt");
Krieger kriegerMitPferd = new Krieger("DateiMitInformationÜberPferd.txt");

class Kampf
{
    void kämpftKämpftKämpft(Krieger a, Krieger b)
    {
         Waffe waffe = a.getWaffe();
         int attackValue = waffe.getAttackValue();
         if (waffe.kannAlsLanzeVerwendetWerden() && b.besitzt(einPferd)) attackValue += 5;
         ....
    }
```
(immer nur ganz grob, um Ideen zu verdeutlichen - das auzuarbeiten ist ja _eigentlich_ dein Job :wink: )


----------



## Gast2 (29. Jun 2008)

Moin,



			
				Marco13 hat gesagt.:
			
		

> @mogel: Bevor du dich jetzt auf's Decorator-Pattern stürzt, solltest du *GENAU* überlegen, ob das für deinen Fall angebracht ist.



es ist super geeignet ... ich nehme einen Krieger ... der hat nichts (außer Kleidung) ... dann drücke ich ihm eine Waffe in die Hand (1.Dekorierer) ... dadurch erhöhen sich alle Wert (er hat ja nun endlich eine Waffe) ... dann drücke ich ihm ein Schild in die Hand (2. Dekorierer) ... dadurch ändern sich die Werte (Angriff runter [unhandlich] - Verteidigung hoch [praktisch]) ... und so weiter (wenn ich den Krieger gedanklich dekoriere bin immer irgendwie im Kaufhaus ???:L )


```
public abstract class Krieger
{
	abstract public Unit getUnit();
	
	abstract public int AttackValue();
	abstract public int DamageValue();
	abstract public int DefenceValue();
	
	abstract public boolean hatWaffe(Class waffe);
}
```

dazu kommen die jeweiligen Dekorierer ... z.b. Schwert


```
public class Schwert extends KriegerDekorierer
{
	public Schwert(Krieger krieger) { super(krieger); }
	
	/** Angriffsstärke ist TW */
	public int AttackValue()
	{
		int tw = getUnit().Talentwert(Hiebwaffen.class);
		return super.AttackValue() + tw; 
	}
	
	/** Schaden 2 bis 6 */
	public int DamageValue() { return super.DamageValue() + Atlantis.rnd(2, 6);  }
	
	/** Verteidigungsstärke ist TW */
	public int DefenceValue()
	{
		int tw = getUnit().Talentwert(Hiebwaffen.class);
		return super.DefenceValue() + tw;
	}

	public boolean hatWaffe(Class waffe)
	{
		if (waffe.equals(this.getClass())) return true;
		return super.hatWaffe(waffe);
	}
}
```

damit werden pro Dekorierer die entsprechenden Werte geändert ... funktioniert super

die Ausnahmen mache ich dann wie folgt (ungefähr, ist jetzt kurz aus dem Kopf, da nicht fertig)


```
public static void _1on1_(Krieger angreifer, Krieger verteidiger)
{
	// ....

	int damage = angreifer.DamageValue();
	if (angreifer.hatWaffe(Pferd.class) && verteidiger.hatWaffe(Speer.class)) damage *= 0.5;

	// ...
}
```

damit habe ich alles was wichtig ist schön gebündelt und ist leicht wartbar ... so wie ich es mag



> (immer nur ganz grob, um Ideen zu verdeutlichen - das auzuarbeiten ist ja _eigentlich_ dein Job :wink: )


ick will den Job gar nicht abgeben 



hand, mogel


----------



## Marco13 (29. Jun 2008)

Hmja, aber wenn für jedes Item (wie viele es da auch immer geben mag) ein Decorator dazukommt, wäre das auch ungünstig. Für Waffen und Schilde wäre es IMHO noch OK und auch sinnvoll, aber spätestens, wenn der Krieger dann (um ein übertriebenes Beispiel zu nennen) 20 Goldmünzen besitzt, und dafür 20 Dekorierer hintereinandergeschaltet werden, ist das auch sinnlos. Für sowas wie Zaubertränke oder anderen "Kram, den man im Rucksack hat" wäre eine Inventar-Klasse sicher besser geeignet.


----------



## SebiB90 (29. Jun 2008)

Marco13 hat gesagt.:
			
		

> "Kram, den man im Rucksack hat" wäre eine Inventar-Klasse sicher besser geeignet.


wie wärs mit nem RucksackDekorierer. Dort gibt es dann ne Methode addItem() mit dem man die hinzufügen kannst und es lassen sich dann auch einfach items wieder entfernen.


----------



## Gast2 (29. Jun 2008)

Moin,

mehr als Waffen und Schilde wird da nicht dazu kommen ... Goldmünzen haben kein Anteil beim Kämpfen (irgendwie eigentlich schon, aber....) ... daher wird die Anzahl überschaubar bleiben

um Dir etwas Hintergrund zu geben ... eine Einheit besteht aus mehreren Personen ... theoretisch unendlich viele wird aber als int gespeichert ... diese Einehit hat alle Items, Schwerten, Schilder, Silber, Holz, Frikadellen und so weiter

vor einem Kampf wird eben diese Einheit nach Anzahl der Personen in Krieger "zerlegt" ... und diese Krieger werden, je nachdem was die Einheit an Gegenstände bzw. Waffen hat, Dekoriert ... nach dem Kampf werden die "überlebenden" wieder zur Einheit zusammen gesetzt

hand, mogel


----------



## Marco13 (29. Jun 2008)

SebiB90 hat gesagt.:
			
		

> Marco13 hat gesagt.:
> 
> 
> 
> ...



Hm :? naja, das würde ja das Problem nicht lösen, dass man für 100 Items dann 100 Dekorierer hintereinanderschaltet. Und das "Wegnehmen" eines Items wäre auch nicht so leicht - man müßte ja diese Kette von Dekorierern irgendwo aufbrechen, und einen Teil neu erstellen - das ist mit Sicherheit NICHT die Intention des Dekorierer-Patterns..... Für eine Menge von Objekten gibt's Collections - im speziellen, Sets (oder ggf. Listen).


----------



## SebiB90 (29. Jun 2008)

Marco13 hat gesagt.:
			
		

> SebiB90 hat gesagt.:
> 
> 
> 
> ...


du verstehst mich falsch..
es gibt für ALLE Items nur EIN RucksackDekorierer in dem alle Items drin sind.
Sie werden in einer Liste gespeichert, die halt durchlaufen wird beim aufruf der Methoden.
Und das entfernen ist über eine remove Methode dann auch ganz leicht, da es ja ne Liste ist(z.b. ArrayList)


----------



## Marco13 (30. Jun 2008)

Vielleicht hatte ich das mit dem Rucksack falsch verstanden. Ich meinte nicht, dass der Rucksack irgendwas ist, womit der Krieger erst dekoriert wird, und wo man dann Items reintun kann (was du jetzt anscheinend meintest), sondern dass jeder Krieger automatisch einen Rucksack hat, der einfach als Inventarliste dient... aber das sind jetzt vielleicht Details, über die der Schreiber des Spiels sich Gedanken machen sollte.


----------

