Laden...

Klassenstruktur und Interaktion für eine Finanz Verwaltung

Erstellt von jdem vor 16 Jahren Letzter Beitrag vor 16 Jahren 3.886 Views
J
jdem Themenstarter:in
42 Beiträge seit 2007
vor 16 Jahren
Klassenstruktur und Interaktion für eine Finanz Verwaltung

Hallo,

ich schreibe grade (bzw. plane und durchdenke) eine kleine Finanzverwaltung. Im wesentlichen geht es um das "Tracken" von Ein- und Ausgängen auf verschiedenen Konten. Ich bin nun beim grundsätzlichen Design auf ein Problem gestoßen und mir fehlt die Idee dieses Elegant zu lösen. Folgendes habe ich mir gedacht:

Ich habe ein Portfolio welches mehrere (beliebig viele) Konten enthält. Jedes Konto hat einen Anfangbetrag. Zu jedem Konto gehört eine Liste von Transaktionen wobei eine Transaktion eine Ausgabe, Einnahme oder ein Transfer zwischen zwei Konten ist.

Um den aktuellen Betrag eines Kontos zu berechnen wollte ich durch die Liste der Transaktionen iterieren und jede Transaktion auf den Betrag, der sich durch Anwendung der vorherigen Transaktionen ergeben hat, anweden. Hier etwas PSeudocode zum verdeutlichen.

class Portfolio
{
	List<Konto> konten;
}

class Konto
{
	int anfangsSaldo;
	List<Transaktion> transaktionen;

	void FügeTransaktionHinzu(Transaktion trans)
	{
		transaktionen.add(trans);
	}

	int BerechneSaldo()
	{
		int saldo = anfangsSaldo;
		für jede Transaktion trans in transaktionen
			saldo = trans.FühreTransaktionAus(saldo);
	}
}

class Transaktion
{
	public int FühreTransaktionAus(int betrag)
}

class Ausgabe : public Transaktion
{
}

class Einnahme : public Transaktion
{
}

class Transfer : public Transaktion
{
}

Dies sollte für "Einnahme" und "Ausgabe" auch wunderbar funktionieren. Was mir kopfschmerzen bereitet ist der "Transfer". Dieser bezieht sich ja immer auf zwei Konten. D.h. der "Transfer" ist im grunde eine zusammengesetzte Transaktion (Einnahme/Ausgabe) und ich könnte sie auch so behandeln, verliere aber damit die Information das es sich um einen "Transfer" und nicht um eine einfache "Ausgabe" repektive "Einnahme" handelt. Und genau diese Unterscheidung brauche ich später in der Darstellung der Ergebnisse.

Ich würde in meinem Code also gerne folgendes schreiben können:


konto1.FügeTransaktionHinzu(transfer1);
konto2.FügeTransaktionHinzu(transfer1);

womit ich einen transfer eines bestimmten betrags von konto1 auf konto2 erreichen will.

Hat jemand da eine Idee?

Grüße
Bastian

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo jdem,

ich sehe das Problem nicht ganz. Ein Transfer sind ja zwei Buchungen, die zusammengehören. Du könntest also zwei Transaktions-Klassen machen TransferOut und TransferIn, die wechselseitig verknüpft sind. Bei dem einen Konto fügst du als Transaktion ein TransferOut und bei dem anderen ein TransferIn hinzu. Dann weiß FühreTransaktionAus genau, was zu tun ist und kann je nach Klasse (TransferOut oder TransferIn) den Saldo erhöhen oder vermindern.

herbivore

J
jdem Themenstarter:in
42 Beiträge seit 2007
vor 16 Jahren

Hallo herbivore,

danke für die Antwort. Die Idee mit zwei Transfer Klassen finde ich schon nicht schlecht. Das Löst mein ursprüngliches Problem erzeugt aber ein neues. Nehmen wir an ich wähle eine Transaktion eines Kontos aus und möchte diese löschen. Dann würde ich feststelle das ich einen Transfer (entweder in oder out) erwischt habe und müsste das gegenstück nun auch löschen. Um das gegenstück auch zu löschen müsste ich durch alle Konten iterieren und den passenden Transfer suchen. Das ist zwar möglich aber unschön wie ich finde.

Hast du dazu auch noch eine Idee oder seh ich den Wald vor lauter Bäumen wieder nicht?

Grüße
Bastian

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo jdem,

da Transaktion und Konto m.E. eh eng gekoppelte Klassen sind, spräche m.E. nichts dagegen, wenn eine Transaktion weiß, auf welches Konto sie sich bezieht. Es gibt sicher noch zwei weitere Möglichkeiten, das Problem auch ohne diese Koppelung zu lösen: Interfaces (z.B. ITransactionOwner) und Events (z.B. IAmDeleted). Ok, über die Namen kann man sich streiten.

herbivore

J
jdem Themenstarter:in
42 Beiträge seit 2007
vor 16 Jahren

Hallo herbivore,

vielen dank für deine Antworten!

Irgendwie widerstrebt mir die Kopplung...und Interfaces und Events würden in ein eigentlich sehr einfaches System (unnötige?) komplexität bringen.

Vielleicht muss ich meinen grundsätzlichen Aufbau nochmal überdenken, falls dazu jemand Ideen hat: immer her damit.

Ansonsten werde ich den Weg der gegenseitigen Referenzen gehen müssen.

Grüße
Basti

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo jdem,

wenn du die Koppelung nicht willst, dann nimm ein Interface oder Events. Das Interfaces sind über den Daumen 2 zusätzliche Codezeilen. Da würde ich nicht gerade davon reden, dass es ein einfaches System kompliziert macht. Der Event sind ca. 8-10 zusätzliche Zeilen, also auch nicht wirklich die Welt.

Zeilen, auf denen nur Klammern stehen, natürlich jeweils nicht mitgerechnet.

herbivore

J
jdem Themenstarter:in
42 Beiträge seit 2007
vor 16 Jahren

Mh, könntest du kurz in drei Zeilen erklären wie du dir die Lösung mit Interfaces vorstellst? Ich seh die zwei Zeilen momentan noch nicht 😉

Danke nochmal!

Grüße
Basti

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo jdem,


interface ITransactionOwner
{
   void Remove (Transaction ta); 
}

Natürlich brauchst du ansonsten alles, was du auch bräuchtest, wenn du die Lösung mit der direkten Koppelung verwenden würdest. Deshalb ja nur zwei zusätzliche Zeilen für das Interface.

herbivore

J
jdem Themenstarter:in
42 Beiträge seit 2007
vor 16 Jahren

Ok, ich füge dann jeder Transaction seinen Owner zu und speichere gleichzeitig bei einem Transfer jeweils eine Referenz auf das Gegenüber. Wenn ich den Transfer löschen will lösche ich mittels des Interfaces den einen und über die gespeicherte Referenz das gegenüber.

Ich glaube damit kann ich mich anfreunden 😉

Vielen dank und freundliche Grüße
Bastian

309 Beiträge seit 2007
vor 16 Jahren

Aber jedesmal ALLE Transaktionen durchgehen ??? Irgendwann wird das doch langsam. Sichere doch ein Monatssaldo, dann brauchst du nur einen Monat durchzugehen.

Mfg Hajoseb

**"Zufall ist das Pseudonym Gottes, wenn er nicht selbst unterschreiben will.” **
Anatole France

R
494 Beiträge seit 2006
vor 16 Jahren

Ja, bei mehreren Millionen Transaktionen könnte man tatsächlich Performance einbußen feststellen 😁

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo Hajoseb,

ob man alle Transaktionen durchgehen muss, hängt ja nur davon ab, wie intelligent man diese speichert. Möglichkeiten wären SortedList und Dictionary. Davon würde ich jedenfalls keine Entscheidung struktureller Art abhängig machen.

herbivore

309 Beiträge seit 2007
vor 16 Jahren

Tja. Ich bin halt noch ein Computer-Dino ...

Damals hat man sich halt noch gedanken über Speicher und Optimierung gemacht 8)

**"Zufall ist das Pseudonym Gottes, wenn er nicht selbst unterschreiben will.” **
Anatole France

49.485 Beiträge seit 2005
vor 16 Jahren

Hallo Hajoseb,

das habe ich auch. 🙂 Meine Vorschläge sind ja Optimierungsmöglichkeiten.

Davon abgesehen ist es nicht sinnvoll, Optimierungen vorzunehmen, die nicht mehr zeitgemäß sind. 🙂 Nicht, dass du eines Tages eben fehlender Anpassung noch ausstirbst. 🙂

herbivore

309 Beiträge seit 2007
vor 16 Jahren

Na, Ja. Ich bin ja eben erst aus meiner Höhle wieder raus gekrochen um quasi neu anzufangen 8)

In der zwischenzeit gibt es halt Objektorientieres Programmieren und C# ... Beim Umstieg von TurboPascal auf Delphi 2 habe ich mich aus Zeit- und familiären Gründen zurück gezogen.

Die neuen Technologien muss ich erst mal nachholen ... und um es richtig zu machen bin ich nach kurzem Anfang bei Delphi2005 eben auf C# umgestiegen, um auch .net 2.0 nutzen zu können (ich BRAUCHE die screen-copy-Funktionen).

Jetzt fühle ich mich ungefähr wie Scotty in TNG als er nach 70 Jahren aus dem Transporter-Musterpuffer befreit wurde und den Maschienenraum der neuen Enterprise sah 😁

Die Grundlagen sind ähnlich aber es ist doch alles neu g

Mfg Hajoseb

**"Zufall ist das Pseudonym Gottes, wenn er nicht selbst unterschreiben will.” **
Anatole France