Klassen für Objekt richtig erstellen

Fohnbit

Top Contributor
Hallo!

Ich habe eine Stromzählerabfrage über ModbusRTU programmiert.
Nun möchte ich meinen Code "richtig" in Klassen und Objekten aufteilen.

Es gibt 2 Zähler:
3-Phasig
1-Phasig

Jeder dieser Zähler hat unterschiedliche Baudsettings sowie Modbus Einstellungen. Die Ausgaben (Watt, Volt, ...) soll aber für beide gleich sein.
Die Zähler geben folgende Daten zurück:
Voltage
Current
Power
Volt Amps
Power Factor
Frequency of Voltage
Import Power
Export Power

Ich habe bis dato das so einmal gelöst wie im Bild.

Jedoch in wie weit soll man die Objekte einzeln abbilden?
Ein Stromzähler hat:
1 oder 3 Phasen
Er hat 1 Adresse
Er hat serielle Einstellungen
Er hat 1 oder mehr Input Register Adressen

Association oder Aggregation ist mir auch noch nicht ganz klar.
 

Anhänge

  • Bildschirmfoto vom 2014-12-27 13:43:40.png
    Bildschirmfoto vom 2014-12-27 13:43:40.png
    75,9 KB · Aufrufe: 30
Hi,

Ich würde nur eine Klasse "SmartMeter" erstellen, in der alle Eigenschaften drin sind, inklusive der Phasen als Collection oder Array[3]. Der Einphasige gibt halt für .getPhase(0) seine Phase zurück, und null für 1 und 2 -

zB könnte die Klasse eine Methode haben "setupAsOnePhase()" der die Phasen befüllt -

phases[0] = new Phase(<values>)
phases[1] = null
phases[2] = null

Man könnte dann noch einen SmartMeter1Phase als Klasse ableiten, und aus Conveniencegründen sowas wir "getPhase()" implementieren, aber eigentlich ist das Blödsinn - du müsstest in der Folge ja immer erstmal checken "instanceof Smartmeter1Phase" oder so.

Diese Vorgehensweise hat imo den Vorteil, dass du jeden SmartMeter gleich behandeln kannst im Code, und einfach über die Phasen iterieren kannst.
 
Also es gibt kein "richtiges" Modellieren. Aber für deinen Fall ist das eindeutig wie du es angehen solltest.

Wenn du gemeinsame Eigenschaften hast, die beide Stromzähler Teilen, dann bietet sich eine abstrakte Oberklasse an.

@senior.weber: Das ist nicht der richtige Ansatz! Wenn es ums Iterieren geht, dann kann man einfach eine Schnittstelle bieten mit Anzahl der Phasen und eine getter-Funktion, dann braucht man nicht mit null-Values zu arbeiten:

Bsp:
Java:
for(int i = 0; i < powerMeter.getPhaseCount(); i++) {
  powerMeter.getPhase(i);
}

Das ist wesentlich sauberer und die Zähler unterscheiden sich wirklich nur in dieser "Kleinigkeit".
 
Das ist wesentlich sauberer und die Zähler unterscheiden sich wirklich nur in dieser "Kleinigkeit".

ähm - warum soll er dann eine abstrakte Oberklasse bilden, wenn der einzige Unterschied der Unterklassen die Anzahle der Phasen ist?

@senior.weber: Das ist nicht der richtige Ansatz!

Es gibt 2 Fälle: 1 Phase und 3 Phasen - d.h. dein getPhaseCount() kann nur 1 oder 3 zurückgeben. Also auch irgendwie nicht der richtige Ansatz denke ich.

Ok null Werte abtesten ist auch nicht immer elegant, ich mache viel Groovy deshalb ist es üblich ein null (== groovy false) zurückzugeben - dann kann man mit
Code:
phases.get(1)?.getVolt()
oder so arbeiten.

Evt wäre es sinnvoll, so vorzugehen:

Code:
for( Phase p : meter.getPhases()){
   <p kennt seine Position (RST/123)>
}
 
Zuletzt bearbeitet:
Hallo,

ich bin recht neu und habe mir dazu auch Gedanken gemacht. Mich stört, dass beim Lösungsansatz mit dem Array ordentlich Abhängigkeiten in der Klasse gesetzt werden. Meine Lösung ist sicher aber wieder viel zu kompliziert.

Wie wäre es, mit einer Sammlung für die Phasen als eigener Datentyp, welcher n der Lage ist, die Anzahl der Phasen, sowie eine Liste dieser zurückzugeben?

[Java]
package de.counter;

import java.util.ArrayList;

public class Phases {

private int phaseCount = 0;

private ArrayList<PhaseInterface> phases = new ArrayList<PhaseInterface>();

public void addPhase(final PhaseInterface phase) {
phases.add(phase);
phaseCount++;
}

public ArrayList<PhaseInterface> getPhases() {
return phases;
}

public int getPhaseCount() {
return phaseCount;
}
}
[/code]

Die hinzufügbaren Phasen könnten auch ein Interface implementieren, welches die Funktionen zum Aufrufen der einzelnen Felder
sicher stellt und wiedrum Abstraktion ermöglicht.

Java:
package de.counter;

public interface PhaseInterface {
	public double getVoltage();
}

Und dann die konkrete Implementation:

Java:
package de.counter;

public class Phase implements PhaseInterface {
	
	private double voltage;

	public Phase(double voltage) {
		this.voltage = voltage;
	}
	@Override
	public double getVoltage() {
		return voltage;
	}


}

Im Smartmeter würde ich dann einfach auf den Phasentyp delegieren um die Phasenliste zurück zu geben.
Zusätzlich würde ich, um die Art des Zählers schnell bestimmen und vergleichen zu können mit statischen Knstanten und einer internen Konstanten arbeiten.

Java:
package de.counter;

import java.util.ArrayList;

public class SmartMeter {
	public static final int SMETER1PHASE = 0;
	public static final int SMETER3PHASE = 1;
	private final int smType;

	private Phases phases;

	public SmartMeter(Phases phases) {
		this.phases = phases;

		if (phases.getPhaseCount() > 1) {
			this.smType = SmartMeter.SMETER3PHASE;
		} else {
			this.smType = SmartMeter.SMETER1PHASE;
		}
	}

	public ArrayList<PhaseInterface> getPhases() {
		return phases.getPhases();
	}

	public boolean is3Phase() {
		return smType == SmartMeter.SMETER3PHASE;
	}
	// und so weiter

}

Wenn ich das richtig sehe sind doch damit die Koplungen recht gering, da sie nirgends innerhalb der Klassen fast codiert sind.
SmartMeter erwartet lediglich ein Phases Objekt im Constructor und Phases in einer Methode einen InterfaceTyp Phase.

Ist die Herangehensweise so annehmbear, oder totaler Käse / Zu kompliziert / falsch gedacht / besser machbar (Letzteres isses ja immer).

PS: Darf man sowas hier im Forum? Also einen Lösungsvorschlag mit einer eigenen Frage kombinieren, oder ist das nicht so gerne gesehen?
 
Also das ist eine klare Vererbungshierarchie. Das analoge Beispiel dazu wäre: Fahrzeug -> LKW -> PKW

Ist nämlich das gleiche!

Aber wenn man nicht weiß in welchem Kontext dann diese Klassen verwendet werden, dann kann man nur spekulieren.
 
Hallo consider,

das ist imo im Ansatz OK - nur das PhaseInterface ist Käse-> es gibt ja nur eine konkrete Implementation - verstanden?

Für smType würde ich eine Enum Konstante oder einen String als Konstante nehmen, den kann man auch gleich so human-readable ausgeben im Zweifelsfall.

@Flown

Also das ist eine klare Vererbungshierarchie. Das analoge Beispiel dazu wäre: Fahrzeug -> LKW -> PKW
Ist nämlich das gleiche!

Das verstehe ich nicht in diesem Kontext - Wozu braucht man hier eine Vererbungshierarchie, wenn

1. die Kinderklassen *alle* Eigenschaften der Elterklasse hat und gleich implementiert
2. die Kinder sich nur in einem Merkmal unterscheiden

Um es für andere verständlich zu schreiben: ich denke du meinst

Code:
Fahrzeug -> LKW 
        |-> PKW
?
 
Zuletzt bearbeitet:
Entschuldige ich hätte das mit der Hierarchie besser hinschreiben sollen, danke für die Verbesserung.

1. die Kinderklassen *alle* Eigenschaften der Elterklasse hat und gleich implementiert
2. die Kinder sich nur in einem Merkmal unterscheiden

Gegenfrage was unterscheidet PKW von LKW? Trotzdem sind das zwei verschiedene Dinge, die eine eigene Klasse erfordern und im Normalfall getrennt behandelt werden würden. Das ist das gleich wie mit Stromzählern IMHO.

Aber egal, wie man es auch wendet und dreht, dass ist jetzt eine philosophische Frage, wie man das implementieren würde. Das ist eine Frage des Stils und, wie ich vorher erwähnt habe, eine Frage des Kontext, wie man die Klassen weiterverwenden wird.
 

Neue Themen


Zurück
Oben