Code-Strukturierung, macht Vererbung hier Sinn?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Qubit
User
Beiträge: 130
Registriert: Dienstag 7. Oktober 2008, 09:07

Man könnte für die Motoren auch eine Art Factory-Pattern und zur Berechnung eine Art Interface (~Protocol) verwenden..

Code: Alles auswählen

from typing import Protocol

class Zylinder:
    def __init__(self,hoehe,breite,tiefe):
        self.hoehe  = hoehe
        self.breite = breite
        self.tiefe  = tiefe

class Motor:
    def __init__(self,leistung,gas):
        self.leistung = leistung
        self.gas      = gas

class OttoMotor(Motor):
    def __init__(self,leistung):
        Motor.__init__(self,leistung,'Benzin')

class DieselMotor(Motor):
    def __init__(self,leistung):
        Motor.__init__(self,leistung,'Diesel')

class MotorFactory:
    def __new__(self,motor,zylinder,anzahl_zylinder):
        self.motor    = motor
        self.motor.zylinder = zylinder
        self.motor.anzahl_zylinder = anzahl_zylinder
        return motor

class MotorBerechnung(Protocol):
    def beschleunigung_auf_100(self): pass

class OttoMotorBerechnung(MotorBerechnung):
    otto_faktor = 0.0000321

    def beschleunigung_auf_100(self):
        volumen_zylinder=self.motor.zylinder.hoehe*self.motor.zylinder.breite*self.motor.zylinder.tiefe
        return volumen_zylinder*self.motor.anzahl_zylinder*self.motor.leistung*self.otto_faktor

class DieselMotorBerechnung(MotorBerechnung):
    diesel_faktor = 0.0000432

    def beschleunigung_auf_100(self):
        volumen_zylinder=self.motor.zylinder.hoehe*self.motor.zylinder.breite*self.motor.zylinder.tiefe
        return volumen_zylinder*self.motor.anzahl_zylinder*self.motor.leistung*self.diesel_faktor

class OttoMotorZylinder(OttoMotor,OttoMotorBerechnung):
    def __init__(self,otto_motor):
        self.motor = otto_motor

    def __str__(self):
        return f"Otto Motor {self.motor.anzahl_zylinder} Zylinder"

class DieselMotorZylinder(DieselMotor,DieselMotorBerechnung):
    def __init__(self,diesel_motor):
        self.motor = diesel_motor

    def __str__(self):
        return f"Diesel Motor {self.motor.anzahl_zylinder} Zylinder"


if __name__ == "__main__":
    zylinder = Zylinder(10,10,10)

    otto_motor_3_zylinder = OttoMotorZylinder(MotorFactory(OttoMotor(100),zylinder,3))
    print(f"{otto_motor_3_zylinder} [Treibstoff: {otto_motor_3_zylinder.motor.gas}]  mit {otto_motor_3_zylinder.motor.leistung}PS von 0 auf 100: {otto_motor_3_zylinder.beschleunigung_auf_100():.2f}s")

    diesel_motor_3_zylinder = DieselMotorZylinder(MotorFactory(DieselMotor(100),zylinder,3))
    print(f"{diesel_motor_3_zylinder} [Treibstoff: {diesel_motor_3_zylinder.motor.gas}] mit {diesel_motor_3_zylinder.motor.leistung}PS von 0 auf 100: {diesel_motor_3_zylinder.beschleunigung_auf_100():.2f}s")
Otto Motor 3 Zylinder [Treibstoff: Benzin] mit 100PS von 0 auf 100: 9.63s
Diesel Motor 3 Zylinder [Treibstoff: Diesel] mit 100PS von 0 auf 100: 12.96s
Wie sinnvoll das hier ist, lässt wie immer in der OOP Freiraum für Diskussionen.. :)
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Aber das ist doch Python und nicht Java. 😱

Okay, ich hab's nicht ernst genommen, aber wenigstens gedacht es wäre nicht kaputt, aber das da wieder Zylinder von Motoren erben ist objektiv falsch.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Benutzeravatar
Dennis89
User
Beiträge: 1436
Registriert: Freitag 11. Dezember 2020, 15:13

Hallo,

@Qubit danke für deine Beteiligung, aber gerade weil man das so in Python nicht macht, fällt das schon mal raus.

Btw. Java sieht recht unübersichtlich aus. 🫣

Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
grubenfox
User
Beiträge: 548
Registriert: Freitag 2. Dezember 2022, 15:49

Dennis89 hat geschrieben: Dienstag 29. Oktober 2024, 07:27 Ich habe nun versucht, das ganze so zu schreiben, das ich es hier zeigen kann. Das heißt aber auch, dass die Rechnungen teilweise erfunden sind und *keinen* Sinn ergeben. Aber in der Funktion `get_norm_volume_flow` sieht man wie die Werte ineinander übergehen und was ich damit meinte, das ich für die Berechnung den Ein- und Auslass solange anpassen muss, bis sich ein Gleichgewicht einstellt.
Ich sehe da jetzt gerade nicht wie da Werte ineinander übergehen.... der erste Zylinder hängt am Einlass, der zweite am Auslass. Soweit so klar. Aber ansonsten scheinen die beiden Zylinder datentechnisch eher unabhängig von einander zu sein. Wie würde denn da ein dritter Zylinder mitspielen? Der hängt dann zwischen dem Zylinder am Einlass (der erste Zylinder) und dem anderen Zylinder am Auslass (der zweite Zylinder)? Und übernimmt dieser dritte Zylinder irgendwelche Daten vom ersten oder zweiten?
Benutzeravatar
Dennis89
User
Beiträge: 1436
Registriert: Freitag 11. Dezember 2020, 15:13

Guten Morgen,

hier geht es auch ab und an weiter.
@grubenfox Das ist immer in Reihe, der Auslass von einem ist immer der Einlass vom anderen. Wenn ich an Hand der ersten zwei Zylinder dein Volumenstrom berechne, der abhängig von anderen Faktoren ist, dann muss ich prüfen, ob dieser dann auch zwischen den 2. und den 3. "reinbekomme" oder ob und welche Faktoren ich ändern muss. So wird hier dann so lange iteriert, bis der Strom überall gleich ist. Dafür habe ich soweit mal eine erste funktionsfähige Funktion geschrieben.

Gerade kann ich wieder den grauen Haaren beim wachsen zu schauen, wenn ich über das Thema Datenbank-Design nachdenke.
Ich möchte die technischen Daten der Motoren aus einer Datenbank abfragen und da jeder Motor eine unterschiedliche Anzahl von Zylindern hat, habe ich mir das so überlegt.
Es gibt eine Tabelle Motor und eine Tabelle Cylinder. Jeder Zylinder bekommt ein Feld "motor_id" und damit kann ich beim laden der Daten dann alle passenden Zylinder zum Motor laden und in folgende Struktur stecken;

Code: Alles auswählen

@define
class Cylinder:
    piston_diameter = field()
    xyz_factor = field()
    abc_factor = field()



@define
class Motor:
    cylinders: list[Cylinder] = field()
    stroke = field()
    speed = field()
Würde man das so machen?

Ich will die Datenbank nicht manuell füllen, sondern will mir ein Skript dafür schreiben, falls sich mal Daten ändern.
Als Datenstruktur für uns Menschen, die bei Bedarf die Daten ändern, hätte ich spontan JSON gewählt, etwa so:

Code: Alles auswählen

{
    "name": "Machine A",
    "speed": 1250,
    "stroke": 0.070,
    "cylinders": [
        {
            "piston_diameter": 0.285,
            "xyz_factor": 0.0958,
            "abc_factor": 0.1255
        },
        {
            "piston_diameter": 0.14,
            "xyz_factor": 0.1189,
            "abc_factor": 0.1169
        }
    ]
}
Wie bekommen meine Zylinder jetzt die ID des passenden Motors mit? Oder soll ich anstelle der ID den Namen des Motors als Referenz wählen? Oder ein ganz anderes Datenbank-Desgin?


Danke und Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13684
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Eher nicht Namen, weil sich die mal ändern können. Und sei es nur weil man sich bei einem vertippt hat und den Fehler korrigieren möchte nachdem schon Zylinder zugeordnet waren. Dann müsste man den Namen ja nicht nur im Motor ändern, sondern in jedem Zylinder der zu diesem Motor gehört. Darum mögen Datenbankleute synthetische IDs so gerne, selbst wenn ein Datensatz einen “natürlichen“ Schlüssel hätte. Gegen Zeichenketten spricht dann auch noch der Speicherverbrauch und die Geschwindigkeit mit der Vergleiche gemacht werden vs. ganzen Zahlen als IDs.

Eine Frage beim DB-Entwurf ist, ob man für jeden Motor grundsätzlich immer neue Zylinder anlegt. Oder ob man den selben Zylinder in mehr als einem Motor verwenden können soll. Entsprechend mit der Folge, dass wenn man beispielsweise den Durchmesser ändert, der sich für alle betroffenen Motoren ändert.
„Incorrect documentation is often worse than no documentation.“ — Bertrand Meyer
Benutzeravatar
grubenfox
User
Beiträge: 548
Registriert: Freitag 2. Dezember 2022, 15:49

Dennis89 hat geschrieben: Donnerstag 28. November 2024, 06:58

Code: Alles auswählen

@define
class Cylinder:
    piston_diameter = field()
    xyz_factor = field()
    abc_factor = field()



@define
class Motor:
    cylinders: list[Cylinder] = field()
    stroke = field()
    speed = field()
Das scheint mir eine typische n:m-Beziehung zu sein. Ich gehe mal davon aus, dass ein Typ eines Zylinders in mehreren unterschiedlichen Motortypen genutzt wird. Bei klassischen relationalen Datenbanken braucht es da eine Hilfstabelle (Datenbankmodellierung

In Python-Code formuliert:

Code: Alles auswählen

@define
class Cylinder:
    id = field()
    piston_diameter = field()
    xyz_factor = field()
    abc_factor = field()


@define
class Motor:
    id = field()
    stroke = field()
    speed = field()


@define
class Hilfstabelle:
    motor_id = field()
    cylinder_id = field()
Ein passender Begriff als Name für die Hilfstabelle fällt mir jetzt nicht ein, da bin ich nicht im Thema drin.
Mir ist aber auch mal eine relationale Datenbank untergekommen in der ein Spaltentyp auch eine Liste sein kann. Wenn ich mich hier so umschaue, dann könnte es Firebird bzw. Interbase sein. Hatte ich aber nie produktiv im Einsatz. Dann kann man es einfach so machen (eigentlich wie ganz oben, habe nur die Id-Spalten hinzugefügt):

Code: Alles auswählen

@define
class Cylinder:
    id = field()
    piston_diameter = field()
    xyz_factor = field()
    abc_factor = field()



@define
class Motor:
    id = field()
    cylinders: list[Cylinder] = field()
    stroke = field()
    speed = field()
Nicht-relationale Datnebank lasse ich jetzt mal außen vor...
Benutzeravatar
Dennis89
User
Beiträge: 1436
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für eure Antworten, dann baue ich das so, mit der ID, auf.


Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
noisefloor
User
Beiträge: 3956
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Mir ist aber auch mal eine relationale Datenbank untergekommen in der ein Spaltentyp auch eine Liste sein kann.
Wenn die DB JSON als Feldtyp unterstützt, kann man die Python Liste als JSON Array in der DB speichern.

Gruß, noisefloor
Benutzeravatar
sparrow
User
Beiträge: 4394
Registriert: Freitag 17. April 2009, 10:28

Im Zweifelsfall immer PostgreSQL. Da gehen sowohl (Multidimensionale)Arrays als auch JSON als Feldtyp. Und die Felder in letzterem lassen sich sogar in SELECT-Statements ansprechen. Und Indexieren. Und Doom läuft auf Postgres.

PostgreSQL is my favorite OS 🤩
Antworten