199 lines
8.5 KiB
C#
199 lines
8.5 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Project_Periodensystem.Model;
|
|
|
|
namespace Project_Periodensystem.Controller
|
|
{
|
|
/// <summary>
|
|
/// ElementStatistics - Spezialisierte Klasse für statistische Berechnungen und Datenanalyse
|
|
///
|
|
/// Diese Klasse wurde aus dem Haupt-Controller ausgelagert, um das Single Responsibility
|
|
/// Principle zu befolgen. Sie konzentriert sich ausschließlich auf:
|
|
///
|
|
/// - Mathematische Berechnungen (Durchschnitte, Extreme)
|
|
/// - Datengruppierung und -analyse (Serien, Kategorien)
|
|
/// - Informationsextraktion (Tuple-basierte Abfragen)
|
|
/// - Performance-optimierte LINQ-Operationen
|
|
///
|
|
/// Vorteile der Auslagerung:
|
|
/// - Bessere Testbarkeit einzelner Berechnungen
|
|
/// - Wiederverwendbarkeit der Statistik-Funktionen
|
|
/// - Klare Trennung von UI-Logik und Datenverarbeitung
|
|
/// - Einfache Erweiterung um neue Statistiken
|
|
/// </summary>
|
|
public class ElementStatistics
|
|
{
|
|
/// <summary>
|
|
/// Private, schreibgeschützte Liste aller Elemente für statistische Berechnungen.
|
|
/// Wird im Konstruktor gesetzt und bleibt danach unveränderlich (readonly).
|
|
/// Garantiert Datenintegrität während der gesamten Lebensdauer des Objekts.
|
|
/// </summary>
|
|
private readonly List<Element> _elements;
|
|
|
|
/// <summary>
|
|
/// Konstruktor der ElementStatistics-Klasse.
|
|
/// Initialisiert die Statistik-Engine mit einer Element-Sammlung.
|
|
///
|
|
/// Design-Prinzipien:
|
|
/// - Dependency Injection: Element-Liste wird von außen bereitgestellt
|
|
/// - Defensive Programmierung: Null-Safety durch Fallback
|
|
/// - Unveränderlichkeit: readonly field für Datensicherheit
|
|
/// </summary>
|
|
/// <param name="elements">Liste der Elemente für statistische Auswertungen (kann null sein)</param>
|
|
public ElementStatistics(List<Element> elements)
|
|
{
|
|
// Null-Safety: Falls null übergeben wird, erstelle eine leere Liste
|
|
// Verhindert NullReferenceExceptions in allen nachfolgenden Methoden
|
|
_elements = elements ?? new List<Element>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extrahiert alle Atomgewichte als Array - demonstriert klassische Array-Erstellung
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Array-Initialisierung: new double[size]
|
|
/// - For-Schleife: Imperative Programmierung
|
|
/// - Property-Zugriff: element.AtomicWeight
|
|
///
|
|
/// ALTERNATIVE (LINQ): return _elements.Select(e => e.AtomicWeight).ToArray();
|
|
/// Zeigt Unterschied zwischen imperativem und funktionalem Stil
|
|
/// </summary>
|
|
/// <returns>Array aller Atomgewichte in g/mol</returns>
|
|
public double[] GetAtomicWeights()
|
|
{
|
|
double[] weights = new double[_elements.Count];
|
|
for (int i = 0; i < _elements.Count; i++)
|
|
{
|
|
weights[i] = _elements[i].AtomicWeight;
|
|
}
|
|
return weights;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Berechnet das durchschnittliche Atomgewicht aller Elemente
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Early Return Pattern: if (!_elements.Any()) return 0.0;
|
|
/// - Method Reuse: Nutzt GetAtomicWeights()
|
|
/// - Klassische Iteration: for-Schleife für Summe
|
|
///
|
|
/// MATHEMATIK: Arithmetisches Mittel = Summe / Anzahl
|
|
/// </summary>
|
|
/// <returns>Durchschnittliches Atomgewicht oder 0.0 bei leerer Liste</returns>
|
|
public double GetAverageAtomicWeight()
|
|
{
|
|
if (!_elements.Any()) return 0.0;
|
|
|
|
double[] weights = GetAtomicWeights();
|
|
double sum = 0;
|
|
for (int i = 0; i < weights.Length; i++)
|
|
{
|
|
sum += weights[i];
|
|
}
|
|
return sum / weights.Length;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sammelt alle einzigartigen Element-Serien - demonstriert LINQ-Pipeline
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - LINQ Select(): Projektion (e => e.Series)
|
|
/// - LINQ Distinct(): Entfernt Duplikate
|
|
/// - LINQ Where(): Filtert leere/null Werte
|
|
/// - LINQ OrderBy(): Alphabetische Sortierung
|
|
/// - Method Chaining: Verkettung mehrerer Operationen
|
|
///
|
|
/// RÜCKGABE: Sortierte Liste aller chemischen Serien
|
|
/// </summary>
|
|
/// <returns>Liste aller Element-Serien (Alkalimetall, Edelgas, etc.)</returns>
|
|
public List<string> GetAllSeries()
|
|
{
|
|
return _elements.Select(e => e.Series) // Projektion
|
|
.Distinct() // Duplikate entfernen
|
|
.Where(s => !string.IsNullOrWhiteSpace(s)) // Null/Empty filtern
|
|
.OrderBy(s => s) // Alphabetisch sortieren
|
|
.ToList(); // Zu Liste konvertieren
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sammelt wichtige Statistiken in einem Tuple - demonstriert strukturierte Rückgaben
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Tuple Return Type: (int, int, double)
|
|
/// - Method Delegation: Ruft andere Methoden auf
|
|
/// - Tuple Creation: (value1, value2, value3)
|
|
///
|
|
/// VERWENDUNG: var (total, series, avg) = statistics.GetStatistics();
|
|
/// </summary>
|
|
/// <returns>Tuple mit (Anzahl Elemente, Anzahl Serien, Durchschnittsgewicht)</returns>
|
|
public (int totalElements, int uniqueSeries, double avgWeight) GetStatistics()
|
|
{
|
|
var seriesCount = GetAllSeries().Count;
|
|
var avgWeight = GetAverageAtomicWeight();
|
|
|
|
return (_elements.Count, seriesCount, avgWeight);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Findet das leichteste und schwerste Element - demonstriert LINQ Ordering
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - LINQ OrderBy() / OrderByDescending(): Sortierung
|
|
/// - LINQ First(): Erstes Element nach Sortierung
|
|
/// - Tuple mit nullable Types: (Element?, Element?)
|
|
/// - Guard Clause: Early return bei leerer Liste
|
|
///
|
|
/// CHEMIE: Wasserstoff ist leichtestes (1.008), schwerste variieren
|
|
/// </summary>
|
|
/// <returns>Tuple mit (leichtestes Element, schwerstes Element) oder (null, null)</returns>
|
|
public (Element? lightest, Element? heaviest) GetWeightExtremes()
|
|
{
|
|
if (!_elements.Any()) return (null, null);
|
|
|
|
var lightest = _elements.OrderBy(e => e.AtomicWeight).First();
|
|
var heaviest = _elements.OrderByDescending(e => e.AtomicWeight).First();
|
|
|
|
return (lightest, heaviest);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extrahiert Element-Informationen nach Ordnungszahl - demonstriert Tuple-basierte APIs
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - LINQ FirstOrDefault(): Sichere Suche (kann null zurückgeben)
|
|
/// - Conditional Operator: condition ? trueValue : falseValue
|
|
/// - Tuple mit Mixed Types: (string, string, double)
|
|
///
|
|
/// FALLBACK: Bei nicht gefundenem Element ("?", "Unknown", 0.0)
|
|
/// </summary>
|
|
/// <param name="atomicNumber">Ordnungszahl des gesuchten Elements (1-118)</param>
|
|
/// <returns>Tuple mit (Symbol, Name, Atomgewicht)</returns>
|
|
public (string symbol, string name, double weight) GetElementInfo(int atomicNumber)
|
|
{
|
|
var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
|
|
return element != null
|
|
? (element.Symbol, element.ElementName, element.AtomicWeight)
|
|
: ("?", "Unknown", 0.0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ermittelt die Position eines Elements im Periodensystem-Grid
|
|
///
|
|
/// C# KONZEPTE:
|
|
/// - Konsistente API: Gleiche Suchmuster wie GetElementInfo()
|
|
/// - Tuple für Koordinaten: (int row, int column)
|
|
/// - Fallback-Werte: (-1, -1) für "nicht gefunden"
|
|
///
|
|
/// VERWENDUNG: var (row, col) = statistics.GetElementPosition(1); // Wasserstoff
|
|
/// </summary>
|
|
/// <param name="atomicNumber">Ordnungszahl des gesuchten Elements</param>
|
|
/// <returns>Tuple mit (Zeile, Spalte) oder (-1, -1) wenn nicht gefunden</returns>
|
|
public (int row, int column) GetElementPosition(int atomicNumber)
|
|
{
|
|
var element = _elements.FirstOrDefault(e => e.AtomicNumber == atomicNumber);
|
|
return element != null ? (element.Row, element.Column) : (-1, -1);
|
|
}
|
|
}
|
|
}
|